@omnitron-dev/prism 0.1.1

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/bin/prism.js +13 -0
  4. package/dist/accessibility/index.d.ts +157 -0
  5. package/dist/accessibility/index.js +186 -0
  6. package/dist/accessibility/index.js.map +1 -0
  7. package/dist/blocks/index.d.ts +1239 -0
  8. package/dist/blocks/index.js +1712 -0
  9. package/dist/blocks/index.js.map +1 -0
  10. package/dist/chunk-77KIJLPP.js +37 -0
  11. package/dist/chunk-77KIJLPP.js.map +1 -0
  12. package/dist/chunk-BTIT7WYH.js +339 -0
  13. package/dist/chunk-BTIT7WYH.js.map +1 -0
  14. package/dist/chunk-BV32OJ2A.js +1409 -0
  15. package/dist/chunk-BV32OJ2A.js.map +1 -0
  16. package/dist/chunk-DDY7TLUI.js +139 -0
  17. package/dist/chunk-DDY7TLUI.js.map +1 -0
  18. package/dist/chunk-DXXZ3ITR.js +4227 -0
  19. package/dist/chunk-DXXZ3ITR.js.map +1 -0
  20. package/dist/chunk-E3XANPTO.js +2319 -0
  21. package/dist/chunk-E3XANPTO.js.map +1 -0
  22. package/dist/chunk-FU52GL2E.js +3 -0
  23. package/dist/chunk-FU52GL2E.js.map +1 -0
  24. package/dist/chunk-GYDT5EKX.js +16505 -0
  25. package/dist/chunk-GYDT5EKX.js.map +1 -0
  26. package/dist/chunk-HO2GKTWJ.js +28 -0
  27. package/dist/chunk-HO2GKTWJ.js.map +1 -0
  28. package/dist/chunk-JDTC2SBY.js +140 -0
  29. package/dist/chunk-JDTC2SBY.js.map +1 -0
  30. package/dist/chunk-JNU4QHJK.js +6 -0
  31. package/dist/chunk-JNU4QHJK.js.map +1 -0
  32. package/dist/chunk-LAEY5USO.js +2621 -0
  33. package/dist/chunk-LAEY5USO.js.map +1 -0
  34. package/dist/chunk-UR6X3W5I.js +530 -0
  35. package/dist/chunk-UR6X3W5I.js.map +1 -0
  36. package/dist/chunk-WC2WM2JD.js +883 -0
  37. package/dist/chunk-WC2WM2JD.js.map +1 -0
  38. package/dist/chunk-XWL6J6IO.js +40 -0
  39. package/dist/chunk-XWL6J6IO.js.map +1 -0
  40. package/dist/cli/index.js +2695 -0
  41. package/dist/cli/index.js.map +1 -0
  42. package/dist/config-BA6IeTq9.d.ts +100 -0
  43. package/dist/core/index.d.ts +454 -0
  44. package/dist/core/index.js +9 -0
  45. package/dist/core/index.js.map +1 -0
  46. package/dist/forms/index.d.ts +562 -0
  47. package/dist/forms/index.js +545 -0
  48. package/dist/forms/index.js.map +1 -0
  49. package/dist/hooks/index.d.ts +7 -0
  50. package/dist/hooks/index.js +10 -0
  51. package/dist/hooks/index.js.map +1 -0
  52. package/dist/http/index.d.ts +233 -0
  53. package/dist/http/index.js +282 -0
  54. package/dist/http/index.js.map +1 -0
  55. package/dist/index-odhPSv9I.d.ts +2491 -0
  56. package/dist/index.css +131 -0
  57. package/dist/index.css.map +1 -0
  58. package/dist/index.d.ts +9109 -0
  59. package/dist/index.js +13280 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/layouts/index.d.ts +854 -0
  62. package/dist/layouts/index.js +6 -0
  63. package/dist/layouts/index.js.map +1 -0
  64. package/dist/netron/index.d.ts +4 -0
  65. package/dist/netron/index.js +4 -0
  66. package/dist/netron/index.js.map +1 -0
  67. package/dist/registry/index.d.ts +352 -0
  68. package/dist/registry/index.js +4 -0
  69. package/dist/registry/index.js.map +1 -0
  70. package/dist/registry-BrDNftd5.d.ts +574 -0
  71. package/dist/settings-plpR26Xk.d.ts +455 -0
  72. package/dist/state/index.d.ts +981 -0
  73. package/dist/state/index.js +5 -0
  74. package/dist/state/index.js.map +1 -0
  75. package/dist/theme/index.d.ts +1049 -0
  76. package/dist/theme/index.js +5 -0
  77. package/dist/theme/index.js.map +1 -0
  78. package/dist/theme-CrXLfP1c.d.ts +389 -0
  79. package/dist/types/index.d.ts +146 -0
  80. package/dist/types/index.js +5 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/use-timeout-D7U3EAtH.d.ts +808 -0
  83. package/package.json +194 -0
@@ -0,0 +1,2695 @@
1
+ import { createRequire } from 'module';
2
+ import * as fs6 from 'fs';
3
+ import * as path from 'path';
4
+ import { Command } from 'commander';
5
+ import * as readline from 'readline';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var require2, pkg, PRISM_VERSION, CONFIG_FILE_NAME, DEFAULT_COMPONENTS_DIR, DEFAULT_BLOCKS_DIR, DEFAULT_HOOKS_DIR, DEFAULT_UTILS_DIR, DEFAULT_REGISTRY_URL, DEFAULT_CONFIG, supportsColor, COLORS, log, COMPONENT_CATEGORIES, BLOCK_CATEGORIES;
17
+ var init_constants = __esm({
18
+ "src/cli/constants.ts"() {
19
+ require2 = createRequire(import.meta.url);
20
+ pkg = require2("../../package.json");
21
+ PRISM_VERSION = pkg.version;
22
+ CONFIG_FILE_NAME = "prism.config.json";
23
+ DEFAULT_COMPONENTS_DIR = "src/components/ui";
24
+ DEFAULT_BLOCKS_DIR = "src/blocks";
25
+ DEFAULT_HOOKS_DIR = "src/hooks";
26
+ DEFAULT_UTILS_DIR = "src/utils";
27
+ DEFAULT_REGISTRY_URL = "https://registry.prism.omnitron.dev";
28
+ DEFAULT_CONFIG = {
29
+ $schema: "https://prism.omnitron.dev/schema.json",
30
+ style: "default",
31
+ tailwind: {
32
+ config: "tailwind.config.js",
33
+ css: "src/index.css",
34
+ baseColor: "slate",
35
+ cssVariables: true
36
+ },
37
+ aliases: {
38
+ components: "@/components/ui",
39
+ blocks: "@/blocks",
40
+ hooks: "@/hooks",
41
+ utils: "@/utils"
42
+ },
43
+ registries: [DEFAULT_REGISTRY_URL]
44
+ };
45
+ supportsColor = !process.env.NO_COLOR && process.stderr.isTTY !== false;
46
+ COLORS = supportsColor ? {
47
+ primary: "\x1B[36m",
48
+ success: "\x1B[32m",
49
+ warning: "\x1B[33m",
50
+ error: "\x1B[31m",
51
+ muted: "\x1B[90m",
52
+ bold: "\x1B[1m",
53
+ reset: "\x1B[0m"
54
+ } : {
55
+ primary: "",
56
+ success: "",
57
+ warning: "",
58
+ error: "",
59
+ muted: "",
60
+ bold: "",
61
+ reset: ""
62
+ };
63
+ log = {
64
+ info: (msg) => console.log(`${COLORS.primary}\u2139${COLORS.reset} ${msg}`),
65
+ success: (msg) => console.log(`${COLORS.success}\u2713${COLORS.reset} ${msg}`),
66
+ warning: (msg) => console.log(`${COLORS.warning}\u26A0${COLORS.reset} ${msg}`),
67
+ error: (msg) => console.error(`${COLORS.error}\u2716${COLORS.reset} ${msg}`),
68
+ muted: (msg) => console.log(`${COLORS.muted}${msg}${COLORS.reset}`)
69
+ };
70
+ COMPONENT_CATEGORIES = [
71
+ "inputs",
72
+ "data-display",
73
+ "feedback",
74
+ "surfaces",
75
+ "navigation",
76
+ "layout",
77
+ "data"
78
+ ];
79
+ BLOCK_CATEGORIES = ["layouts", "auth", "settings", "data", "dashboard", "marketing"];
80
+ }
81
+ });
82
+ function findConfigFile(startDir = process.cwd()) {
83
+ let currentDir = path.resolve(startDir);
84
+ const root = path.parse(currentDir).root;
85
+ while (currentDir !== root) {
86
+ const configPath = path.join(currentDir, CONFIG_FILE_NAME);
87
+ if (fs6.existsSync(configPath)) {
88
+ return configPath;
89
+ }
90
+ currentDir = path.dirname(currentDir);
91
+ }
92
+ return null;
93
+ }
94
+ async function loadConfig(cwd = process.cwd()) {
95
+ const configPath = findConfigFile(cwd);
96
+ if (!configPath) {
97
+ return null;
98
+ }
99
+ try {
100
+ const content = await fs6.promises.readFile(configPath, "utf-8");
101
+ const config = JSON.parse(content);
102
+ return {
103
+ ...DEFAULT_CONFIG,
104
+ ...config,
105
+ rootDir: path.dirname(configPath),
106
+ configPath
107
+ };
108
+ } catch (error) {
109
+ log.error(`Failed to load config: ${error.message}`);
110
+ return null;
111
+ }
112
+ }
113
+ async function saveConfig(config, outputPath = path.join(process.cwd(), CONFIG_FILE_NAME)) {
114
+ const content = JSON.stringify(config, null, 2);
115
+ await fs6.promises.writeFile(outputPath, content, "utf-8");
116
+ }
117
+ function resolveAlias(alias, config) {
118
+ if (alias.startsWith("@/")) {
119
+ return path.join(config.rootDir, "src", alias.slice(2));
120
+ }
121
+ if (alias.startsWith("~/")) {
122
+ return path.join(config.rootDir, alias.slice(2));
123
+ }
124
+ if (alias.startsWith("./") || alias.startsWith("../")) {
125
+ return path.join(config.rootDir, alias);
126
+ }
127
+ return path.join(config.rootDir, alias);
128
+ }
129
+ function getComponentPath(componentName, config) {
130
+ const componentsDir = resolveAlias(config.aliases.components, config);
131
+ return path.join(componentsDir, componentName);
132
+ }
133
+ function getBlockPath(blockName, config) {
134
+ const blocksDir = resolveAlias(config.aliases.blocks, config);
135
+ return path.join(blocksDir, blockName);
136
+ }
137
+ var init_config = __esm({
138
+ "src/cli/config.ts"() {
139
+ init_constants();
140
+ }
141
+ });
142
+
143
+ // src/registry/manager.ts
144
+ var RegistryManager;
145
+ var init_manager = __esm({
146
+ "src/registry/manager.ts"() {
147
+ RegistryManager = class {
148
+ options;
149
+ registries = /* @__PURE__ */ new Map();
150
+ cache = /* @__PURE__ */ new Map();
151
+ loaders = /* @__PURE__ */ new Map();
152
+ constructor(options = {}) {
153
+ this.options = {
154
+ baseDir: options.baseDir ?? (typeof process !== "undefined" && process.cwd ? process.cwd() : "/"),
155
+ defaultRegistry: options.defaultRegistry ?? "prism",
156
+ config: options.config ?? { default: "prism", registries: {} },
157
+ cacheTtl: options.cacheTtl ?? 5 * 60 * 1e3
158
+ // 5 minutes
159
+ };
160
+ }
161
+ // ===========================================================================
162
+ // REGISTRY LOADING
163
+ // ===========================================================================
164
+ /**
165
+ * Register a custom loader for a registry.
166
+ */
167
+ registerLoader(name, loader) {
168
+ this.loaders.set(name, loader);
169
+ }
170
+ /**
171
+ * Load a registry by name.
172
+ */
173
+ async loadRegistry(name) {
174
+ const cached = this.cache.get(name);
175
+ if (cached && Date.now() - cached.timestamp < this.options.cacheTtl) {
176
+ return cached.data;
177
+ }
178
+ const existing = this.registries.get(name);
179
+ if (existing && !cached) {
180
+ return existing;
181
+ }
182
+ const customLoader = this.loaders.get(name);
183
+ if (customLoader) {
184
+ const registry3 = await customLoader();
185
+ this.cacheRegistry(name, registry3);
186
+ return registry3;
187
+ }
188
+ const config = this.options.config.registries[name];
189
+ if (!config) {
190
+ throw new Error(`Registry "${name}" not found in configuration`);
191
+ }
192
+ const registry2 = typeof config === "string" ? await this.loadFromPath(config) : await this.loadFromRemote(config);
193
+ if (registry2.extends) {
194
+ const baseRegistry = await this.loadRegistry(registry2.extends);
195
+ const merged = this.mergeRegistries(baseRegistry, registry2);
196
+ this.cacheRegistry(name, merged);
197
+ return merged;
198
+ }
199
+ this.cacheRegistry(name, registry2);
200
+ return registry2;
201
+ }
202
+ /**
203
+ * Load registry from local file path.
204
+ * Uses dynamic import for ESM compatibility across environments.
205
+ *
206
+ * @param path - Relative or absolute path to registry JSON
207
+ * @returns Loaded registry schema
208
+ */
209
+ async loadFromPath(path9) {
210
+ const fullPath = path9.startsWith("/") ? path9 : `${this.options.baseDir}/${path9}`;
211
+ if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
212
+ const fs9 = await import('fs/promises');
213
+ const content = await fs9.readFile(fullPath, "utf-8");
214
+ return JSON.parse(content);
215
+ }
216
+ if (path9.startsWith("http://") || path9.startsWith("https://")) {
217
+ const response = await fetch(path9);
218
+ if (!response.ok) {
219
+ throw new Error(`Failed to load registry from ${path9}: ${response.statusText}`);
220
+ }
221
+ return response.json();
222
+ }
223
+ throw new Error(
224
+ `Cannot load local file "${fullPath}" in browser environment. Register a custom loader with manager.registerLoader() or use a remote URL.`
225
+ );
226
+ }
227
+ /**
228
+ * Load registry from remote URL.
229
+ */
230
+ async loadFromRemote(config) {
231
+ const response = await fetch(config.url, {
232
+ headers: config.headers
233
+ });
234
+ if (!response.ok) {
235
+ throw new Error(`Failed to load registry from ${config.url}: ${response.statusText}`);
236
+ }
237
+ return response.json();
238
+ }
239
+ /**
240
+ * Cache a loaded registry.
241
+ */
242
+ cacheRegistry(name, registry2) {
243
+ this.registries.set(name, registry2);
244
+ this.cache.set(name, {
245
+ data: registry2,
246
+ timestamp: Date.now()
247
+ });
248
+ }
249
+ /**
250
+ * Merge two registries (base + extension).
251
+ */
252
+ mergeRegistries(base, extension) {
253
+ return {
254
+ ...base,
255
+ ...extension,
256
+ components: { ...base.components, ...extension.components },
257
+ blocks: { ...base.blocks, ...extension.blocks },
258
+ themes: { ...base.themes, ...extension.themes }
259
+ };
260
+ }
261
+ /**
262
+ * Clear registry cache.
263
+ */
264
+ clearCache(name) {
265
+ if (name) {
266
+ this.cache.delete(name);
267
+ } else {
268
+ this.cache.clear();
269
+ }
270
+ }
271
+ // ===========================================================================
272
+ // COMPONENT OPERATIONS
273
+ // ===========================================================================
274
+ /**
275
+ * Get a component definition by name.
276
+ */
277
+ async getComponent(name, registryName) {
278
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
279
+ return registry2.components[name] ?? null;
280
+ }
281
+ /**
282
+ * Get all components from a registry.
283
+ */
284
+ async getComponents(registryName) {
285
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
286
+ return registry2.components;
287
+ }
288
+ /**
289
+ * Search for components.
290
+ */
291
+ async searchComponents(options, registryName) {
292
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
293
+ let results = Object.values(registry2.components);
294
+ if (options.category) {
295
+ results = results.filter((c) => c.category === options.category);
296
+ }
297
+ if (options.query) {
298
+ const query = options.query.toLowerCase();
299
+ results = results.filter(
300
+ (c) => c.name.toLowerCase().includes(query) || c.displayName?.toLowerCase().includes(query) || c.description?.toLowerCase().includes(query)
301
+ );
302
+ }
303
+ if (options.limit && options.limit > 0) {
304
+ results = results.slice(0, options.limit);
305
+ }
306
+ return results;
307
+ }
308
+ /**
309
+ * Get component categories.
310
+ */
311
+ async getComponentCategories(registryName) {
312
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
313
+ const categories = /* @__PURE__ */ new Set();
314
+ for (const component of Object.values(registry2.components)) {
315
+ categories.add(component.category);
316
+ }
317
+ return Array.from(categories).sort();
318
+ }
319
+ // ===========================================================================
320
+ // BLOCK OPERATIONS
321
+ // ===========================================================================
322
+ /**
323
+ * Get a block definition by name.
324
+ */
325
+ async getBlock(name, registryName) {
326
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
327
+ return registry2.blocks[name] ?? null;
328
+ }
329
+ /**
330
+ * Get all blocks from a registry.
331
+ */
332
+ async getBlocks(registryName) {
333
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
334
+ return registry2.blocks;
335
+ }
336
+ /**
337
+ * Search for blocks.
338
+ */
339
+ async searchBlocks(options, registryName) {
340
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
341
+ let results = Object.values(registry2.blocks);
342
+ if (options.category) {
343
+ results = results.filter((b) => b.category === options.category);
344
+ }
345
+ if (options.query) {
346
+ const query = options.query.toLowerCase();
347
+ results = results.filter(
348
+ (b) => b.name.toLowerCase().includes(query) || b.displayName?.toLowerCase().includes(query) || b.description?.toLowerCase().includes(query)
349
+ );
350
+ }
351
+ if (options.limit && options.limit > 0) {
352
+ results = results.slice(0, options.limit);
353
+ }
354
+ return results;
355
+ }
356
+ /**
357
+ * Get block categories.
358
+ */
359
+ async getBlockCategories(registryName) {
360
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
361
+ const categories = /* @__PURE__ */ new Set();
362
+ for (const block of Object.values(registry2.blocks)) {
363
+ categories.add(block.category);
364
+ }
365
+ return Array.from(categories).sort();
366
+ }
367
+ // ===========================================================================
368
+ // DEPENDENCY RESOLUTION
369
+ // ===========================================================================
370
+ /**
371
+ * Resolve all dependencies for a component.
372
+ */
373
+ async resolveComponentDependencies(name, registryName) {
374
+ const registry2 = registryName ?? this.options.defaultRegistry;
375
+ const component = await this.getComponent(name, registry2);
376
+ if (!component) {
377
+ throw new Error(`Component "${name}" not found in registry "${registry2}"`);
378
+ }
379
+ const dependencies = [];
380
+ for (const depName of component.dependencies.components) {
381
+ const resolved = await this.resolveComponentDependencies(depName, registry2);
382
+ dependencies.push(resolved);
383
+ }
384
+ return {
385
+ definition: component,
386
+ registry: registry2,
387
+ dependencies
388
+ };
389
+ }
390
+ /**
391
+ * Resolve all dependencies for a block.
392
+ */
393
+ async resolveBlockDependencies(name, registryName) {
394
+ const registry2 = registryName ?? this.options.defaultRegistry;
395
+ const block = await this.getBlock(name, registry2);
396
+ if (!block) {
397
+ throw new Error(`Block "${name}" not found in registry "${registry2}"`);
398
+ }
399
+ const dependencies = [];
400
+ for (const compName of block.dependencies.components) {
401
+ const resolved = await this.resolveComponentDependencies(compName, registry2);
402
+ dependencies.push(resolved);
403
+ }
404
+ for (const blockName of block.dependencies.blocks) {
405
+ const resolved = await this.resolveBlockDependencies(blockName, registry2);
406
+ dependencies.push(resolved);
407
+ }
408
+ return {
409
+ definition: block,
410
+ registry: registry2,
411
+ dependencies
412
+ };
413
+ }
414
+ /**
415
+ * Get flat list of all npm dependencies for resolved items.
416
+ */
417
+ getNpmDependencies(resolved) {
418
+ const deps = /* @__PURE__ */ new Set();
419
+ function collectDeps(item) {
420
+ const definition = item.definition;
421
+ if ("dependencies" in definition) {
422
+ for (const dep of definition.dependencies.npm) {
423
+ deps.add(dep);
424
+ }
425
+ }
426
+ for (const child of item.dependencies) {
427
+ collectDeps(child);
428
+ }
429
+ }
430
+ collectDeps(resolved);
431
+ return Array.from(deps).sort();
432
+ }
433
+ /**
434
+ * Get flat list of all file paths for resolved items.
435
+ */
436
+ getFilePaths(resolved) {
437
+ const paths = /* @__PURE__ */ new Set();
438
+ function collectPaths(item) {
439
+ const definition = item.definition;
440
+ for (const file of definition.files) {
441
+ paths.add(file.path);
442
+ }
443
+ for (const child of item.dependencies) {
444
+ collectPaths(child);
445
+ }
446
+ }
447
+ collectPaths(resolved);
448
+ return Array.from(paths).sort();
449
+ }
450
+ // ===========================================================================
451
+ // VERSION CHECKING
452
+ // ===========================================================================
453
+ /**
454
+ * Check if a component version is compatible.
455
+ */
456
+ async checkComponentVersion(name, requiredVersion, registryName) {
457
+ const component = await this.getComponent(name, registryName);
458
+ if (!component) return false;
459
+ return this.isVersionCompatible(component.version, requiredVersion);
460
+ }
461
+ /**
462
+ * Check semver version compatibility.
463
+ * Simple implementation - considers major.minor compatibility.
464
+ */
465
+ isVersionCompatible(actual, required) {
466
+ const [actualMajor, actualMinor] = actual.split(".").map(Number);
467
+ const [requiredMajor, requiredMinor] = required.split(".").map(Number);
468
+ if (actualMajor !== requiredMajor) return false;
469
+ return actualMinor >= requiredMinor;
470
+ }
471
+ // ===========================================================================
472
+ // REGISTRY INFO
473
+ // ===========================================================================
474
+ /**
475
+ * Get registry metadata.
476
+ */
477
+ async getRegistryInfo(registryName) {
478
+ const registry2 = await this.loadRegistry(registryName ?? this.options.defaultRegistry);
479
+ return {
480
+ name: registry2.name,
481
+ version: registry2.version,
482
+ description: registry2.description,
483
+ componentCount: Object.keys(registry2.components).length,
484
+ blockCount: Object.keys(registry2.blocks).length,
485
+ themeCount: Object.keys(registry2.themes).length
486
+ };
487
+ }
488
+ /**
489
+ * Get list of loaded registries.
490
+ */
491
+ getLoadedRegistries() {
492
+ return Array.from(this.registries.keys());
493
+ }
494
+ };
495
+ new RegistryManager();
496
+ }
497
+ });
498
+ var init_installer = __esm({
499
+ "src/registry/installer.ts"() {
500
+ }
501
+ });
502
+
503
+ // src/registry/index.ts
504
+ var defaultRegistrySchema;
505
+ var init_registry = __esm({
506
+ "src/registry/index.ts"() {
507
+ init_manager();
508
+ init_installer();
509
+ defaultRegistrySchema = {
510
+ $schema: "https://prism.omnitron.dev/registry/v1/schema.json",
511
+ name: "prism",
512
+ version: "1.0.0",
513
+ description: "Official Prism Design System Registry",
514
+ baseUrl: "https://registry.prism.omnitron.dev",
515
+ components: {
516
+ // Input Components
517
+ button: {
518
+ name: "button",
519
+ version: "1.0.0",
520
+ category: "inputs",
521
+ displayName: "Button",
522
+ description: "Primary action button with multiple variants",
523
+ files: [
524
+ { path: "Button.tsx", type: "component" },
525
+ { path: "Button.types.ts", type: "types" },
526
+ { path: "index.ts", type: "barrel" }
527
+ ],
528
+ dependencies: {
529
+ npm: ["@mui/material"],
530
+ components: []
531
+ },
532
+ hasVariants: true,
533
+ docs: "https://docs.prism.omnitron.dev/components/button"
534
+ },
535
+ "icon-button": {
536
+ name: "icon-button",
537
+ version: "1.0.0",
538
+ category: "inputs",
539
+ displayName: "Icon Button",
540
+ description: "Compact button for icon-only actions",
541
+ files: [
542
+ { path: "IconButton.tsx", type: "component" },
543
+ { path: "index.ts", type: "barrel" }
544
+ ],
545
+ dependencies: {
546
+ npm: ["@mui/material"],
547
+ components: []
548
+ },
549
+ hasVariants: true
550
+ },
551
+ "text-field": {
552
+ name: "text-field",
553
+ version: "1.0.0",
554
+ category: "inputs",
555
+ displayName: "Text Field",
556
+ description: "Text input with label and helper text",
557
+ files: [
558
+ { path: "TextField.tsx", type: "component" },
559
+ { path: "TextField.types.ts", type: "types" },
560
+ { path: "index.ts", type: "barrel" }
561
+ ],
562
+ dependencies: {
563
+ npm: ["@mui/material"],
564
+ components: []
565
+ },
566
+ hasVariants: true
567
+ },
568
+ select: {
569
+ name: "select",
570
+ version: "1.0.0",
571
+ category: "inputs",
572
+ displayName: "Select",
573
+ description: "Dropdown selection component",
574
+ files: [
575
+ { path: "Select.tsx", type: "component" },
576
+ { path: "Select.types.ts", type: "types" },
577
+ { path: "index.ts", type: "barrel" }
578
+ ],
579
+ dependencies: {
580
+ npm: ["@mui/material"],
581
+ components: []
582
+ },
583
+ hasVariants: true
584
+ },
585
+ checkbox: {
586
+ name: "checkbox",
587
+ version: "1.0.0",
588
+ category: "inputs",
589
+ displayName: "Checkbox",
590
+ description: "Checkbox input for boolean values",
591
+ files: [
592
+ { path: "Checkbox.tsx", type: "component" },
593
+ { path: "index.ts", type: "barrel" }
594
+ ],
595
+ dependencies: {
596
+ npm: ["@mui/material"],
597
+ components: []
598
+ },
599
+ hasVariants: false
600
+ },
601
+ switch: {
602
+ name: "switch",
603
+ version: "1.0.0",
604
+ category: "inputs",
605
+ displayName: "Switch",
606
+ description: "Toggle switch for on/off states",
607
+ files: [
608
+ { path: "Switch.tsx", type: "component" },
609
+ { path: "index.ts", type: "barrel" }
610
+ ],
611
+ dependencies: {
612
+ npm: ["@mui/material"],
613
+ components: []
614
+ },
615
+ hasVariants: false
616
+ },
617
+ // Data Display
618
+ avatar: {
619
+ name: "avatar",
620
+ version: "1.0.0",
621
+ category: "data-display",
622
+ displayName: "Avatar",
623
+ description: "User avatar with image or initials",
624
+ files: [
625
+ { path: "Avatar.tsx", type: "component" },
626
+ { path: "AvatarGroup.tsx", type: "component" },
627
+ { path: "index.ts", type: "barrel" }
628
+ ],
629
+ dependencies: {
630
+ npm: ["@mui/material"],
631
+ components: []
632
+ },
633
+ hasVariants: true
634
+ },
635
+ badge: {
636
+ name: "badge",
637
+ version: "1.0.0",
638
+ category: "data-display",
639
+ displayName: "Badge",
640
+ description: "Badge for notifications and status",
641
+ files: [
642
+ { path: "Badge.tsx", type: "component" },
643
+ { path: "index.ts", type: "barrel" }
644
+ ],
645
+ dependencies: {
646
+ npm: ["@mui/material"],
647
+ components: []
648
+ },
649
+ hasVariants: true
650
+ },
651
+ chip: {
652
+ name: "chip",
653
+ version: "1.0.0",
654
+ category: "data-display",
655
+ displayName: "Chip",
656
+ description: "Compact element for tags and selections",
657
+ files: [
658
+ { path: "Chip.tsx", type: "component" },
659
+ { path: "index.ts", type: "barrel" }
660
+ ],
661
+ dependencies: {
662
+ npm: ["@mui/material"],
663
+ components: []
664
+ },
665
+ hasVariants: true
666
+ },
667
+ tooltip: {
668
+ name: "tooltip",
669
+ version: "1.0.0",
670
+ category: "data-display",
671
+ displayName: "Tooltip",
672
+ description: "Informative tooltip on hover",
673
+ files: [
674
+ { path: "Tooltip.tsx", type: "component" },
675
+ { path: "index.ts", type: "barrel" }
676
+ ],
677
+ dependencies: {
678
+ npm: ["@mui/material"],
679
+ components: []
680
+ },
681
+ hasVariants: false
682
+ },
683
+ // Feedback
684
+ alert: {
685
+ name: "alert",
686
+ version: "1.0.0",
687
+ category: "feedback",
688
+ displayName: "Alert",
689
+ description: "Alert messages with severity levels",
690
+ files: [
691
+ { path: "Alert.tsx", type: "component" },
692
+ { path: "index.ts", type: "barrel" }
693
+ ],
694
+ dependencies: {
695
+ npm: ["@mui/material"],
696
+ components: []
697
+ },
698
+ hasVariants: true
699
+ },
700
+ snackbar: {
701
+ name: "snackbar",
702
+ version: "1.0.0",
703
+ category: "feedback",
704
+ displayName: "Snackbar",
705
+ description: "Brief notification messages",
706
+ files: [
707
+ { path: "Snackbar.tsx", type: "component" },
708
+ { path: "SnackbarProvider.tsx", type: "component" },
709
+ { path: "useSnackbar.ts", type: "component" },
710
+ { path: "index.ts", type: "barrel" }
711
+ ],
712
+ dependencies: {
713
+ npm: ["@mui/material", "notistack"],
714
+ components: []
715
+ },
716
+ hasVariants: false
717
+ },
718
+ dialog: {
719
+ name: "dialog",
720
+ version: "1.0.0",
721
+ category: "feedback",
722
+ displayName: "Dialog",
723
+ description: "Modal dialog with actions",
724
+ files: [
725
+ { path: "Dialog.tsx", type: "component" },
726
+ { path: "ConfirmDialog.tsx", type: "component" },
727
+ { path: "index.ts", type: "barrel" }
728
+ ],
729
+ dependencies: {
730
+ npm: ["@mui/material"],
731
+ components: ["button"]
732
+ },
733
+ hasVariants: false
734
+ },
735
+ progress: {
736
+ name: "progress",
737
+ version: "1.0.0",
738
+ category: "feedback",
739
+ displayName: "Progress",
740
+ description: "Progress indicators (linear and circular)",
741
+ files: [
742
+ { path: "LinearProgress.tsx", type: "component" },
743
+ { path: "CircularProgress.tsx", type: "component" },
744
+ { path: "index.ts", type: "barrel" }
745
+ ],
746
+ dependencies: {
747
+ npm: ["@mui/material"],
748
+ components: []
749
+ },
750
+ hasVariants: false
751
+ },
752
+ // Surfaces
753
+ card: {
754
+ name: "card",
755
+ version: "1.0.0",
756
+ category: "surfaces",
757
+ displayName: "Card",
758
+ description: "Content card with header, content, and actions",
759
+ files: [
760
+ { path: "Card.tsx", type: "component" },
761
+ { path: "Card.types.ts", type: "types" },
762
+ { path: "index.ts", type: "barrel" }
763
+ ],
764
+ dependencies: {
765
+ npm: ["@mui/material"],
766
+ components: []
767
+ },
768
+ hasVariants: true
769
+ },
770
+ paper: {
771
+ name: "paper",
772
+ version: "1.0.0",
773
+ category: "surfaces",
774
+ displayName: "Paper",
775
+ description: "Basic surface with elevation",
776
+ files: [
777
+ { path: "Paper.tsx", type: "component" },
778
+ { path: "index.ts", type: "barrel" }
779
+ ],
780
+ dependencies: {
781
+ npm: ["@mui/material"],
782
+ components: []
783
+ },
784
+ hasVariants: false
785
+ },
786
+ accordion: {
787
+ name: "accordion",
788
+ version: "1.0.0",
789
+ category: "surfaces",
790
+ displayName: "Accordion",
791
+ description: "Expandable content panels",
792
+ files: [
793
+ { path: "Accordion.tsx", type: "component" },
794
+ { path: "index.ts", type: "barrel" }
795
+ ],
796
+ dependencies: {
797
+ npm: ["@mui/material"],
798
+ components: []
799
+ },
800
+ hasVariants: false
801
+ },
802
+ // Navigation
803
+ tabs: {
804
+ name: "tabs",
805
+ version: "1.0.0",
806
+ category: "navigation",
807
+ displayName: "Tabs",
808
+ description: "Tabbed navigation component",
809
+ files: [
810
+ { path: "Tabs.tsx", type: "component" },
811
+ { path: "TabPanel.tsx", type: "component" },
812
+ { path: "index.ts", type: "barrel" }
813
+ ],
814
+ dependencies: {
815
+ npm: ["@mui/material"],
816
+ components: []
817
+ },
818
+ hasVariants: true
819
+ },
820
+ breadcrumbs: {
821
+ name: "breadcrumbs",
822
+ version: "1.0.0",
823
+ category: "navigation",
824
+ displayName: "Breadcrumbs",
825
+ description: "Navigation breadcrumb trail",
826
+ files: [
827
+ { path: "Breadcrumbs.tsx", type: "component" },
828
+ { path: "index.ts", type: "barrel" }
829
+ ],
830
+ dependencies: {
831
+ npm: ["@mui/material"],
832
+ components: []
833
+ },
834
+ hasVariants: false
835
+ },
836
+ menu: {
837
+ name: "menu",
838
+ version: "1.0.0",
839
+ category: "navigation",
840
+ displayName: "Menu",
841
+ description: "Dropdown menu for actions",
842
+ files: [
843
+ { path: "Menu.tsx", type: "component" },
844
+ { path: "MenuItem.tsx", type: "component" },
845
+ { path: "index.ts", type: "barrel" }
846
+ ],
847
+ dependencies: {
848
+ npm: ["@mui/material"],
849
+ components: []
850
+ },
851
+ hasVariants: false
852
+ },
853
+ // Layout
854
+ stack: {
855
+ name: "stack",
856
+ version: "1.0.0",
857
+ category: "layout",
858
+ displayName: "Stack",
859
+ description: "Vertical/horizontal flex layout",
860
+ files: [
861
+ { path: "Stack.tsx", type: "component" },
862
+ { path: "index.ts", type: "barrel" }
863
+ ],
864
+ dependencies: {
865
+ npm: ["@mui/material"],
866
+ components: []
867
+ },
868
+ hasVariants: false
869
+ },
870
+ grid: {
871
+ name: "grid",
872
+ version: "1.0.0",
873
+ category: "layout",
874
+ displayName: "Grid",
875
+ description: "Responsive grid layout",
876
+ files: [
877
+ { path: "Grid.tsx", type: "component" },
878
+ { path: "index.ts", type: "barrel" }
879
+ ],
880
+ dependencies: {
881
+ npm: ["@mui/material"],
882
+ components: []
883
+ },
884
+ hasVariants: false
885
+ },
886
+ container: {
887
+ name: "container",
888
+ version: "1.0.0",
889
+ category: "layout",
890
+ displayName: "Container",
891
+ description: "Centered content container",
892
+ files: [
893
+ { path: "Container.tsx", type: "component" },
894
+ { path: "index.ts", type: "barrel" }
895
+ ],
896
+ dependencies: {
897
+ npm: ["@mui/material"],
898
+ components: []
899
+ },
900
+ hasVariants: false
901
+ },
902
+ divider: {
903
+ name: "divider",
904
+ version: "1.0.0",
905
+ category: "layout",
906
+ displayName: "Divider",
907
+ description: "Visual separator",
908
+ files: [
909
+ { path: "Divider.tsx", type: "component" },
910
+ { path: "index.ts", type: "barrel" }
911
+ ],
912
+ dependencies: {
913
+ npm: ["@mui/material"],
914
+ components: []
915
+ },
916
+ hasVariants: false
917
+ },
918
+ // Data
919
+ "data-table": {
920
+ name: "data-table",
921
+ version: "1.0.0",
922
+ category: "data",
923
+ displayName: "Data Table",
924
+ description: "Full-featured data table with sorting, filtering, pagination",
925
+ files: [
926
+ { path: "DataTable.tsx", type: "component" },
927
+ { path: "DataTable.types.ts", type: "types" },
928
+ { path: "DataTableToolbar.tsx", type: "component" },
929
+ { path: "DataTablePagination.tsx", type: "component" },
930
+ { path: "index.ts", type: "barrel" }
931
+ ],
932
+ dependencies: {
933
+ npm: ["@mui/material", "@tanstack/react-table"],
934
+ components: ["button", "text-field", "select", "checkbox", "menu"]
935
+ },
936
+ hasVariants: true,
937
+ docs: "https://docs.prism.omnitron.dev/components/data-table"
938
+ },
939
+ table: {
940
+ name: "table",
941
+ version: "1.0.0",
942
+ category: "data",
943
+ displayName: "Table",
944
+ description: "Basic table component",
945
+ files: [
946
+ { path: "Table.tsx", type: "component" },
947
+ { path: "index.ts", type: "barrel" }
948
+ ],
949
+ dependencies: {
950
+ npm: ["@mui/material"],
951
+ components: []
952
+ },
953
+ hasVariants: false
954
+ },
955
+ list: {
956
+ name: "list",
957
+ version: "1.0.0",
958
+ category: "data",
959
+ displayName: "List",
960
+ description: "Vertical list of items",
961
+ files: [
962
+ { path: "List.tsx", type: "component" },
963
+ { path: "ListItem.tsx", type: "component" },
964
+ { path: "index.ts", type: "barrel" }
965
+ ],
966
+ dependencies: {
967
+ npm: ["@mui/material"],
968
+ components: []
969
+ },
970
+ hasVariants: false
971
+ }
972
+ },
973
+ blocks: {
974
+ // Dashboard blocks
975
+ "dashboard-layout": {
976
+ name: "dashboard-layout",
977
+ version: "1.0.0",
978
+ category: "layouts",
979
+ displayName: "Dashboard Layout",
980
+ description: "Complete dashboard layout with sidebar and header",
981
+ files: [
982
+ { path: "DashboardLayout.tsx", type: "component" },
983
+ { path: "DashboardLayout.types.ts", type: "type" },
984
+ { path: "Sidebar.tsx", type: "component" },
985
+ { path: "Header.tsx", type: "component" },
986
+ { path: "NavSection.tsx", type: "component" },
987
+ { path: "NavItem.tsx", type: "component" },
988
+ { path: "useDashboard.ts", type: "hook" },
989
+ { path: "index.ts", type: "barrel" }
990
+ ],
991
+ dependencies: {
992
+ npm: ["@mui/material", "framer-motion"],
993
+ components: ["avatar", "menu", "icon-button", "tooltip"],
994
+ blocks: []
995
+ },
996
+ defaultConfig: {
997
+ sidebarWidth: 280,
998
+ headerHeight: 64,
999
+ collapsedWidth: 72
1000
+ },
1001
+ docs: "https://docs.prism.omnitron.dev/blocks/dashboard-layout"
1002
+ },
1003
+ "auth-forms": {
1004
+ name: "auth-forms",
1005
+ version: "1.0.0",
1006
+ category: "auth",
1007
+ displayName: "Authentication Forms",
1008
+ description: "Login, register, forgot password, and verify forms",
1009
+ files: [
1010
+ { path: "LoginForm.tsx", type: "component" },
1011
+ { path: "RegisterForm.tsx", type: "component" },
1012
+ { path: "ForgotPasswordForm.tsx", type: "component" },
1013
+ { path: "VerifyCodeForm.tsx", type: "component" },
1014
+ { path: "auth.schema.ts", type: "schema" },
1015
+ { path: "useAuthForm.ts", type: "hook" },
1016
+ { path: "index.ts", type: "barrel" }
1017
+ ],
1018
+ dependencies: {
1019
+ npm: ["@mui/material", "react-hook-form", "@hookform/resolvers", "zod"],
1020
+ components: ["button", "text-field", "checkbox", "alert"],
1021
+ blocks: []
1022
+ },
1023
+ defaultConfig: {
1024
+ showSocialLogin: true,
1025
+ showRememberMe: true
1026
+ }
1027
+ },
1028
+ "settings-panel": {
1029
+ name: "settings-panel",
1030
+ version: "1.0.0",
1031
+ category: "settings",
1032
+ displayName: "Settings Panel",
1033
+ description: "Theme settings panel with live preview",
1034
+ files: [
1035
+ { path: "SettingsPanel.tsx", type: "component" },
1036
+ { path: "SettingsDrawer.tsx", type: "component" },
1037
+ { path: "ThemePreview.tsx", type: "component" },
1038
+ { path: "useSettings.ts", type: "hook" },
1039
+ { path: "index.ts", type: "barrel" }
1040
+ ],
1041
+ dependencies: {
1042
+ npm: ["@mui/material", "framer-motion"],
1043
+ components: ["button", "switch", "select", "icon-button"],
1044
+ blocks: []
1045
+ },
1046
+ defaultConfig: {
1047
+ position: "right"
1048
+ }
1049
+ },
1050
+ "user-profile": {
1051
+ name: "user-profile",
1052
+ version: "1.0.0",
1053
+ category: "data",
1054
+ displayName: "User Profile",
1055
+ description: "User profile page with avatar, info, and settings",
1056
+ files: [
1057
+ { path: "ProfilePage.tsx", type: "component" },
1058
+ { path: "ProfileHeader.tsx", type: "component" },
1059
+ { path: "ProfileTabs.tsx", type: "component" },
1060
+ { path: "AccountTab.tsx", type: "component" },
1061
+ { path: "SecurityTab.tsx", type: "component" },
1062
+ { path: "NotificationsTab.tsx", type: "component" },
1063
+ { path: "useProfile.ts", type: "hook" },
1064
+ { path: "index.ts", type: "barrel" }
1065
+ ],
1066
+ dependencies: {
1067
+ npm: ["@mui/material", "react-hook-form"],
1068
+ components: ["avatar", "button", "tabs", "card", "text-field", "switch"],
1069
+ blocks: []
1070
+ },
1071
+ defaultConfig: {}
1072
+ },
1073
+ "data-grid": {
1074
+ name: "data-grid",
1075
+ version: "1.0.0",
1076
+ category: "data",
1077
+ displayName: "Data Grid",
1078
+ description: "Advanced data grid with server-side features",
1079
+ files: [
1080
+ { path: "DataGrid.tsx", type: "component" },
1081
+ { path: "DataGrid.types.ts", type: "type" },
1082
+ { path: "GridToolbar.tsx", type: "component" },
1083
+ { path: "GridFilters.tsx", type: "component" },
1084
+ { path: "GridExport.tsx", type: "component" },
1085
+ { path: "useDataGrid.ts", type: "hook" },
1086
+ { path: "index.ts", type: "barrel" }
1087
+ ],
1088
+ dependencies: {
1089
+ npm: ["@mui/material", "@tanstack/react-table", "@tanstack/react-virtual"],
1090
+ components: ["button", "text-field", "select", "checkbox", "menu", "chip"],
1091
+ blocks: []
1092
+ },
1093
+ defaultConfig: {
1094
+ pageSize: 25,
1095
+ enableColumnResize: true,
1096
+ enableColumnReorder: true
1097
+ }
1098
+ }
1099
+ },
1100
+ themes: {}
1101
+ };
1102
+ }
1103
+ });
1104
+
1105
+ // src/cli/commands/add.ts
1106
+ var add_exports = {};
1107
+ __export(add_exports, {
1108
+ addCommand: () => addCommand,
1109
+ generateFileContent: () => generateFileContent,
1110
+ toPascalCase: () => toPascalCase
1111
+ });
1112
+ function addCommand() {
1113
+ const command = new Command("add");
1114
+ command.description("Add components or blocks to your project").argument("[items...]", "Components or blocks to add").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("-c, --cwd <path>", "Working directory", process.cwd()).option("-p, --path <path>", "Custom output path").option("-i, --install", "Auto-install npm dependencies").action(async (items, options) => {
1115
+ await runAdd(items, options);
1116
+ });
1117
+ return command;
1118
+ }
1119
+ async function runAdd(items, options) {
1120
+ const cwd = options.cwd || process.cwd();
1121
+ const config = await loadConfig(cwd);
1122
+ if (!config) {
1123
+ log.error("No prism.config.json found. Run `prism init` first.");
1124
+ process.exit(1);
1125
+ }
1126
+ let itemsToAdd = items;
1127
+ if (options.all) {
1128
+ itemsToAdd = [
1129
+ ...Object.keys(defaultRegistrySchema.components),
1130
+ ...Object.keys(defaultRegistrySchema.blocks).map((b) => `block:${b}`)
1131
+ ];
1132
+ }
1133
+ if (itemsToAdd.length === 0) {
1134
+ log.error("No items specified. Use `prism add <component>` or `prism add --all`");
1135
+ log.info("Run `prism list` to see available components.");
1136
+ process.exit(1);
1137
+ }
1138
+ console.log("");
1139
+ log.info(`Adding ${itemsToAdd.length} item(s)...`);
1140
+ console.log("");
1141
+ const results = [];
1142
+ const allNpmDeps = /* @__PURE__ */ new Set();
1143
+ for (const item of itemsToAdd) {
1144
+ try {
1145
+ const result = await addItem(item, config, options);
1146
+ results.push(result);
1147
+ if (result.npmDeps) {
1148
+ for (const dep of result.npmDeps) {
1149
+ allNpmDeps.add(dep);
1150
+ }
1151
+ }
1152
+ } catch (error) {
1153
+ results.push({
1154
+ name: item,
1155
+ success: false,
1156
+ error: error.message
1157
+ });
1158
+ }
1159
+ }
1160
+ console.log("");
1161
+ const successCount = results.filter((r) => r.success).length;
1162
+ const failCount = results.filter((r) => !r.success).length;
1163
+ if (successCount > 0) {
1164
+ log.success(`Added ${successCount} item(s) successfully.`);
1165
+ }
1166
+ if (failCount > 0) {
1167
+ log.error(`Failed to add ${failCount} item(s).`);
1168
+ for (const result of results.filter((r) => !r.success)) {
1169
+ log.muted(` - ${result.name}: ${result.error}`);
1170
+ }
1171
+ }
1172
+ if (allNpmDeps.size > 0) {
1173
+ console.log("");
1174
+ log.info("Required npm dependencies:");
1175
+ const depsArray = Array.from(allNpmDeps).sort();
1176
+ for (const dep of depsArray) {
1177
+ log.muted(` - ${dep}`);
1178
+ }
1179
+ console.log("");
1180
+ log.info("Install with:");
1181
+ log.muted(` npm install ${depsArray.join(" ")}`);
1182
+ log.muted(` # or`);
1183
+ log.muted(` pnpm add ${depsArray.join(" ")}`);
1184
+ if ((options.install || options.yes) && allNpmDeps.size > 0) {
1185
+ const pm = detectPackageManager(cwd);
1186
+ const installCmd = pm === "pnpm" ? "pnpm add" : pm === "yarn" ? "yarn add" : "npm install";
1187
+ log.info(`Installing dependencies with ${pm}...`);
1188
+ try {
1189
+ const { execSync } = await import('child_process');
1190
+ execSync(`${installCmd} ${depsArray.join(" ")}`, {
1191
+ cwd,
1192
+ stdio: "inherit"
1193
+ });
1194
+ log.success("Dependencies installed successfully.");
1195
+ } catch {
1196
+ log.warning("Auto-install failed. Please install dependencies manually.");
1197
+ }
1198
+ }
1199
+ }
1200
+ console.log("");
1201
+ }
1202
+ function detectPackageManager(cwd) {
1203
+ if (fs6.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1204
+ if (fs6.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
1205
+ return "npm";
1206
+ }
1207
+ async function addItem(item, config, options) {
1208
+ const isBlock = item.startsWith("block:");
1209
+ const itemName = isBlock ? item.slice(6) : item;
1210
+ const registry2 = isBlock ? defaultRegistrySchema.blocks : defaultRegistrySchema.components;
1211
+ const definition = registry2[itemName];
1212
+ if (!definition) {
1213
+ return {
1214
+ name: item,
1215
+ success: false,
1216
+ error: `Not found in registry. Run 'prism list' to see available items.`
1217
+ };
1218
+ }
1219
+ const outputPath = options.path ? path.join(config.rootDir, options.path, itemName) : isBlock ? getBlockPath(itemName, config) : getComponentPath(itemName, config);
1220
+ if (fs6.existsSync(outputPath) && !options.overwrite) {
1221
+ return {
1222
+ name: item,
1223
+ success: false,
1224
+ error: `Already exists at ${path.relative(config.rootDir, outputPath)}. Use --overwrite to replace.`
1225
+ };
1226
+ }
1227
+ await fs6.promises.mkdir(outputPath, { recursive: true });
1228
+ for (const file of definition.files) {
1229
+ const filePath = path.join(outputPath, file.path);
1230
+ const content = generateFileContent(itemName, file.path, file.type, definition, isBlock);
1231
+ await fs6.promises.writeFile(filePath, content, "utf-8");
1232
+ }
1233
+ log.success(`Added ${itemName} \u2192 ${path.relative(config.rootDir, outputPath)}/`);
1234
+ await updateLockfile(config.rootDir, itemName, definition.version, isBlock);
1235
+ const npmDeps = [];
1236
+ if ("dependencies" in definition && definition.dependencies?.npm) {
1237
+ npmDeps.push(...definition.dependencies.npm);
1238
+ }
1239
+ return { name: item, success: true, npmDeps };
1240
+ }
1241
+ async function updateLockfile(rootDir, name, version, isBlock) {
1242
+ const lockfilePath = path.join(rootDir, "prism.lock.json");
1243
+ let lockfile = {
1244
+ version: "1",
1245
+ components: {},
1246
+ blocks: {}
1247
+ };
1248
+ if (fs6.existsSync(lockfilePath)) {
1249
+ try {
1250
+ lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
1251
+ } catch {
1252
+ }
1253
+ }
1254
+ const entry = {
1255
+ name,
1256
+ version,
1257
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
1258
+ };
1259
+ if (isBlock) {
1260
+ lockfile.blocks[name] = entry;
1261
+ } else {
1262
+ lockfile.components[name] = entry;
1263
+ }
1264
+ await fs6.promises.writeFile(lockfilePath, JSON.stringify(lockfile, null, 2) + "\n", "utf-8");
1265
+ }
1266
+ function toPascalCase(name) {
1267
+ return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
1268
+ }
1269
+ function toCamelCase(name) {
1270
+ const pascal = toPascalCase(name);
1271
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
1272
+ }
1273
+ function generateFileContent(name, fileName, fileType, definition, isBlock) {
1274
+ const pascalName = toPascalCase(name);
1275
+ const camelName = toCamelCase(name);
1276
+ if (fileName === "index.ts") {
1277
+ return generateBarrelExport(definition, pascalName);
1278
+ }
1279
+ if (fileType === "types" || fileName.endsWith(".types.ts")) {
1280
+ return generateTypeDefinitions(name, pascalName);
1281
+ }
1282
+ if (fileType === "hook" || fileName.startsWith("use")) {
1283
+ const hookName = fileName.replace(".ts", "");
1284
+ return generateHook(hookName, pascalName, definition, isBlock);
1285
+ }
1286
+ if (fileType === "schema" || fileName.endsWith(".schema.ts")) {
1287
+ return generateSchema(name, pascalName, definition);
1288
+ }
1289
+ return generateComponent(name, pascalName, camelName, fileName, definition, isBlock);
1290
+ }
1291
+ function generateBarrelExport(definition, pascalName) {
1292
+ const exports$1 = [];
1293
+ for (const file of definition.files) {
1294
+ if (file.path === "index.ts") continue;
1295
+ const moduleName = file.path.replace(/\.tsx?$/, ".js");
1296
+ if (file.type === "types" || file.path.endsWith(".types.ts")) {
1297
+ exports$1.push(`export type * from './${moduleName}';`);
1298
+ } else {
1299
+ exports$1.push(`export * from './${moduleName}';`);
1300
+ }
1301
+ }
1302
+ return `/**
1303
+ * ${definition.displayName || pascalName}
1304
+ *
1305
+ * ${definition.description || ""}
1306
+ *
1307
+ * @module @omnitron-dev/prism/components/${definition.name}
1308
+ */
1309
+
1310
+ ${exports$1.join("\n")}
1311
+ `;
1312
+ }
1313
+ function generateTypeDefinitions(name, pascalName, definition) {
1314
+ const muiComponent = getMuiComponent(name);
1315
+ return `/**
1316
+ * ${pascalName} Type Definitions
1317
+ *
1318
+ * @module @omnitron-dev/prism/components/${name}
1319
+ */
1320
+
1321
+ import type { ${muiComponent}Props as Mui${muiComponent}Props } from '@mui/material/${muiComponent}';
1322
+
1323
+ /**
1324
+ * Props for the ${pascalName} component.
1325
+ * Extends MUI ${muiComponent} with Prism-specific options.
1326
+ */
1327
+ export interface ${pascalName}Props extends Mui${muiComponent}Props {
1328
+ /**
1329
+ * Additional CSS class name.
1330
+ */
1331
+ className?: string;
1332
+ }
1333
+
1334
+ /**
1335
+ * Ref type for ${pascalName} component.
1336
+ */
1337
+ export type ${pascalName}Ref = HTMLDivElement;
1338
+ `;
1339
+ }
1340
+ function generateHook(hookName, pascalName, definition, isBlock) {
1341
+ const camelHook = toCamelCase(hookName);
1342
+ if (isBlock) {
1343
+ return generateBlockHook(hookName, pascalName, definition);
1344
+ }
1345
+ return `/**
1346
+ * ${hookName} Hook
1347
+ *
1348
+ * Custom hook for ${definition.displayName || pascalName} component logic.
1349
+ *
1350
+ * @module @omnitron-dev/prism/components/${definition.name}
1351
+ */
1352
+
1353
+ import { useState, useCallback, useMemo } from 'react';
1354
+
1355
+ /**
1356
+ * Options for ${camelHook} hook.
1357
+ */
1358
+ export interface ${toPascalCase(hookName)}Options {
1359
+ /**
1360
+ * Initial state value.
1361
+ */
1362
+ initialValue?: boolean;
1363
+ }
1364
+
1365
+ /**
1366
+ * Return type for ${camelHook} hook.
1367
+ */
1368
+ export interface ${toPascalCase(hookName)}Return {
1369
+ /**
1370
+ * Current state value.
1371
+ */
1372
+ value: boolean;
1373
+ /**
1374
+ * Set value to true.
1375
+ */
1376
+ onOpen: () => void;
1377
+ /**
1378
+ * Set value to false.
1379
+ */
1380
+ onClose: () => void;
1381
+ /**
1382
+ * Toggle the value.
1383
+ */
1384
+ onToggle: () => void;
1385
+ }
1386
+
1387
+ /**
1388
+ * Hook for managing ${definition.displayName || pascalName} state.
1389
+ *
1390
+ * @param options - Hook options
1391
+ * @returns State and handlers
1392
+ *
1393
+ * @example
1394
+ * \`\`\`tsx
1395
+ * function Example() {
1396
+ * const { value, onOpen, onClose, onToggle } = ${camelHook}();
1397
+ *
1398
+ * return (
1399
+ * <button onClick={onToggle}>
1400
+ * {value ? 'Open' : 'Closed'}
1401
+ * </button>
1402
+ * );
1403
+ * }
1404
+ * \`\`\`
1405
+ */
1406
+ export function ${camelHook}(options: ${toPascalCase(hookName)}Options = {}): ${toPascalCase(hookName)}Return {
1407
+ const { initialValue = false } = options;
1408
+
1409
+ const [value, setValue] = useState(initialValue);
1410
+
1411
+ const onOpen = useCallback(() => setValue(true), []);
1412
+ const onClose = useCallback(() => setValue(false), []);
1413
+ const onToggle = useCallback(() => setValue((prev) => !prev), []);
1414
+
1415
+ return useMemo(
1416
+ () => ({ value, onOpen, onClose, onToggle }),
1417
+ [value, onOpen, onClose, onToggle]
1418
+ );
1419
+ }
1420
+ `;
1421
+ }
1422
+ function generateBlockHook(hookName, pascalName, definition) {
1423
+ const camelHook = toCamelCase(hookName);
1424
+ return `/**
1425
+ * ${hookName} Hook
1426
+ *
1427
+ * State management hook for ${definition.displayName || pascalName} block.
1428
+ *
1429
+ * @module @omnitron-dev/prism/blocks/${definition.name}
1430
+ */
1431
+
1432
+ import { useState, useCallback, useMemo, useContext, createContext } from 'react';
1433
+ import type { ReactNode } from 'react';
1434
+
1435
+ // =============================================================================
1436
+ // TYPES
1437
+ // =============================================================================
1438
+
1439
+ /**
1440
+ * State for ${pascalName} block.
1441
+ */
1442
+ export interface ${pascalName}State {
1443
+ /**
1444
+ * Whether the sidebar/panel is open.
1445
+ */
1446
+ isOpen: boolean;
1447
+ /**
1448
+ * Whether the sidebar/panel is collapsed.
1449
+ */
1450
+ isCollapsed: boolean;
1451
+ }
1452
+
1453
+ /**
1454
+ * Actions for ${pascalName} block.
1455
+ */
1456
+ export interface ${pascalName}Actions {
1457
+ /**
1458
+ * Open the sidebar/panel.
1459
+ */
1460
+ open: () => void;
1461
+ /**
1462
+ * Close the sidebar/panel.
1463
+ */
1464
+ close: () => void;
1465
+ /**
1466
+ * Toggle open state.
1467
+ */
1468
+ toggle: () => void;
1469
+ /**
1470
+ * Collapse the sidebar.
1471
+ */
1472
+ collapse: () => void;
1473
+ /**
1474
+ * Expand the sidebar.
1475
+ */
1476
+ expand: () => void;
1477
+ /**
1478
+ * Toggle collapsed state.
1479
+ */
1480
+ toggleCollapse: () => void;
1481
+ }
1482
+
1483
+ /**
1484
+ * Context value for ${pascalName}.
1485
+ */
1486
+ export interface ${pascalName}ContextValue extends ${pascalName}State, ${pascalName}Actions {}
1487
+
1488
+ /**
1489
+ * Options for ${camelHook} hook.
1490
+ */
1491
+ export interface ${toPascalCase(hookName)}Options {
1492
+ /**
1493
+ * Initial open state.
1494
+ */
1495
+ defaultOpen?: boolean;
1496
+ /**
1497
+ * Initial collapsed state.
1498
+ */
1499
+ defaultCollapsed?: boolean;
1500
+ }
1501
+
1502
+ // =============================================================================
1503
+ // CONTEXT
1504
+ // =============================================================================
1505
+
1506
+ const ${pascalName}Context = createContext<${pascalName}ContextValue | null>(null);
1507
+
1508
+ /**
1509
+ * Provider props.
1510
+ */
1511
+ export interface ${pascalName}ProviderProps extends ${toPascalCase(hookName)}Options {
1512
+ children: ReactNode;
1513
+ }
1514
+
1515
+ /**
1516
+ * Provider component for ${pascalName} context.
1517
+ */
1518
+ export function ${pascalName}Provider({
1519
+ children,
1520
+ defaultOpen = true,
1521
+ defaultCollapsed = false,
1522
+ }: ${pascalName}ProviderProps) {
1523
+ const value = ${camelHook}({ defaultOpen, defaultCollapsed });
1524
+
1525
+ return (
1526
+ <${pascalName}Context.Provider value={value}>
1527
+ {children}
1528
+ </${pascalName}Context.Provider>
1529
+ );
1530
+ }
1531
+
1532
+ // =============================================================================
1533
+ // HOOK
1534
+ // =============================================================================
1535
+
1536
+ /**
1537
+ * Hook for managing ${definition.displayName || pascalName} state.
1538
+ *
1539
+ * @param options - Hook options
1540
+ * @returns State and actions
1541
+ *
1542
+ * @example
1543
+ * \`\`\`tsx
1544
+ * function ${pascalName}() {
1545
+ * const { isOpen, isCollapsed, toggle, toggleCollapse } = ${camelHook}();
1546
+ *
1547
+ * return (
1548
+ * <div>
1549
+ * <button onClick={toggle}>Toggle Open</button>
1550
+ * <button onClick={toggleCollapse}>Toggle Collapse</button>
1551
+ * </div>
1552
+ * );
1553
+ * }
1554
+ * \`\`\`
1555
+ */
1556
+ export function ${camelHook}(
1557
+ options: ${toPascalCase(hookName)}Options = {}
1558
+ ): ${pascalName}ContextValue {
1559
+ const context = useContext(${pascalName}Context);
1560
+
1561
+ const { defaultOpen = true, defaultCollapsed = false } = options;
1562
+
1563
+ const [isOpen, setIsOpen] = useState(context?.isOpen ?? defaultOpen);
1564
+ const [isCollapsed, setIsCollapsed] = useState(context?.isCollapsed ?? defaultCollapsed);
1565
+
1566
+ const open = useCallback(() => setIsOpen(true), []);
1567
+ const close = useCallback(() => setIsOpen(false), []);
1568
+ const toggle = useCallback(() => setIsOpen((prev) => !prev), []);
1569
+
1570
+ const collapse = useCallback(() => setIsCollapsed(true), []);
1571
+ const expand = useCallback(() => setIsCollapsed(false), []);
1572
+ const toggleCollapse = useCallback(() => setIsCollapsed((prev) => !prev), []);
1573
+
1574
+ return useMemo(
1575
+ () => ({
1576
+ isOpen,
1577
+ isCollapsed,
1578
+ open,
1579
+ close,
1580
+ toggle,
1581
+ collapse,
1582
+ expand,
1583
+ toggleCollapse,
1584
+ }),
1585
+ [isOpen, isCollapsed, open, close, toggle, collapse, expand, toggleCollapse]
1586
+ );
1587
+ }
1588
+
1589
+ /**
1590
+ * Hook to consume ${pascalName} context.
1591
+ * Must be used within a ${pascalName}Provider.
1592
+ */
1593
+ export function use${pascalName}Context(): ${pascalName}ContextValue {
1594
+ const context = useContext(${pascalName}Context);
1595
+
1596
+ if (!context) {
1597
+ throw new Error('use${pascalName}Context must be used within a ${pascalName}Provider');
1598
+ }
1599
+
1600
+ return context;
1601
+ }
1602
+ `;
1603
+ }
1604
+ function generateSchema(name, pascalName, definition) {
1605
+ return `/**
1606
+ * ${pascalName} Schema
1607
+ *
1608
+ * Zod validation schemas for ${definition.displayName || pascalName} forms.
1609
+ *
1610
+ * @module @omnitron-dev/prism/blocks/${definition.name}
1611
+ */
1612
+
1613
+ import { z } from 'zod';
1614
+
1615
+ /**
1616
+ * Login form schema.
1617
+ */
1618
+ export const loginSchema = z.object({
1619
+ email: z
1620
+ .string()
1621
+ .min(1, 'Email is required')
1622
+ .email('Invalid email address'),
1623
+ password: z
1624
+ .string()
1625
+ .min(1, 'Password is required')
1626
+ .min(8, 'Password must be at least 8 characters'),
1627
+ rememberMe: z.boolean().optional(),
1628
+ });
1629
+
1630
+ /**
1631
+ * Login form values type.
1632
+ */
1633
+ export type LoginFormValues = z.infer<typeof loginSchema>;
1634
+
1635
+ /**
1636
+ * Register form schema.
1637
+ */
1638
+ export const registerSchema = z
1639
+ .object({
1640
+ firstName: z.string().min(1, 'First name is required'),
1641
+ lastName: z.string().min(1, 'Last name is required'),
1642
+ email: z
1643
+ .string()
1644
+ .min(1, 'Email is required')
1645
+ .email('Invalid email address'),
1646
+ password: z
1647
+ .string()
1648
+ .min(1, 'Password is required')
1649
+ .min(8, 'Password must be at least 8 characters'),
1650
+ confirmPassword: z.string().min(1, 'Please confirm your password'),
1651
+ acceptTerms: z.literal(true, {
1652
+ errorMap: () => ({ message: 'You must accept the terms' }),
1653
+ }),
1654
+ })
1655
+ .refine((data) => data.password === data.confirmPassword, {
1656
+ message: 'Passwords do not match',
1657
+ path: ['confirmPassword'],
1658
+ });
1659
+
1660
+ /**
1661
+ * Register form values type.
1662
+ */
1663
+ export type RegisterFormValues = z.infer<typeof registerSchema>;
1664
+
1665
+ /**
1666
+ * Forgot password form schema.
1667
+ */
1668
+ export const forgotPasswordSchema = z.object({
1669
+ email: z
1670
+ .string()
1671
+ .min(1, 'Email is required')
1672
+ .email('Invalid email address'),
1673
+ });
1674
+
1675
+ /**
1676
+ * Forgot password form values type.
1677
+ */
1678
+ export type ForgotPasswordFormValues = z.infer<typeof forgotPasswordSchema>;
1679
+
1680
+ /**
1681
+ * Verify code form schema.
1682
+ */
1683
+ export const verifyCodeSchema = z.object({
1684
+ code: z
1685
+ .string()
1686
+ .min(1, 'Code is required')
1687
+ .length(6, 'Code must be 6 digits'),
1688
+ });
1689
+
1690
+ /**
1691
+ * Verify code form values type.
1692
+ */
1693
+ export type VerifyCodeFormValues = z.infer<typeof verifyCodeSchema>;
1694
+ `;
1695
+ }
1696
+ function generateComponent(name, pascalName, camelName, fileName, definition, isBlock) {
1697
+ const componentName = fileName.replace(/\.tsx$/, "");
1698
+ const componentPascal = toPascalCase(componentName.replace(pascalName, "")) || pascalName;
1699
+ const muiComponent = getMuiComponent(name);
1700
+ if (isBlock) {
1701
+ return generateBlockComponent(name, componentName, componentPascal, definition);
1702
+ }
1703
+ return `'use client';
1704
+
1705
+ /**
1706
+ * ${componentPascal} Component
1707
+ *
1708
+ * ${definition.description || ""}
1709
+ *
1710
+ * @module @omnitron-dev/prism/components/${definition.name}
1711
+ * @see https://mui.com/material-ui/react-${name}/
1712
+ */
1713
+
1714
+ import { forwardRef } from 'react';
1715
+ import Mui${muiComponent} from '@mui/material/${muiComponent}';
1716
+ import type { ${muiComponent}Props as Mui${muiComponent}Props } from '@mui/material/${muiComponent}';
1717
+ import { clsx } from 'clsx';
1718
+
1719
+ /**
1720
+ * Props for the ${componentPascal} component.
1721
+ */
1722
+ export interface ${componentPascal}Props extends Mui${muiComponent}Props {
1723
+ /**
1724
+ * Additional CSS class name.
1725
+ */
1726
+ className?: string;
1727
+ }
1728
+
1729
+ /**
1730
+ * ${definition.displayName || componentPascal} component.
1731
+ *
1732
+ * A wrapper around MUI ${muiComponent} with Prism design system styling.
1733
+ *
1734
+ * @example
1735
+ * \`\`\`tsx
1736
+ * <${componentPascal} variant="contained" color="primary">
1737
+ * Click me
1738
+ * </${componentPascal}>
1739
+ * \`\`\`
1740
+ */
1741
+ export const ${componentPascal} = forwardRef<HTMLButtonElement, ${componentPascal}Props>(
1742
+ function ${componentPascal}({ className, ...props }, ref) {
1743
+ return (
1744
+ <Mui${muiComponent}
1745
+ ref={ref}
1746
+ className={clsx('prism-${name}', className)}
1747
+ {...props}
1748
+ />
1749
+ );
1750
+ }
1751
+ );
1752
+
1753
+ ${componentPascal}.displayName = '${componentPascal}';
1754
+ `;
1755
+ }
1756
+ function generateBlockComponent(name, componentName, componentPascal, definition) {
1757
+ return `'use client';
1758
+
1759
+ /**
1760
+ * ${componentPascal} Component
1761
+ *
1762
+ * ${definition.description || ""}
1763
+ *
1764
+ * @module @omnitron-dev/prism/blocks/${definition.name}
1765
+ */
1766
+
1767
+ import { forwardRef } from 'react';
1768
+ import type { ReactNode } from 'react';
1769
+ import Box from '@mui/material/Box';
1770
+ import type { BoxProps } from '@mui/material/Box';
1771
+ import { styled } from '@mui/material/styles';
1772
+ import { clsx } from 'clsx';
1773
+
1774
+ /**
1775
+ * Props for the ${componentPascal} component.
1776
+ */
1777
+ export interface ${componentPascal}Props extends Omit<BoxProps, 'children'> {
1778
+ /**
1779
+ * Content to render inside the component.
1780
+ */
1781
+ children?: ReactNode;
1782
+ /**
1783
+ * Additional CSS class name.
1784
+ */
1785
+ className?: string;
1786
+ }
1787
+
1788
+ /**
1789
+ * Styled root component.
1790
+ */
1791
+ const ${componentPascal}Root = styled(Box)(({ theme }) => ({
1792
+ display: 'flex',
1793
+ flexDirection: 'column',
1794
+ minHeight: '100vh',
1795
+ backgroundColor: theme.palette.background.default,
1796
+ }));
1797
+
1798
+ /**
1799
+ * ${definition.displayName || componentPascal} component.
1800
+ *
1801
+ * @example
1802
+ * \`\`\`tsx
1803
+ * <${componentPascal}>
1804
+ * <Header />
1805
+ * <Sidebar />
1806
+ * <Main />
1807
+ * </${componentPascal}>
1808
+ * \`\`\`
1809
+ */
1810
+ export const ${componentPascal} = forwardRef<HTMLDivElement, ${componentPascal}Props>(
1811
+ function ${componentPascal}({ className, children, ...props }, ref) {
1812
+ return (
1813
+ <${componentPascal}Root
1814
+ ref={ref}
1815
+ className={clsx('prism-${name}', className)}
1816
+ {...props}
1817
+ >
1818
+ {children}
1819
+ </${componentPascal}Root>
1820
+ );
1821
+ }
1822
+ );
1823
+
1824
+ ${componentPascal}.displayName = '${componentPascal}';
1825
+ `;
1826
+ }
1827
+ function getMuiComponent(name) {
1828
+ const mapping = {
1829
+ button: "Button",
1830
+ "icon-button": "IconButton",
1831
+ "text-field": "TextField",
1832
+ select: "Select",
1833
+ checkbox: "Checkbox",
1834
+ switch: "Switch",
1835
+ avatar: "Avatar",
1836
+ badge: "Badge",
1837
+ chip: "Chip",
1838
+ tooltip: "Tooltip",
1839
+ alert: "Alert",
1840
+ snackbar: "Snackbar",
1841
+ dialog: "Dialog",
1842
+ progress: "CircularProgress",
1843
+ card: "Card",
1844
+ paper: "Paper",
1845
+ accordion: "Accordion",
1846
+ tabs: "Tabs",
1847
+ breadcrumbs: "Breadcrumbs",
1848
+ menu: "Menu",
1849
+ stack: "Stack",
1850
+ grid: "Grid",
1851
+ container: "Container",
1852
+ divider: "Divider",
1853
+ "data-table": "Table",
1854
+ table: "Table",
1855
+ list: "List"
1856
+ };
1857
+ return mapping[name] || toPascalCase(name);
1858
+ }
1859
+ var init_add = __esm({
1860
+ "src/cli/commands/add.ts"() {
1861
+ init_constants();
1862
+ init_config();
1863
+ init_registry();
1864
+ }
1865
+ });
1866
+
1867
+ // src/cli/index.ts
1868
+ init_add();
1869
+
1870
+ // src/cli/commands/init.ts
1871
+ init_constants();
1872
+ init_config();
1873
+ async function prompt(question, defaultValue) {
1874
+ const rl = readline.createInterface({
1875
+ input: process.stdin,
1876
+ output: process.stdout
1877
+ });
1878
+ return new Promise((resolve3) => {
1879
+ const displayQuestion = defaultValue ? `${question} (${defaultValue}): ` : `${question}: `;
1880
+ rl.question(displayQuestion, (answer) => {
1881
+ rl.close();
1882
+ resolve3(answer.trim() || defaultValue || "");
1883
+ });
1884
+ });
1885
+ }
1886
+ async function confirm(question, defaultValue = true) {
1887
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
1888
+ const answer = await prompt(`${question} ${hint}`);
1889
+ if (!answer) {
1890
+ return defaultValue;
1891
+ }
1892
+ return ["y", "yes", "\u0434\u0430"].includes(answer.toLowerCase());
1893
+ }
1894
+ function initCommand() {
1895
+ const command = new Command("init");
1896
+ command.description("Initialize Prism in your project").option("-y, --yes", "Skip prompts and use defaults").option("-d, --defaults", "Use default configuration").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (options) => {
1897
+ await runInit(options);
1898
+ });
1899
+ return command;
1900
+ }
1901
+ async function runInit(options) {
1902
+ const cwd = options.cwd || process.cwd();
1903
+ console.log("");
1904
+ log.info("Initializing Prism...");
1905
+ console.log("");
1906
+ const existingConfig = findConfigFile(cwd);
1907
+ if (existingConfig) {
1908
+ log.warning(`Config already exists at ${existingConfig}`);
1909
+ const overwrite = options.yes || await confirm("Overwrite existing configuration?", false);
1910
+ if (!overwrite) {
1911
+ log.info("Initialization cancelled.");
1912
+ return;
1913
+ }
1914
+ }
1915
+ let config;
1916
+ if (options.yes || options.defaults) {
1917
+ config = { ...DEFAULT_CONFIG };
1918
+ } else {
1919
+ config = await interactiveInit(cwd);
1920
+ }
1921
+ const dirs = [
1922
+ path.join(cwd, DEFAULT_COMPONENTS_DIR),
1923
+ path.join(cwd, DEFAULT_BLOCKS_DIR),
1924
+ path.join(cwd, DEFAULT_HOOKS_DIR),
1925
+ path.join(cwd, DEFAULT_UTILS_DIR)
1926
+ ];
1927
+ for (const dir of dirs) {
1928
+ if (!fs6.existsSync(dir)) {
1929
+ await fs6.promises.mkdir(dir, { recursive: true });
1930
+ log.success(`Created ${path.relative(cwd, dir)}/`);
1931
+ }
1932
+ }
1933
+ const configPath = path.join(cwd, CONFIG_FILE_NAME);
1934
+ await saveConfig(config, configPath);
1935
+ log.success(`Created ${CONFIG_FILE_NAME}`);
1936
+ console.log("");
1937
+ log.success("Prism initialized successfully!");
1938
+ console.log("");
1939
+ log.info("Next steps:");
1940
+ console.log(" 1. Run `prism add button` to add your first component");
1941
+ console.log(" 2. Run `prism list` to see available components");
1942
+ console.log(" 3. Visit https://prism.omnitron.dev/docs for documentation");
1943
+ console.log("");
1944
+ }
1945
+ async function interactiveInit(cwd) {
1946
+ console.log("This will guide you through configuring Prism for your project.\n");
1947
+ const styleAnswer = await prompt("Which style would you like to use? (default/new-york)", "default");
1948
+ const style = styleAnswer === "new-york" ? "new-york" : "default";
1949
+ const componentsAlias = await prompt("Where should components be installed?", "@/components/ui");
1950
+ const blocksAlias = await prompt("Where should blocks be installed?", "@/blocks");
1951
+ const hooksAlias = await prompt("Where should hooks be installed?", "@/hooks");
1952
+ const utilsAlias = await prompt("Where should utils be installed?", "@/utils");
1953
+ const tailwindConfigPath = path.join(cwd, "tailwind.config.js");
1954
+ const tailwindTsConfigPath = path.join(cwd, "tailwind.config.ts");
1955
+ const hasTailwind = fs6.existsSync(tailwindConfigPath) || fs6.existsSync(tailwindTsConfigPath);
1956
+ let tailwindConfig;
1957
+ if (hasTailwind) {
1958
+ const useTailwind = await confirm("Tailwind CSS detected. Configure CSS variables?", true);
1959
+ if (useTailwind) {
1960
+ const cssFile = await prompt("Where is your global CSS file?", "src/index.css");
1961
+ const baseColor = await prompt("What base color would you like?", "slate");
1962
+ tailwindConfig = {
1963
+ config: fs6.existsSync(tailwindTsConfigPath) ? "tailwind.config.ts" : "tailwind.config.js",
1964
+ css: cssFile,
1965
+ baseColor,
1966
+ cssVariables: true
1967
+ };
1968
+ }
1969
+ }
1970
+ return {
1971
+ $schema: "https://prism.omnitron.dev/schema.json",
1972
+ style,
1973
+ tailwind: tailwindConfig,
1974
+ aliases: {
1975
+ components: componentsAlias,
1976
+ blocks: blocksAlias,
1977
+ hooks: hooksAlias,
1978
+ utils: utilsAlias
1979
+ },
1980
+ registries: DEFAULT_CONFIG.registries
1981
+ };
1982
+ }
1983
+
1984
+ // src/cli/commands/list.ts
1985
+ init_constants();
1986
+ init_registry();
1987
+ function listCommand() {
1988
+ const command = new Command("list");
1989
+ command.description("List available components and blocks").option("-c, --components", "List only components").option("-b, --blocks", "List only blocks").option("--category <category>", "Filter by category").option("--json", "Output as JSON").action(async (options) => {
1990
+ await runList(options);
1991
+ });
1992
+ return command;
1993
+ }
1994
+ async function runList(options) {
1995
+ const showComponents = options.components || !options.components && !options.blocks;
1996
+ const showBlocks = options.blocks || !options.components && !options.blocks;
1997
+ if (options.json) {
1998
+ const output = {
1999
+ ...showComponents && { components: defaultRegistrySchema.components },
2000
+ ...showBlocks && { blocks: defaultRegistrySchema.blocks }
2001
+ };
2002
+ console.log(JSON.stringify(output, null, 2));
2003
+ return;
2004
+ }
2005
+ console.log("");
2006
+ if (showComponents) {
2007
+ log.info("Available Components:");
2008
+ console.log("");
2009
+ listItems(defaultRegistrySchema.components, options.category, COMPONENT_CATEGORIES);
2010
+ }
2011
+ if (showBlocks) {
2012
+ if (showComponents) console.log("");
2013
+ log.info("Available Blocks:");
2014
+ console.log("");
2015
+ listItems(defaultRegistrySchema.blocks, options.category, BLOCK_CATEGORIES);
2016
+ }
2017
+ console.log("");
2018
+ log.muted("Use `prism add <name>` to add a component to your project.");
2019
+ log.muted("Use `prism add block:<name>` to add a block to your project.");
2020
+ console.log("");
2021
+ }
2022
+ function listItems(items, filterCategory, categoryOrder) {
2023
+ const byCategory = {};
2024
+ for (const item of Object.values(items)) {
2025
+ if (filterCategory && item.category !== filterCategory) {
2026
+ continue;
2027
+ }
2028
+ if (!byCategory[item.category]) {
2029
+ byCategory[item.category] = [];
2030
+ }
2031
+ byCategory[item.category].push(item);
2032
+ }
2033
+ const sortedCategories = Object.keys(byCategory).sort((a, b) => {
2034
+ const aIndex = categoryOrder.indexOf(a);
2035
+ const bIndex = categoryOrder.indexOf(b);
2036
+ if (aIndex === -1 && bIndex === -1) return a.localeCompare(b);
2037
+ if (aIndex === -1) return 1;
2038
+ if (bIndex === -1) return -1;
2039
+ return aIndex - bIndex;
2040
+ });
2041
+ for (const category of sortedCategories) {
2042
+ const categoryItems = byCategory[category];
2043
+ const categoryTitle = category.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
2044
+ console.log(` ${COLORS.primary}${categoryTitle}${COLORS.reset}`);
2045
+ for (const item of categoryItems.sort((a, b) => a.name.localeCompare(b.name))) {
2046
+ const displayName = item.displayName || item.name;
2047
+ const description = item.description ? ` - ${item.description}` : "";
2048
+ console.log(
2049
+ ` ${COLORS.muted}\u2022${COLORS.reset} ${item.name} ${COLORS.muted}(${displayName})${description}${COLORS.reset}`
2050
+ );
2051
+ }
2052
+ console.log("");
2053
+ }
2054
+ }
2055
+
2056
+ // src/cli/commands/diff.ts
2057
+ init_constants();
2058
+ init_config();
2059
+ init_registry();
2060
+ function diffCommand() {
2061
+ const command = new Command("diff");
2062
+ command.description("Show differences between local and registry versions").argument("[items...]", "Components or blocks to diff (default: all installed)").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (items, options) => {
2063
+ await runDiff(items, options);
2064
+ });
2065
+ return command;
2066
+ }
2067
+ async function runDiff(items, options) {
2068
+ const cwd = options.cwd || process.cwd();
2069
+ const config = await loadConfig(cwd);
2070
+ if (!config) {
2071
+ log.error("No prism.config.json found. Run `prism init` first.");
2072
+ process.exit(1);
2073
+ }
2074
+ console.log("");
2075
+ log.info("Checking for updates...");
2076
+ console.log("");
2077
+ const installedItems = await findInstalledItems(config, items);
2078
+ if (installedItems.length === 0) {
2079
+ log.info("No Prism components or blocks found in your project.");
2080
+ log.muted("Run `prism add <component>` to add components.");
2081
+ return;
2082
+ }
2083
+ const diffs = [];
2084
+ for (const item of installedItems) {
2085
+ const status = await checkItemStatus(item, config);
2086
+ diffs.push({ name: item.name, status });
2087
+ }
2088
+ const upToDate = diffs.filter((d) => d.status === "up-to-date");
2089
+ const outdated = diffs.filter((d) => d.status === "outdated");
2090
+ const modified = diffs.filter((d) => d.status === "modified");
2091
+ const unknown = diffs.filter((d) => d.status === "unknown");
2092
+ if (upToDate.length > 0) {
2093
+ console.log(`${COLORS.success}Up to date (${upToDate.length}):${COLORS.reset}`);
2094
+ for (const item of upToDate) {
2095
+ console.log(` ${COLORS.muted}\u2713${COLORS.reset} ${item.name}`);
2096
+ }
2097
+ console.log("");
2098
+ }
2099
+ if (modified.length > 0) {
2100
+ console.log(`${COLORS.warning}Modified locally (${modified.length}):${COLORS.reset}`);
2101
+ for (const item of modified) {
2102
+ console.log(` ${COLORS.warning}~${COLORS.reset} ${item.name}`);
2103
+ }
2104
+ console.log("");
2105
+ log.muted("Modified items have local changes. Use --overwrite with update to replace.");
2106
+ }
2107
+ if (outdated.length > 0) {
2108
+ console.log(`${COLORS.primary}Updates available (${outdated.length}):${COLORS.reset}`);
2109
+ for (const item of outdated) {
2110
+ console.log(` ${COLORS.primary}\u2191${COLORS.reset} ${item.name}`);
2111
+ }
2112
+ console.log("");
2113
+ log.info("Run `prism update` to update outdated components.");
2114
+ }
2115
+ if (unknown.length > 0) {
2116
+ console.log(`${COLORS.muted}Unknown (${unknown.length}):${COLORS.reset}`);
2117
+ for (const item of unknown) {
2118
+ console.log(` ${COLORS.muted}?${COLORS.reset} ${item.name}`);
2119
+ }
2120
+ console.log("");
2121
+ }
2122
+ console.log("");
2123
+ }
2124
+ async function findInstalledItems(config, filterItems) {
2125
+ const items = [];
2126
+ const componentsDir = getComponentPath("", config);
2127
+ if (fs6.existsSync(componentsDir)) {
2128
+ const entries = await fs6.promises.readdir(componentsDir, { withFileTypes: true });
2129
+ for (const entry of entries) {
2130
+ if (entry.isDirectory()) {
2131
+ const name = entry.name;
2132
+ if (filterItems.length === 0 || filterItems.includes(name)) {
2133
+ items.push({
2134
+ name,
2135
+ type: "component",
2136
+ path: path.join(componentsDir, name)
2137
+ });
2138
+ }
2139
+ }
2140
+ }
2141
+ }
2142
+ const blocksDir = getBlockPath("", config);
2143
+ if (fs6.existsSync(blocksDir)) {
2144
+ const entries = await fs6.promises.readdir(blocksDir, { withFileTypes: true });
2145
+ for (const entry of entries) {
2146
+ if (entry.isDirectory()) {
2147
+ const name = entry.name;
2148
+ if (filterItems.length === 0 || filterItems.includes(name) || filterItems.includes(`block:${name}`)) {
2149
+ items.push({
2150
+ name,
2151
+ type: "block",
2152
+ path: path.join(blocksDir, name)
2153
+ });
2154
+ }
2155
+ }
2156
+ }
2157
+ }
2158
+ return items;
2159
+ }
2160
+ async function checkItemStatus(item, config) {
2161
+ const registry2 = item.type === "block" ? defaultRegistrySchema.blocks : defaultRegistrySchema.components;
2162
+ const definition = registry2[item.name];
2163
+ if (!definition) {
2164
+ return "unknown";
2165
+ }
2166
+ const lockfilePath = path.join(config.rootDir, "prism.lock.json");
2167
+ let installedVersion;
2168
+ if (fs6.existsSync(lockfilePath)) {
2169
+ try {
2170
+ const lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
2171
+ const installed = item.type === "block" ? lockfile.blocks?.[item.name] : lockfile.components?.[item.name];
2172
+ installedVersion = installed?.version;
2173
+ } catch {
2174
+ }
2175
+ }
2176
+ if (installedVersion && installedVersion !== definition.version) {
2177
+ return "outdated";
2178
+ }
2179
+ const hasModifications = await checkForLocalModifications(item, definition);
2180
+ if (hasModifications) {
2181
+ return "modified";
2182
+ }
2183
+ return "up-to-date";
2184
+ }
2185
+ async function checkForLocalModifications(item, definition, _config) {
2186
+ for (const file of definition.files) {
2187
+ const filePath = path.join(item.path, file.path);
2188
+ if (!fs6.existsSync(filePath)) {
2189
+ return true;
2190
+ }
2191
+ }
2192
+ const localFiles = await fs6.promises.readdir(item.path);
2193
+ const expectedFiles = new Set(definition.files.map((f) => f.path));
2194
+ for (const localFile of localFiles) {
2195
+ if (localFile.startsWith(".") || localFile === "node_modules") {
2196
+ continue;
2197
+ }
2198
+ if (!expectedFiles.has(localFile)) {
2199
+ return true;
2200
+ }
2201
+ }
2202
+ return false;
2203
+ }
2204
+
2205
+ // src/cli/commands/update.ts
2206
+ init_constants();
2207
+ init_config();
2208
+ init_registry();
2209
+ function updateCommand() {
2210
+ const command = new Command("update");
2211
+ command.description("Update installed components and blocks").argument("[items...]", "Components or blocks to update (default: all installed)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite modified files").option("-a, --all", "Update all installed items").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (items, options) => {
2212
+ await runUpdate(items, options);
2213
+ });
2214
+ return command;
2215
+ }
2216
+ async function runUpdate(items, options) {
2217
+ const cwd = options.cwd || process.cwd();
2218
+ const config = await loadConfig(cwd);
2219
+ if (!config) {
2220
+ log.error("No prism.config.json found. Run `prism init` first.");
2221
+ process.exit(1);
2222
+ }
2223
+ console.log("");
2224
+ log.info("Checking for updates...");
2225
+ console.log("");
2226
+ const installedItems = await findInstalledItems2(config, items, options.all);
2227
+ if (installedItems.length === 0) {
2228
+ log.info("No Prism components or blocks found to update.");
2229
+ return;
2230
+ }
2231
+ const toUpdate = [];
2232
+ for (const item of installedItems) {
2233
+ const hasUpdate = await checkForUpdate(item, config);
2234
+ if (hasUpdate) {
2235
+ toUpdate.push(item);
2236
+ }
2237
+ }
2238
+ if (toUpdate.length === 0) {
2239
+ log.success("All items are up to date!");
2240
+ return;
2241
+ }
2242
+ log.info(`Found ${toUpdate.length} item(s) to update:`);
2243
+ for (const item of toUpdate) {
2244
+ console.log(` \u2022 ${item.name}`);
2245
+ }
2246
+ console.log("");
2247
+ const results = [];
2248
+ for (const item of toUpdate) {
2249
+ try {
2250
+ await updateItem(item, config, options);
2251
+ results.push({ name: item.name, success: true });
2252
+ log.success(`Updated ${item.name}`);
2253
+ } catch (error) {
2254
+ results.push({ name: item.name, success: false, error: error.message });
2255
+ log.error(`Failed to update ${item.name}: ${error.message}`);
2256
+ }
2257
+ }
2258
+ console.log("");
2259
+ const successCount = results.filter((r) => r.success).length;
2260
+ const failCount = results.filter((r) => !r.success).length;
2261
+ if (successCount > 0) {
2262
+ log.success(`Updated ${successCount} item(s) successfully.`);
2263
+ }
2264
+ if (failCount > 0) {
2265
+ log.error(`Failed to update ${failCount} item(s).`);
2266
+ }
2267
+ console.log("");
2268
+ }
2269
+ async function findInstalledItems2(config, filterItems, all) {
2270
+ const items = [];
2271
+ const componentsDir = getComponentPath("", config);
2272
+ if (fs6.existsSync(componentsDir)) {
2273
+ const entries = await fs6.promises.readdir(componentsDir, { withFileTypes: true });
2274
+ for (const entry of entries) {
2275
+ if (entry.isDirectory()) {
2276
+ const name = entry.name;
2277
+ if (all || filterItems.length === 0 || filterItems.includes(name)) {
2278
+ items.push({
2279
+ name,
2280
+ type: "component",
2281
+ path: path.join(componentsDir, name)
2282
+ });
2283
+ }
2284
+ }
2285
+ }
2286
+ }
2287
+ const blocksDir = getBlockPath("", config);
2288
+ if (fs6.existsSync(blocksDir)) {
2289
+ const entries = await fs6.promises.readdir(blocksDir, { withFileTypes: true });
2290
+ for (const entry of entries) {
2291
+ if (entry.isDirectory()) {
2292
+ const name = entry.name;
2293
+ if (all || filterItems.length === 0 || filterItems.includes(name) || filterItems.includes(`block:${name}`)) {
2294
+ items.push({
2295
+ name,
2296
+ type: "block",
2297
+ path: path.join(blocksDir, name)
2298
+ });
2299
+ }
2300
+ }
2301
+ }
2302
+ }
2303
+ return items;
2304
+ }
2305
+ async function checkForUpdate(item, config) {
2306
+ const registry2 = item.type === "block" ? defaultRegistrySchema.blocks : defaultRegistrySchema.components;
2307
+ const definition = registry2[item.name];
2308
+ if (!definition) {
2309
+ return false;
2310
+ }
2311
+ const lockfilePath = path.join(config.rootDir, "prism.lock.json");
2312
+ if (fs6.existsSync(lockfilePath)) {
2313
+ try {
2314
+ const lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
2315
+ const installed = item.type === "block" ? lockfile.blocks?.[item.name] : lockfile.components?.[item.name];
2316
+ if (installed?.version && installed.version !== definition.version) {
2317
+ return true;
2318
+ }
2319
+ } catch {
2320
+ }
2321
+ }
2322
+ return false;
2323
+ }
2324
+ async function updateItem(item, config, options) {
2325
+ const registry2 = item.type === "block" ? defaultRegistrySchema.blocks : defaultRegistrySchema.components;
2326
+ const definition = registry2[item.name];
2327
+ if (!definition) {
2328
+ throw new Error("Item not found in registry");
2329
+ }
2330
+ if (!options.overwrite) {
2331
+ const backupDir = path.join(item.path, ".prism-backup");
2332
+ await fs6.promises.mkdir(backupDir, { recursive: true });
2333
+ for (const file of definition.files) {
2334
+ const filePath = path.join(item.path, file.path);
2335
+ if (fs6.existsSync(filePath)) {
2336
+ const backupPath = path.join(backupDir, file.path);
2337
+ await fs6.promises.copyFile(filePath, backupPath);
2338
+ }
2339
+ }
2340
+ log.muted(` Backed up ${definition.files.length} file(s) to .prism-backup/`);
2341
+ }
2342
+ const { generateFileContent: generateFileContent2 } = await Promise.resolve().then(() => (init_add(), add_exports));
2343
+ for (const file of definition.files) {
2344
+ const filePath = path.join(item.path, file.path);
2345
+ const content = generateFileContent2(
2346
+ item.name,
2347
+ file.path,
2348
+ file.type,
2349
+ definition,
2350
+ item.type === "block"
2351
+ );
2352
+ await fs6.promises.writeFile(filePath, content, "utf-8");
2353
+ }
2354
+ log.muted(` Updated ${definition.files.length} file(s) in ${path.relative(config.rootDir, item.path)}/`);
2355
+ const lockfilePath = path.join(config.rootDir, "prism.lock.json");
2356
+ let lockfile = {
2357
+ version: "1",
2358
+ components: {},
2359
+ blocks: {}
2360
+ };
2361
+ if (fs6.existsSync(lockfilePath)) {
2362
+ try {
2363
+ lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
2364
+ } catch {
2365
+ }
2366
+ }
2367
+ const entry = {
2368
+ name: item.name,
2369
+ version: definition.version,
2370
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
2371
+ };
2372
+ if (item.type === "block") {
2373
+ lockfile.blocks[item.name] = entry;
2374
+ } else {
2375
+ lockfile.components[item.name] = entry;
2376
+ }
2377
+ await fs6.promises.writeFile(lockfilePath, JSON.stringify(lockfile, null, 2), "utf-8");
2378
+ }
2379
+
2380
+ // src/cli/commands/remove.ts
2381
+ init_constants();
2382
+ init_config();
2383
+ function removeCommand() {
2384
+ const command = new Command("remove");
2385
+ command.description("Remove components or blocks from your project").argument("<items...>", "Components or blocks to remove").option("-y, --yes", "Skip confirmation prompts").option("-f, --force", "Force removal even if files have been modified").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (items, options) => {
2386
+ await runRemove(items, options);
2387
+ });
2388
+ return command;
2389
+ }
2390
+ async function runRemove(items, options) {
2391
+ const cwd = options.cwd || process.cwd();
2392
+ const config = await loadConfig(cwd);
2393
+ if (!config) {
2394
+ log.error("No prism.config.json found. Run `prism init` first.");
2395
+ process.exit(1);
2396
+ }
2397
+ if (items.length === 0) {
2398
+ log.error("No items specified. Use `prism remove <component>` or `prism remove block:<name>`");
2399
+ process.exit(1);
2400
+ }
2401
+ console.log("");
2402
+ log.info(`Removing ${items.length} item(s)...`);
2403
+ console.log("");
2404
+ const results = [];
2405
+ for (const item of items) {
2406
+ try {
2407
+ const result = await removeItem(item, config, options);
2408
+ results.push(result);
2409
+ } catch (error) {
2410
+ results.push({
2411
+ name: item,
2412
+ success: false,
2413
+ error: error.message
2414
+ });
2415
+ }
2416
+ }
2417
+ console.log("");
2418
+ const successCount = results.filter((r) => r.success).length;
2419
+ const failCount = results.filter((r) => !r.success).length;
2420
+ if (successCount > 0) {
2421
+ log.success(`Removed ${successCount} item(s) successfully.`);
2422
+ }
2423
+ if (failCount > 0) {
2424
+ log.error(`Failed to remove ${failCount} item(s):`);
2425
+ for (const result of results.filter((r) => !r.success)) {
2426
+ log.muted(` - ${result.name}: ${result.error}`);
2427
+ }
2428
+ process.exit(1);
2429
+ }
2430
+ }
2431
+ async function removeItem(item, config, options) {
2432
+ const isBlock = item.startsWith("block:");
2433
+ const name = isBlock ? item.replace("block:", "") : item;
2434
+ const itemPath = isBlock ? getBlockPath(name, config) : getComponentPath(name, config);
2435
+ if (!fs6.existsSync(itemPath)) {
2436
+ return {
2437
+ name: item,
2438
+ success: false,
2439
+ error: `Not installed at ${path.relative(config.rootDir, itemPath)}`
2440
+ };
2441
+ }
2442
+ try {
2443
+ await fs6.promises.rm(itemPath, { recursive: true, force: true });
2444
+ log.success(`Removed ${name} from ${path.relative(config.rootDir, itemPath)}/`);
2445
+ await updateLockfile2(config.rootDir, name, isBlock);
2446
+ return { name: item, success: true };
2447
+ } catch (error) {
2448
+ return {
2449
+ name: item,
2450
+ success: false,
2451
+ error: `Failed to remove: ${error.message}`
2452
+ };
2453
+ }
2454
+ }
2455
+ async function updateLockfile2(rootDir, name, isBlock) {
2456
+ const lockfilePath = path.join(rootDir, "prism.lock.json");
2457
+ if (!fs6.existsSync(lockfilePath)) {
2458
+ return;
2459
+ }
2460
+ try {
2461
+ const lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
2462
+ if (isBlock) {
2463
+ delete lockfile.blocks[name];
2464
+ } else {
2465
+ delete lockfile.components[name];
2466
+ }
2467
+ await fs6.promises.writeFile(lockfilePath, JSON.stringify(lockfile, null, 2) + "\n", "utf-8");
2468
+ log.muted(` Updated prism.lock.json`);
2469
+ } catch {
2470
+ log.warning(" Could not update lockfile");
2471
+ }
2472
+ }
2473
+
2474
+ // src/cli/commands/doctor.ts
2475
+ init_constants();
2476
+ init_config();
2477
+ function doctorCommand() {
2478
+ const command = new Command("doctor");
2479
+ command.description("Diagnose project configuration and environment").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (options) => {
2480
+ await runDoctor(options);
2481
+ });
2482
+ return command;
2483
+ }
2484
+ async function runDoctor(options) {
2485
+ const cwd = options.cwd || process.cwd();
2486
+ console.log("");
2487
+ log.info("Prism Doctor - Checking project health...");
2488
+ console.log("");
2489
+ const checks = [];
2490
+ checks.push(await checkConfigFile(cwd));
2491
+ checks.push(...await checkPackageJson(cwd));
2492
+ const config = await loadConfig(cwd);
2493
+ if (config) {
2494
+ checks.push(...checkDirectories(config));
2495
+ }
2496
+ checks.push(await checkTsConfig(cwd));
2497
+ checks.push(await checkLockfile(cwd));
2498
+ console.log("");
2499
+ const passCount = checks.filter((c) => c.status === "pass").length;
2500
+ const warnCount = checks.filter((c) => c.status === "warn").length;
2501
+ const failCount = checks.filter((c) => c.status === "fail").length;
2502
+ for (const check of checks) {
2503
+ const icon = check.status === "pass" ? `${COLORS.success}\u2713${COLORS.reset}` : check.status === "warn" ? `${COLORS.warning}\u26A0${COLORS.reset}` : `${COLORS.error}\u2716${COLORS.reset}`;
2504
+ console.log(` ${icon} ${check.name}: ${check.message}`);
2505
+ }
2506
+ console.log("");
2507
+ console.log(
2508
+ ` ${COLORS.success}${passCount} passed${COLORS.reset}` + (warnCount > 0 ? `, ${COLORS.warning}${warnCount} warnings${COLORS.reset}` : "") + (failCount > 0 ? `, ${COLORS.error}${failCount} failed${COLORS.reset}` : "")
2509
+ );
2510
+ console.log("");
2511
+ if (failCount > 0) {
2512
+ process.exit(1);
2513
+ }
2514
+ }
2515
+ async function checkConfigFile(cwd) {
2516
+ const configPath = findConfigFile(cwd);
2517
+ if (!configPath) {
2518
+ return {
2519
+ name: "Config file",
2520
+ status: "fail",
2521
+ message: "prism.config.json not found. Run `prism init` to create one."
2522
+ };
2523
+ }
2524
+ return {
2525
+ name: "Config file",
2526
+ status: "pass",
2527
+ message: `Found at ${path.relative(cwd, configPath)}`
2528
+ };
2529
+ }
2530
+ async function checkPackageJson(cwd) {
2531
+ const results = [];
2532
+ const pkgPath = path.join(cwd, "package.json");
2533
+ if (!fs6.existsSync(pkgPath)) {
2534
+ results.push({
2535
+ name: "package.json",
2536
+ status: "fail",
2537
+ message: "Not found in project root."
2538
+ });
2539
+ return results;
2540
+ }
2541
+ try {
2542
+ const pkg2 = JSON.parse(await fs6.promises.readFile(pkgPath, "utf-8"));
2543
+ const allDeps = { ...pkg2.dependencies, ...pkg2.devDependencies, ...pkg2.peerDependencies };
2544
+ const requiredPeers = ["react", "react-dom", "@mui/material"];
2545
+ for (const dep of requiredPeers) {
2546
+ if (allDeps[dep]) {
2547
+ results.push({
2548
+ name: dep,
2549
+ status: "pass",
2550
+ message: `${allDeps[dep]}`
2551
+ });
2552
+ } else {
2553
+ results.push({
2554
+ name: dep,
2555
+ status: "fail",
2556
+ message: "Not installed. Required peer dependency."
2557
+ });
2558
+ }
2559
+ }
2560
+ const optionalDeps = ["@emotion/react", "@emotion/styled", "zustand"];
2561
+ for (const dep of optionalDeps) {
2562
+ if (allDeps[dep]) {
2563
+ results.push({
2564
+ name: dep,
2565
+ status: "pass",
2566
+ message: `${allDeps[dep]}`
2567
+ });
2568
+ } else {
2569
+ results.push({
2570
+ name: dep,
2571
+ status: "warn",
2572
+ message: "Not installed. Recommended dependency."
2573
+ });
2574
+ }
2575
+ }
2576
+ } catch {
2577
+ results.push({
2578
+ name: "package.json",
2579
+ status: "fail",
2580
+ message: "Failed to parse."
2581
+ });
2582
+ }
2583
+ return results;
2584
+ }
2585
+ function checkDirectories(config) {
2586
+ const results = [];
2587
+ const dirs = {
2588
+ components: config.aliases.components,
2589
+ blocks: config.aliases.blocks,
2590
+ hooks: config.aliases.hooks,
2591
+ utils: config.aliases.utils
2592
+ };
2593
+ for (const [name, alias] of Object.entries(dirs)) {
2594
+ const resolved = resolveAlias(alias, config);
2595
+ if (fs6.existsSync(resolved)) {
2596
+ results.push({
2597
+ name: `${name} directory`,
2598
+ status: "pass",
2599
+ message: `Exists at ${path.relative(config.rootDir, resolved)}`
2600
+ });
2601
+ } else {
2602
+ results.push({
2603
+ name: `${name} directory`,
2604
+ status: "warn",
2605
+ message: `Not found at ${path.relative(config.rootDir, resolved)}. Will be created on first add.`
2606
+ });
2607
+ }
2608
+ }
2609
+ return results;
2610
+ }
2611
+ async function checkTsConfig(cwd) {
2612
+ const tsConfigPath = path.join(cwd, "tsconfig.json");
2613
+ if (!fs6.existsSync(tsConfigPath)) {
2614
+ return {
2615
+ name: "TypeScript",
2616
+ status: "warn",
2617
+ message: "tsconfig.json not found. Path aliases may not work."
2618
+ };
2619
+ }
2620
+ try {
2621
+ const content = await fs6.promises.readFile(tsConfigPath, "utf-8");
2622
+ const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
2623
+ const tsConfig = JSON.parse(stripped);
2624
+ const paths = tsConfig.compilerOptions?.paths || tsConfig.compilerOptions?.baseUrl;
2625
+ if (paths) {
2626
+ return {
2627
+ name: "TypeScript",
2628
+ status: "pass",
2629
+ message: "Path aliases configured."
2630
+ };
2631
+ }
2632
+ return {
2633
+ name: "TypeScript",
2634
+ status: "warn",
2635
+ message: "No path aliases found. Ensure @ alias is configured for Prism imports."
2636
+ };
2637
+ } catch {
2638
+ return {
2639
+ name: "TypeScript",
2640
+ status: "warn",
2641
+ message: "Could not parse tsconfig.json."
2642
+ };
2643
+ }
2644
+ }
2645
+ async function checkLockfile(cwd) {
2646
+ const lockfilePath = path.join(cwd, "prism.lock.json");
2647
+ if (!fs6.existsSync(lockfilePath)) {
2648
+ return {
2649
+ name: "Lockfile",
2650
+ status: "pass",
2651
+ message: "No lockfile yet (no components installed)."
2652
+ };
2653
+ }
2654
+ try {
2655
+ const lockfile = JSON.parse(await fs6.promises.readFile(lockfilePath, "utf-8"));
2656
+ const componentCount = Object.keys(lockfile.components || {}).length;
2657
+ const blockCount = Object.keys(lockfile.blocks || {}).length;
2658
+ return {
2659
+ name: "Lockfile",
2660
+ status: "pass",
2661
+ message: `${componentCount} component(s), ${blockCount} block(s) installed.`
2662
+ };
2663
+ } catch {
2664
+ return {
2665
+ name: "Lockfile",
2666
+ status: "warn",
2667
+ message: "Lockfile exists but could not be parsed."
2668
+ };
2669
+ }
2670
+ }
2671
+
2672
+ // src/cli/index.ts
2673
+ init_constants();
2674
+ init_add();
2675
+ init_constants();
2676
+ function createCli() {
2677
+ const program = new Command();
2678
+ program.name("prism").description("Prism Design System CLI - Component installation and management").version(PRISM_VERSION, "-v, --version", "Display the current version");
2679
+ program.addCommand(initCommand());
2680
+ program.addCommand(addCommand());
2681
+ program.addCommand(removeCommand());
2682
+ program.addCommand(listCommand());
2683
+ program.addCommand(diffCommand());
2684
+ program.addCommand(updateCommand());
2685
+ program.addCommand(doctorCommand());
2686
+ return program;
2687
+ }
2688
+ async function cli() {
2689
+ const program = createCli();
2690
+ await program.parseAsync(process.argv);
2691
+ }
2692
+
2693
+ export { DEFAULT_CONFIG, PRISM_VERSION, addCommand, cli, createCli, diffCommand, doctorCommand, initCommand, listCommand, removeCommand, updateCommand };
2694
+ //# sourceMappingURL=index.js.map
2695
+ //# sourceMappingURL=index.js.map