pittaya 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,34 +7,80 @@ import { Command } from "commander";
7
7
  import chalk from "chalk";
8
8
  import ora from "ora";
9
9
  import prompts from "prompts";
10
- import path4 from "path";
11
- import fs4 from "fs/promises";
10
+ import path6 from "path";
11
+ import fs6 from "fs/promises";
12
12
  import { execa } from "execa";
13
13
 
14
14
  // src/utils/registry.ts
15
15
  import fetch from "node-fetch";
16
- var REGISTRY_BASE_URL = "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry";
17
- async function fetchRegistry() {
16
+ import fs from "fs/promises";
17
+ import { existsSync } from "fs";
18
+ import path from "path";
19
+ import { fileURLToPath } from "url";
20
+ var DEFAULT_REGISTRY_BASE_URL = "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry";
21
+ function shouldPreferLocalRegistry() {
22
+ const raw = process.env.PITTAYA_REGISTRY_PREFER_LOCAL;
23
+ if (raw == null) return false;
24
+ const normalized = raw.toLowerCase();
25
+ return normalized === "true" || normalized === "1" || normalized === "yes";
26
+ }
27
+ function getLocalRegistryBaseUrl() {
18
28
  try {
19
- const response = await fetch(`${REGISTRY_BASE_URL}/index.json`);
29
+ const filePath = fileURLToPath(import.meta.url);
30
+ const dirPath = path.dirname(filePath);
31
+ const candidate = path.resolve(dirPath, "../../../registry");
32
+ if (!existsSync(candidate)) return null;
33
+ if (!existsSync(path.join(candidate, "styles"))) return null;
34
+ return candidate;
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+ function getRegistryBaseUrl() {
40
+ const localRegistry = shouldPreferLocalRegistry() ? getLocalRegistryBaseUrl() : null;
41
+ if (localRegistry) return localRegistry;
42
+ if (process.env.PITTAYA_REGISTRY_URL) {
43
+ return process.env.PITTAYA_REGISTRY_URL;
44
+ }
45
+ return DEFAULT_REGISTRY_BASE_URL;
46
+ }
47
+ function isHttpUrl(value) {
48
+ return value.startsWith("http://") || value.startsWith("https://");
49
+ }
50
+ async function readJsonFromRegistry(relativePath, config) {
51
+ const baseUrl = getRegistryBaseUrl();
52
+ if (isHttpUrl(baseUrl)) {
53
+ const response = await fetch(`${baseUrl}/${relativePath}`);
20
54
  if (!response.ok) {
21
55
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
22
56
  }
23
57
  return await response.json();
58
+ }
59
+ const absolutePath = path.resolve(baseUrl, relativePath);
60
+ const raw = await fs.readFile(absolutePath, "utf-8");
61
+ return JSON.parse(raw);
62
+ }
63
+ function getStyleFromConfig(config) {
64
+ return config?.style || "new-york";
65
+ }
66
+ async function fetchRegistry(config) {
67
+ try {
68
+ const style = getStyleFromConfig(config);
69
+ const styleIndex = await readJsonFromRegistry(`styles/${style}/index.json`, config);
70
+ return styleIndex;
24
71
  } catch (error) {
25
72
  console.error("Error fetching registry:", error);
26
73
  throw new Error("Unable to load the registry of components");
27
74
  }
28
75
  }
29
- async function getRegistryComponent(name) {
76
+ async function getRegistryComponent(name, config) {
30
77
  try {
31
- const response = await fetch(
32
- `${REGISTRY_BASE_URL}/components/${name}.json`
78
+ const style = getStyleFromConfig(config);
79
+ const styleComponent = await readJsonFromRegistry(
80
+ `styles/${style}/components/${name}.json`,
81
+ config
33
82
  );
34
- if (!response.ok) {
35
- throw new Error(`Component "${name}" not found in registry`);
36
- }
37
- return await response.json();
83
+ return styleComponent;
38
84
  } catch (error) {
39
85
  throw new Error(`Error loading component "${name}": ${error.message}`);
40
86
  }
@@ -72,21 +118,21 @@ function escapeRegex(str) {
72
118
  }
73
119
 
74
120
  // src/utils/package-manager.ts
75
- import fs from "fs/promises";
76
- import path from "path";
121
+ import fs2 from "fs/promises";
122
+ import path2 from "path";
77
123
  async function detectPackageManager() {
78
124
  try {
79
- await fs.access("pnpm-lock.yaml");
125
+ await fs2.access("pnpm-lock.yaml");
80
126
  return "pnpm";
81
127
  } catch {
82
128
  }
83
129
  try {
84
- await fs.access("yarn.lock");
130
+ await fs2.access("yarn.lock");
85
131
  return "yarn";
86
132
  } catch {
87
133
  }
88
134
  try {
89
- await fs.access("bun.lockb");
135
+ await fs2.access("bun.lockb");
90
136
  return "bun";
91
137
  } catch {
92
138
  }
@@ -95,8 +141,8 @@ async function detectPackageManager() {
95
141
  async function isPackageInstalled(packageName) {
96
142
  const cwd = process.cwd();
97
143
  try {
98
- const packageJsonPath = path.join(cwd, "package.json");
99
- const packageJson2 = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
144
+ const packageJsonPath = path2.join(cwd, "package.json");
145
+ const packageJson2 = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
100
146
  const allDeps = {
101
147
  ...packageJson2.dependencies,
102
148
  ...packageJson2.devDependencies
@@ -107,8 +153,8 @@ async function isPackageInstalled(packageName) {
107
153
  } catch {
108
154
  }
109
155
  try {
110
- const packagePath = path.join(cwd, "node_modules", packageName);
111
- await fs.access(packagePath);
156
+ const packagePath = path2.join(cwd, "node_modules", packageName);
157
+ await fs2.access(packagePath);
112
158
  return true;
113
159
  } catch {
114
160
  }
@@ -126,28 +172,28 @@ async function checkMissingDependencies(dependencies) {
126
172
  }
127
173
 
128
174
  // src/utils/component-checker.ts
129
- import path3 from "path";
130
- import fs3 from "fs/promises";
175
+ import path4 from "path";
176
+ import fs4 from "fs/promises";
131
177
 
132
178
  // src/utils/project-structure.ts
133
- import fs2 from "fs/promises";
134
- import path2 from "path";
179
+ import fs3 from "fs/promises";
180
+ import path3 from "path";
135
181
  async function hasSrcDirectory(cwd = process.cwd()) {
136
182
  try {
137
- const srcPath = path2.join(cwd, "src");
138
- await fs2.access(srcPath);
183
+ const srcPath = path3.join(cwd, "src");
184
+ await fs3.access(srcPath);
139
185
  const commonDirs = ["app", "components", "lib", "pages"];
140
186
  for (const dir of commonDirs) {
141
187
  try {
142
- await fs2.access(path2.join(srcPath, dir));
188
+ await fs3.access(path3.join(srcPath, dir));
143
189
  return true;
144
190
  } catch {
145
191
  continue;
146
192
  }
147
193
  }
148
194
  try {
149
- const tsconfigPath = path2.join(cwd, "tsconfig.json");
150
- const tsconfig = JSON.parse(await fs2.readFile(tsconfigPath, "utf-8"));
195
+ const tsconfigPath = path3.join(cwd, "tsconfig.json");
196
+ const tsconfig = JSON.parse(await fs3.readFile(tsconfigPath, "utf-8"));
151
197
  if (tsconfig.compilerOptions?.paths) {
152
198
  const paths = tsconfig.compilerOptions.paths;
153
199
  if (paths["@/*"]?.includes("./src/*")) {
@@ -184,12 +230,12 @@ async function getDefaultPaths(cwd = process.cwd()) {
184
230
  // src/utils/component-checker.ts
185
231
  async function isComponentInstalled(name, config) {
186
232
  try {
187
- const component = await getRegistryComponent(name);
233
+ const component = await getRegistryComponent(name, config);
188
234
  if (!component) return false;
189
235
  for (const file of component.files) {
190
236
  const targetPath = await resolveTargetPath(file.name, component.type, config);
191
- const filePath = path3.join(process.cwd(), targetPath);
192
- const exists = await fs3.access(filePath).then(() => true).catch(() => false);
237
+ const filePath = path4.join(process.cwd(), targetPath);
238
+ const exists = await fs4.access(filePath).then(() => true).catch(() => false);
193
239
  if (!exists) return false;
194
240
  }
195
241
  return true;
@@ -198,29 +244,135 @@ async function isComponentInstalled(name, config) {
198
244
  }
199
245
  }
200
246
  async function resolveTargetPath(fileName, type, config) {
247
+ const normalized = fileName.replace(/\\/g, "/");
201
248
  if (type === "registry:ui") {
202
249
  const resolvedPath = await resolveAliasPath(config.aliases.ui);
203
- return path3.join(resolvedPath, fileName);
250
+ const relative = normalized.replace(/^ui\//, "");
251
+ return path4.join(resolvedPath, relative);
204
252
  }
205
253
  if (type === "registry:lib") {
206
254
  const resolvedPath = await resolveAliasPath(config.aliases.lib);
207
- return path3.join(resolvedPath, fileName);
255
+ const relative = normalized.replace(/^lib\//, "");
256
+ return path4.join(resolvedPath, relative);
208
257
  }
209
258
  if (type === "registry:hook") {
210
259
  const resolvedPath = await resolveAliasPath(config.aliases.hooks);
211
- return path3.join(resolvedPath, fileName);
260
+ return path4.join(resolvedPath, fileName);
212
261
  }
213
262
  return fileName;
214
263
  }
215
264
 
265
+ // src/utils/project-config.ts
266
+ import fs5 from "fs/promises";
267
+ import path5 from "path";
268
+ function applyPittayaProjectConfig(pittaya) {
269
+ if (pittaya.registry?.url) {
270
+ process.env.PITTAYA_REGISTRY_URL = pittaya.registry.url;
271
+ }
272
+ if (typeof pittaya.registry?.preferLocal === "boolean") {
273
+ process.env.PITTAYA_REGISTRY_PREFER_LOCAL = String(pittaya.registry.preferLocal);
274
+ }
275
+ }
276
+ async function readJsonIfExists(absolutePath) {
277
+ try {
278
+ const raw = await fs5.readFile(absolutePath, "utf-8");
279
+ return JSON.parse(raw);
280
+ } catch {
281
+ return null;
282
+ }
283
+ }
284
+ async function loadProjectConfig(cwd = process.cwd()) {
285
+ const componentsJsonPath = path5.join(cwd, "components.json");
286
+ const pittayaJsonPath = path5.join(cwd, "pittaya.json");
287
+ const config = await readJsonIfExists(componentsJsonPath);
288
+ if (!config) {
289
+ throw new Error("components.json not found");
290
+ }
291
+ const pittaya = await readJsonIfExists(pittayaJsonPath) ?? {};
292
+ return { config, pittaya };
293
+ }
294
+
295
+ // src/utils/confirm.ts
296
+ import { createInterface } from "readline";
297
+ function resolveFromString(answer, initial) {
298
+ const value = (answer ?? "").trim().toLowerCase();
299
+ if (!value) return initial;
300
+ if (value === "y" || value === "yes") return true;
301
+ if (value === "n" || value === "no") return false;
302
+ return initial;
303
+ }
304
+ async function confirm(message, initial = false) {
305
+ const suffix = initial ? "(Y/n)" : "(y/N)";
306
+ const prompt = `${message} ${suffix} `;
307
+ if (!process.stdin.isTTY) {
308
+ const rl = createInterface({
309
+ input: process.stdin,
310
+ output: process.stdout
311
+ });
312
+ return await new Promise((resolve) => {
313
+ rl.question(prompt, (answer) => {
314
+ rl.close();
315
+ resolve(resolveFromString(answer, initial));
316
+ });
317
+ });
318
+ }
319
+ return await new Promise((resolve) => {
320
+ const stdin = process.stdin;
321
+ const stdout = process.stdout;
322
+ const prevRawMode = stdin.isRaw;
323
+ if (typeof stdin.setRawMode === "function") {
324
+ stdin.setRawMode(true);
325
+ }
326
+ stdin.resume();
327
+ stdout.write(prompt);
328
+ const cleanup = () => {
329
+ stdin.off("data", onData);
330
+ if (typeof stdin.setRawMode === "function") {
331
+ stdin.setRawMode(Boolean(prevRawMode));
332
+ }
333
+ stdin.pause();
334
+ };
335
+ const finish = (result) => {
336
+ stdout.write(`${result ? "y" : "n"}
337
+ `);
338
+ cleanup();
339
+ resolve(result);
340
+ };
341
+ const onData = (chunk) => {
342
+ const str = chunk.toString("utf8");
343
+ if (str === "") {
344
+ cleanup();
345
+ process.kill(process.pid, "SIGINT");
346
+ return;
347
+ }
348
+ const key = str.toLowerCase();
349
+ if (key === "\r" || key === "\n") {
350
+ finish(initial);
351
+ return;
352
+ }
353
+ if (key === "y") {
354
+ finish(true);
355
+ return;
356
+ }
357
+ if (key === "n") {
358
+ finish(false);
359
+ return;
360
+ }
361
+ };
362
+ stdin.on("data", onData);
363
+ });
364
+ }
365
+
216
366
  // src/commands/add.ts
217
367
  async function add(components, options) {
218
368
  const cwd = process.cwd();
219
- const componentsJsonPath = path4.join(cwd, "components.json");
220
369
  let config;
370
+ let pittayaConfig;
221
371
  try {
222
- const configContent = await fs4.readFile(componentsJsonPath, "utf-8");
223
- config = JSON.parse(configContent);
372
+ const loaded = await loadProjectConfig(cwd);
373
+ config = loaded.config;
374
+ pittayaConfig = loaded.pittaya;
375
+ applyPittayaProjectConfig(pittayaConfig);
224
376
  } catch (error) {
225
377
  console.log(chalk.red("\n\u274C components.json not found.\n"));
226
378
  console.log(
@@ -229,10 +381,14 @@ async function add(components, options) {
229
381
  );
230
382
  return;
231
383
  }
384
+ const resolvedOptions = {
385
+ ...options,
386
+ addMissingDeps: options.addMissingDeps ?? pittayaConfig?.install?.autoInstallDeps ?? false
387
+ };
232
388
  const spinner = ora("Fetching available components...").start();
233
389
  let registry;
234
390
  try {
235
- registry = await fetchRegistry();
391
+ registry = await fetchRegistry(config);
236
392
  spinner.succeed("Registry loaded!");
237
393
  } catch (error) {
238
394
  spinner.fail("Error loading registry");
@@ -266,7 +422,7 @@ Adding ${components.length} component(s)...
266
422
  `)
267
423
  );
268
424
  for (const componentName of components) {
269
- await addComponent(componentName, config, options);
425
+ await addComponent(componentName, config, resolvedOptions);
270
426
  }
271
427
  console.log(chalk.green("\n\u2705 Components added successfully!\n"));
272
428
  }
@@ -278,7 +434,7 @@ async function addComponent(name, config, options) {
278
434
  }
279
435
  const spinner = ora(`Installing ${chalk.bold(name)}...`).start();
280
436
  try {
281
- const component = await getRegistryComponent(name);
437
+ const component = await getRegistryComponent(name, config);
282
438
  if (!component) {
283
439
  spinner.fail(`Component "${name}" not found in registry.`);
284
440
  return;
@@ -298,12 +454,10 @@ async function addComponent(name, config, options) {
298
454
  if (options.addMissingDeps) {
299
455
  console.log(chalk.dim("Installing dependencies automatically...\n"));
300
456
  } else {
301
- const { install } = await prompts({
302
- type: "confirm",
303
- name: "install",
304
- message: "Do you want to install the dependencies now?",
305
- initial: true
306
- });
457
+ const install = await confirm(
458
+ "Do you want to install the dependencies now?",
459
+ true
460
+ );
307
461
  if (!install) {
308
462
  console.log(chalk.yellow("\n\u26A0\uFE0F Component not installed. Install the dependencies manually and try again.\n"));
309
463
  return;
@@ -336,25 +490,23 @@ async function addComponent(name, config, options) {
336
490
  }
337
491
  for (const file of component.files) {
338
492
  const targetPath = await resolveTargetPath(file.name, component.type, config);
339
- const filePath = path4.join(process.cwd(), targetPath);
340
- const exists = await fs4.access(filePath).then(() => true).catch(() => false);
493
+ const filePath = path6.join(process.cwd(), targetPath);
494
+ const exists = await fs6.access(filePath).then(() => true).catch(() => false);
341
495
  if (exists && !options.overwrite && !options.yes) {
342
496
  spinner.stop();
343
- const { overwrite } = await prompts({
344
- type: "confirm",
345
- name: "overwrite",
346
- message: `${targetPath} already exists. Overwrite?`,
347
- initial: false
348
- });
497
+ const overwrite = await confirm(
498
+ `${targetPath} already exists. Overwrite?`,
499
+ false
500
+ );
349
501
  if (!overwrite) {
350
502
  spinner.warn(`Skipping ${targetPath}`);
351
503
  continue;
352
504
  }
353
505
  spinner.start();
354
506
  }
355
- await fs4.mkdir(path4.dirname(filePath), { recursive: true });
507
+ await fs6.mkdir(path6.dirname(filePath), { recursive: true });
356
508
  const content = transformImports(file.content, config);
357
- await fs4.writeFile(filePath, content, "utf-8");
509
+ await fs6.writeFile(filePath, content, "utf-8");
358
510
  }
359
511
  spinner.succeed(`${chalk.bold(name)} installed successfully!`);
360
512
  } catch (error) {
@@ -363,46 +515,367 @@ async function addComponent(name, config, options) {
363
515
  }
364
516
  }
365
517
 
366
- // src/commands/init.ts
518
+ // src/commands/remove.ts
367
519
  import chalk2 from "chalk";
368
520
  import ora2 from "ora";
369
521
  import prompts2 from "prompts";
370
- import path5 from "path";
371
- import fs5 from "fs/promises";
522
+ import path7 from "path";
523
+ import fs7 from "fs/promises";
524
+ async function remove(components, options) {
525
+ const cwd = process.cwd();
526
+ let config;
527
+ let pittayaConfig;
528
+ try {
529
+ const loaded = await loadProjectConfig(cwd);
530
+ config = loaded.config;
531
+ pittayaConfig = loaded.pittaya;
532
+ applyPittayaProjectConfig(pittayaConfig);
533
+ } catch (error) {
534
+ console.log(chalk2.red("\n\u274C components.json not found.\n"));
535
+ console.log(
536
+ chalk2.dim(`Run ${chalk2.bold("npx pittaya init")} first.
537
+ `)
538
+ );
539
+ return;
540
+ }
541
+ const spinner = ora2("Fetching installed components...").start();
542
+ let registry;
543
+ try {
544
+ registry = await fetchRegistry(config);
545
+ spinner.succeed("Registry loaded!");
546
+ } catch (error) {
547
+ spinner.fail("Error loading registry");
548
+ console.error(error);
549
+ return;
550
+ }
551
+ if (components.length === 0) {
552
+ const allComponents = registry.components || [];
553
+ const installedComponents = [];
554
+ for (const comp of allComponents) {
555
+ const slug = comp.slug || comp.name;
556
+ if (await isComponentInstalled(slug, config)) {
557
+ installedComponents.push({
558
+ title: `${slug}${comp.description ? ` - ${comp.description}` : ""}`,
559
+ value: slug
560
+ });
561
+ }
562
+ }
563
+ if (installedComponents.length === 0) {
564
+ console.log(chalk2.yellow("\n\u{1F4E6} No components installed to remove.\n"));
565
+ return;
566
+ }
567
+ const { selected } = await prompts2({
568
+ type: "multiselect",
569
+ name: "selected",
570
+ message: "Select components to remove:",
571
+ choices: installedComponents,
572
+ min: 1
573
+ });
574
+ if (!selected || selected.length === 0) {
575
+ console.log(chalk2.yellow("\n\u274C No components selected.\n"));
576
+ return;
577
+ }
578
+ components = selected;
579
+ }
580
+ if (!options.yes) {
581
+ const confirmed = await confirm(
582
+ `Are you sure you want to remove ${chalk2.bold(components.join(", "))}?`,
583
+ false
584
+ );
585
+ if (!confirmed) {
586
+ console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
587
+ return;
588
+ }
589
+ }
590
+ console.log(
591
+ chalk2.dim(`
592
+ Removing ${components.length} component(s)...
593
+ `)
594
+ );
595
+ for (const componentName of components) {
596
+ await removeComponent(componentName, config);
597
+ }
598
+ console.log(chalk2.green("\n\u2705 Components removed successfully!\n"));
599
+ }
600
+ async function removeComponent(name, config) {
601
+ const spinner = ora2(`Removing ${chalk2.bold(name)}...`).start();
602
+ try {
603
+ const component = await getRegistryComponent(name, config);
604
+ if (!component) {
605
+ spinner.fail(`Component "${name}" not found in registry.`);
606
+ return;
607
+ }
608
+ const removedFiles = [];
609
+ for (const file of component.files) {
610
+ const targetPath = await resolveTargetPath(file.name, component.type, config);
611
+ const filePath = path7.join(process.cwd(), targetPath);
612
+ const exists = await fs7.access(filePath).then(() => true).catch(() => false);
613
+ if (exists) {
614
+ await fs7.unlink(filePath);
615
+ removedFiles.push(filePath);
616
+ }
617
+ }
618
+ for (const filePath of removedFiles) {
619
+ await removeEmptyDirs(path7.dirname(filePath));
620
+ }
621
+ spinner.succeed(`${chalk2.bold(name)} removed successfully!`);
622
+ } catch (error) {
623
+ spinner.fail(`Error removing ${name}`);
624
+ console.error(error);
625
+ }
626
+ }
627
+ async function removeEmptyDirs(dirPath) {
628
+ try {
629
+ const files = await fs7.readdir(dirPath);
630
+ if (files.length === 0) {
631
+ await fs7.rmdir(dirPath);
632
+ await removeEmptyDirs(path7.dirname(dirPath));
633
+ }
634
+ } catch {
635
+ }
636
+ }
637
+
638
+ // src/commands/init.ts
639
+ import chalk3 from "chalk";
640
+ import ora3 from "ora";
641
+ import prompts3 from "prompts";
642
+ import path9 from "path";
643
+ import fs9 from "fs/promises";
372
644
  import { execa as execa2 } from "execa";
645
+
646
+ // src/utils/style-installer.ts
647
+ import fs8 from "fs/promises";
648
+ import path8 from "path";
649
+ import postcss from "postcss";
650
+ async function applyRegistryStyleToProject(styleComponent, config, options) {
651
+ const cssPath = config.tailwind?.css;
652
+ if (!cssPath) {
653
+ return;
654
+ }
655
+ const absoluteCssPath = path8.resolve(process.cwd(), cssPath);
656
+ const raw = await fs8.readFile(absoluteCssPath, "utf-8").catch(() => "");
657
+ const next = await transformTailwindV4Css(raw, styleComponent.cssVars ?? {}, {
658
+ overwriteCssVars: options?.overwriteCssVars ?? true
659
+ });
660
+ await fs8.mkdir(path8.dirname(absoluteCssPath), { recursive: true });
661
+ await fs8.writeFile(absoluteCssPath, next, "utf-8");
662
+ }
663
+ async function transformTailwindV4Css(input, cssVars, options) {
664
+ const result = await postcss([
665
+ ensureImportPlugin({ importPath: "tailwindcss" }),
666
+ ensureImportPlugin({ importPath: "tw-animate-css" }),
667
+ ensureCustomVariantDarkPlugin(),
668
+ upsertThemeAtRulePlugin(cssVars.theme ?? {}, {
669
+ overwrite: options.overwriteCssVars
670
+ }),
671
+ upsertRuleVarsPlugin(":root", cssVars.light ?? {}, {
672
+ overwrite: options.overwriteCssVars
673
+ }),
674
+ upsertRuleVarsPlugin(".dark", cssVars.dark ?? {}, {
675
+ overwrite: options.overwriteCssVars
676
+ }),
677
+ ensureBaseLayerPlugin()
678
+ ]).process(input, { from: void 0 });
679
+ return result.css.replace(/(\n\s*\n)+/g, "\n\n").trimStart();
680
+ }
681
+ function ensureImportPlugin({
682
+ importPath
683
+ }) {
684
+ return {
685
+ postcssPlugin: "pittaya-ensure-import",
686
+ Once(root) {
687
+ const exists = root.nodes.some(
688
+ (n) => n.type === "atrule" && n.name === "import" && n.params.includes(`"${importPath}"`)
689
+ );
690
+ if (exists) return;
691
+ const node = postcss.atRule({
692
+ name: "import",
693
+ params: `"${importPath}"`
694
+ });
695
+ root.prepend(node);
696
+ }
697
+ };
698
+ }
699
+ ensureImportPlugin.postcss = true;
700
+ function ensureCustomVariantDarkPlugin() {
701
+ return {
702
+ postcssPlugin: "pittaya-ensure-custom-variant-dark",
703
+ Once(root) {
704
+ const exists = root.nodes.some(
705
+ (n) => n.type === "atrule" && n.name === "custom-variant" && n.params.startsWith("dark ")
706
+ );
707
+ if (exists) return;
708
+ const node = postcss.atRule({
709
+ name: "custom-variant",
710
+ params: "dark (&:is(.dark *))"
711
+ });
712
+ root.append(node);
713
+ }
714
+ };
715
+ }
716
+ ensureCustomVariantDarkPlugin.postcss = true;
717
+ function upsertThemeAtRulePlugin(vars, options) {
718
+ return {
719
+ postcssPlugin: "pittaya-upsert-theme-atrule",
720
+ Once(root) {
721
+ if (Object.keys(vars).length === 0) return;
722
+ let themeNode = root.nodes.find(
723
+ (n) => n.type === "atrule" && n.name === "theme" && n.params === "inline"
724
+ );
725
+ if (!themeNode) {
726
+ themeNode = postcss.atRule({
727
+ name: "theme",
728
+ params: "inline"
729
+ });
730
+ root.append(themeNode);
731
+ }
732
+ for (const [k, v] of Object.entries(vars)) {
733
+ const prop = `--${k.replace(/^--/, "")}`;
734
+ const existing = themeNode.nodes?.find(
735
+ (n) => n.type === "decl" && n.prop === prop
736
+ );
737
+ if (existing) {
738
+ if (options.overwrite) {
739
+ existing.value = v;
740
+ }
741
+ } else {
742
+ themeNode.append(
743
+ postcss.decl({
744
+ prop,
745
+ value: v
746
+ })
747
+ );
748
+ }
749
+ }
750
+ }
751
+ };
752
+ }
753
+ upsertThemeAtRulePlugin.postcss = true;
754
+ function upsertRuleVarsPlugin(selector, vars, options) {
755
+ return {
756
+ postcssPlugin: `pittaya-upsert-vars-${selector}`,
757
+ Once(root) {
758
+ if (Object.keys(vars).length === 0) return;
759
+ let rule = root.nodes.find(
760
+ (n) => n.type === "rule" && n.selector === selector
761
+ );
762
+ if (!rule) {
763
+ rule = postcss.rule({ selector });
764
+ root.append(rule);
765
+ }
766
+ for (const [k, v] of Object.entries(vars)) {
767
+ const prop = `--${k.replace(/^--/, "")}`;
768
+ const existing = rule.nodes?.find(
769
+ (n) => n.type === "decl" && n.prop === prop
770
+ );
771
+ if (existing) {
772
+ if (options.overwrite) {
773
+ existing.value = v;
774
+ }
775
+ } else {
776
+ rule.append(
777
+ postcss.decl({
778
+ prop,
779
+ value: v
780
+ })
781
+ );
782
+ }
783
+ }
784
+ }
785
+ };
786
+ }
787
+ upsertRuleVarsPlugin.postcss = true;
788
+ function ensureBaseLayerPlugin() {
789
+ return {
790
+ postcssPlugin: "pittaya-ensure-base-layer",
791
+ Once(root) {
792
+ const hasLayerBase = root.nodes.some(
793
+ (n) => n.type === "atrule" && n.name === "layer" && n.params === "base"
794
+ );
795
+ if (hasLayerBase) return;
796
+ const baseLayer = postcss.atRule({
797
+ name: "layer",
798
+ params: "base"
799
+ });
800
+ baseLayer.append(
801
+ postcss.rule({
802
+ selector: "*",
803
+ nodes: [
804
+ postcss.atRule({
805
+ name: "apply",
806
+ params: "border-border outline-ring/50"
807
+ })
808
+ ]
809
+ })
810
+ );
811
+ baseLayer.append(
812
+ postcss.rule({
813
+ selector: "body",
814
+ nodes: [
815
+ postcss.atRule({
816
+ name: "apply",
817
+ params: "bg-background text-foreground"
818
+ })
819
+ ]
820
+ })
821
+ );
822
+ root.append(baseLayer);
823
+ }
824
+ };
825
+ }
826
+ ensureBaseLayerPlugin.postcss = true;
827
+
828
+ // src/commands/init.ts
373
829
  async function init(options) {
374
- console.log(chalk2.bold("\nWelcome to Pittaya UI!\n"));
830
+ const pittayaColorHex = "#f2556d";
831
+ console.log(
832
+ chalk3.bold(
833
+ `
834
+ Welcome to ${chalk3.hex(pittayaColorHex)("Pittaya")} UI!
835
+ `
836
+ )
837
+ );
375
838
  const cwd = process.cwd();
376
- const componentsJsonPath = path5.join(cwd, "components.json");
377
- const exists = await fs5.access(componentsJsonPath).then(() => true).catch(() => false);
839
+ const componentsJsonPath = path9.join(cwd, "components.json");
840
+ const pittayaJsonPath = path9.join(cwd, "pittaya.json");
841
+ const exists = await fs9.access(componentsJsonPath).then(() => true).catch(() => false);
842
+ const pittayaExists = await fs9.access(pittayaJsonPath).then(() => true).catch(() => false);
378
843
  if (exists && !options.yes) {
379
- const { overwrite } = await prompts2({
380
- type: "confirm",
381
- name: "overwrite",
382
- message: "components.json already exists. Do you want to overwrite it?",
383
- initial: false
384
- });
844
+ const overwrite = await confirm(
845
+ `${chalk3.underline("components.json")} already exists. Do you want to overwrite it?`,
846
+ false
847
+ );
385
848
  if (!overwrite) {
386
- console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
849
+ console.log(chalk3.yellow("\n\u274C Operation cancelled.\n"));
387
850
  return;
388
851
  }
389
852
  }
853
+ let shouldWritePittayaJson = true;
854
+ if (pittayaExists && !options.yes) {
855
+ const overwrite = await confirm(
856
+ `${chalk3.underline("pittaya.json")} already exists. Do you want to overwrite it?`,
857
+ false
858
+ );
859
+ if (!overwrite) {
860
+ shouldWritePittayaJson = false;
861
+ }
862
+ }
390
863
  const defaultPaths = await getDefaultPaths(cwd);
391
864
  const config = options.yes ? {
392
- style: "new-york",
865
+ style: "pittaya",
393
866
  tailwindCss: defaultPaths.globalsCss,
394
867
  rsc: true,
395
868
  componentsPath: defaultPaths.components,
396
869
  utilsPath: defaultPaths.utils
397
- } : await prompts2([
870
+ } : await prompts3([
398
871
  {
399
872
  type: "select",
400
873
  name: "style",
401
874
  message: "Which style would you like to use?",
402
875
  choices: [
876
+ { title: "Pittaya", value: "pittaya" },
403
877
  { title: "New York", value: "new-york" },
404
- { title: "Default", value: "default" },
405
- { title: "Recife", value: "recife" }
878
+ { title: "Default", value: "default" }
406
879
  ]
407
880
  },
408
881
  {
@@ -412,10 +885,14 @@ async function init(options) {
412
885
  initial: defaultPaths.globalsCss
413
886
  },
414
887
  {
415
- type: "confirm",
888
+ type: "select",
416
889
  name: "rsc",
417
890
  message: "Use React Server Components?",
418
- initial: true
891
+ choices: [
892
+ { title: "Yes", value: true },
893
+ { title: "No", value: false }
894
+ ],
895
+ initial: 0
419
896
  },
420
897
  {
421
898
  type: "text",
@@ -431,16 +908,16 @@ async function init(options) {
431
908
  }
432
909
  ]);
433
910
  if (!config.style && !options.yes) {
434
- console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
911
+ console.log(chalk3.yellow("\n\u274C Operation cancelled.\n"));
435
912
  return;
436
913
  }
437
914
  const componentsJson = {
438
915
  $schema: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry/schema.json",
439
- style: config.style || "new-york",
916
+ style: config.style || "pittaya",
440
917
  rsc: config.rsc ?? true,
441
918
  tsx: true,
442
919
  tailwind: {
443
- config: "tailwind.config.ts",
920
+ config: "",
444
921
  css: config.tailwindCss || "src/app/globals.css",
445
922
  baseColor: "neutral",
446
923
  cssVariables: true,
@@ -449,95 +926,120 @@ async function init(options) {
449
926
  aliases: {
450
927
  components: config.componentsPath || "@/components",
451
928
  utils: config.utilsPath || "@/lib/utils",
452
- ui: `${config.componentsPath || "@/components"}/pittaya/ui`,
929
+ ui: "@/components/ui",
453
930
  lib: "@/lib",
454
931
  hooks: "@/hooks"
455
932
  },
456
933
  iconLibrary: "lucide"
457
934
  };
458
- const spinner = ora2("Creating components.json...").start();
459
- await fs5.writeFile(
935
+ let pittayaJson = {
936
+ registry: {
937
+ url: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry",
938
+ preferLocal: false
939
+ },
940
+ theme: {
941
+ overwriteCssVars: true
942
+ },
943
+ install: {
944
+ autoInstallDeps: true
945
+ }
946
+ };
947
+ if (!shouldWritePittayaJson) {
948
+ try {
949
+ const raw = await fs9.readFile(pittayaJsonPath, "utf-8");
950
+ pittayaJson = JSON.parse(raw);
951
+ } catch {
952
+ shouldWritePittayaJson = true;
953
+ }
954
+ }
955
+ const spinner = ora3("Creating components.json...").start();
956
+ await fs9.writeFile(
460
957
  componentsJsonPath,
461
958
  JSON.stringify(componentsJson, null, 2)
462
959
  );
463
960
  spinner.succeed("components.json created successfully!");
464
- const packageManager = await detectPackageManager2();
465
- const depsSpinner = ora2("Installing base dependencies...").start();
961
+ if (shouldWritePittayaJson) {
962
+ const pittayaSpinner = ora3("Creating pittaya.json...").start();
963
+ await fs9.writeFile(pittayaJsonPath, JSON.stringify(pittayaJson, null, 2));
964
+ pittayaSpinner.succeed("pittaya.json created successfully!");
965
+ }
966
+ applyPittayaProjectConfig(pittayaJson);
967
+ const depsSpinner = ora3("Installing base dependencies...").start();
466
968
  try {
969
+ const packageManager = await detectPackageManager();
467
970
  await execa2(packageManager, [
468
971
  packageManager === "yarn" ? "add" : "install",
469
972
  "class-variance-authority",
470
973
  "clsx",
471
- "tailwind-merge"
974
+ "tailwind-merge",
975
+ "lucide-react",
976
+ "tw-animate-css"
472
977
  ]);
473
978
  depsSpinner.succeed("Dependencies installed!");
474
979
  } catch (error) {
475
980
  depsSpinner.fail("Error installing dependencies");
476
981
  console.error(error);
477
982
  }
478
- console.log(chalk2.green("\n\u2705 Pittaya UI configured successfully!\n"));
479
- console.log(chalk2.dim("Next steps:"));
983
+ try {
984
+ const styleItem = await getRegistryComponent("style", componentsJson);
985
+ await applyRegistryStyleToProject(styleItem, componentsJson, {
986
+ overwriteCssVars: pittayaJson.theme?.overwriteCssVars ?? true
987
+ });
988
+ } catch (error) {
989
+ console.error(error);
990
+ }
991
+ console.log(chalk3.green(`
992
+ \u2705 ${chalk3.hex(pittayaColorHex)("Pittaya")} UI configured successfully!
993
+ `));
994
+ console.log(chalk3.dim("Next steps:"));
480
995
  console.log(
481
- chalk2.dim(
482
- ` ${chalk2.bold("npx pittaya add button")} - Add a component`
996
+ chalk3.dim(
997
+ ` ${chalk3.bold("npx pittaya add button")} - Add a component`
483
998
  )
484
999
  );
485
1000
  console.log(
486
- chalk2.dim(
487
- ` ${chalk2.bold("npx pittaya add --all")} - Add all components
1001
+ chalk3.dim(
1002
+ ` ${chalk3.bold("npx pittaya add --all")} - Add all components
488
1003
  `
489
1004
  )
490
1005
  );
491
1006
  }
492
- async function detectPackageManager2() {
493
- try {
494
- await fs5.access("pnpm-lock.yaml");
495
- return "pnpm";
496
- } catch {
497
- }
498
- try {
499
- await fs5.access("yarn.lock");
500
- return "yarn";
501
- } catch {
502
- }
503
- return "npm";
504
- }
505
1007
 
506
1008
  // src/commands/credits.ts
507
- import chalk3 from "chalk";
1009
+ import chalk4 from "chalk";
508
1010
  async function credits() {
509
- console.log(chalk3.bold("\nPittaya UI - Creators\n"));
510
- console.log(chalk3.cyan(" \u2022 Marcos Bueno"));
511
- console.log(chalk3.cyan(" \u2022 Lucas Ribeiro"));
512
- console.log(chalk3.cyan(" \u2022 Jarbas Gouveia"));
513
- console.log(chalk3.dim("\n Thank you for using Pittaya UI! \u2764\uFE0F\n"));
1011
+ console.log(chalk4.bold("\nPittaya UI - Creators\n"));
1012
+ console.log(chalk4.cyan(" \u2022 Marcos Bueno"));
1013
+ console.log(chalk4.cyan(" \u2022 Lucas Ribeiro"));
1014
+ console.log(chalk4.cyan(" \u2022 Jarbas Gouveia"));
1015
+ console.log(chalk4.dim("\n Thank you for using Pittaya UI! \u2764\uFE0F\n"));
514
1016
  }
515
1017
 
516
1018
  // src/commands/diff.ts
517
- import chalk4 from "chalk";
518
- import ora3 from "ora";
519
- import prompts3 from "prompts";
520
- import path6 from "path";
521
- import fs6 from "fs/promises";
1019
+ import chalk5 from "chalk";
1020
+ import ora4 from "ora";
1021
+ import prompts4 from "prompts";
1022
+ import path10 from "path";
1023
+ import fs10 from "fs/promises";
522
1024
  async function diff(components, options) {
523
1025
  const cwd = process.cwd();
524
- const componentsJsonPath = path6.join(cwd, "components.json");
525
1026
  let config;
526
1027
  try {
527
- const configContent = await fs6.readFile(componentsJsonPath, "utf-8");
528
- config = JSON.parse(configContent);
1028
+ const loaded = await loadProjectConfig(cwd);
1029
+ config = loaded.config;
1030
+ applyPittayaProjectConfig(loaded.pittaya);
529
1031
  } catch (error) {
530
- console.log(chalk4.red("\n\u274C components.json not found.\n"));
1032
+ console.log(chalk5.red("\n\u274C components.json not found.\n"));
531
1033
  console.log(
532
- chalk4.dim(`Run ${chalk4.bold("npx pittaya init")} first.
1034
+ chalk5.dim(`Run ${chalk5.bold("npx pittaya init")} first.
533
1035
  `)
534
1036
  );
535
1037
  return;
536
1038
  }
537
- const spinner = ora3("Fetching registry...").start();
1039
+ const spinner = ora4("Fetching registry...").start();
538
1040
  let registry;
539
1041
  try {
540
- registry = await fetchRegistry();
1042
+ registry = await fetchRegistry(config);
541
1043
  spinner.succeed("Registry loaded!");
542
1044
  } catch (error) {
543
1045
  spinner.fail("Error loading registry");
@@ -554,7 +1056,7 @@ async function diff(components, options) {
554
1056
  }
555
1057
  }
556
1058
  if (componentsToCheck.length === 0) {
557
- console.log(chalk4.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
1059
+ console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
558
1060
  return;
559
1061
  }
560
1062
  } else if (components.length === 0) {
@@ -567,10 +1069,10 @@ async function diff(components, options) {
567
1069
  }
568
1070
  }
569
1071
  if (installedComponents.length === 0) {
570
- console.log(chalk4.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
1072
+ console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
571
1073
  return;
572
1074
  }
573
- const { selected } = await prompts3({
1075
+ const { selected } = await prompts4({
574
1076
  type: "multiselect",
575
1077
  name: "selected",
576
1078
  message: "Select components to check for updates:",
@@ -581,14 +1083,14 @@ async function diff(components, options) {
581
1083
  min: 1
582
1084
  });
583
1085
  if (!selected || selected.length === 0) {
584
- console.log(chalk4.yellow("\n\u274C No components selected.\n"));
1086
+ console.log(chalk5.yellow("\n\u274C No components selected.\n"));
585
1087
  return;
586
1088
  }
587
1089
  componentsToCheck = selected;
588
1090
  } else {
589
1091
  componentsToCheck = components;
590
1092
  }
591
- console.log(chalk4.dim(`
1093
+ console.log(chalk5.dim(`
592
1094
  Checking ${componentsToCheck.length} component(s)...
593
1095
  `));
594
1096
  const results = [];
@@ -602,23 +1104,23 @@ Checking ${componentsToCheck.length} component(s)...
602
1104
  }
603
1105
  async function checkComponentDiff(name, config) {
604
1106
  try {
605
- const component = await getRegistryComponent(name);
1107
+ const component = await getRegistryComponent(name, config);
606
1108
  if (!component) {
607
- console.log(chalk4.red(` \u274C Component "${name}" not found in registry.`));
1109
+ console.log(chalk5.red(` \u274C Component "${name}" not found in registry.`));
608
1110
  return null;
609
1111
  }
610
1112
  const isInstalled = await isComponentInstalled(name, config);
611
1113
  if (!isInstalled) {
612
- console.log(chalk4.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
1114
+ console.log(chalk5.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
613
1115
  return null;
614
1116
  }
615
1117
  const fileDiffs = [];
616
1118
  let hasChanges = false;
617
1119
  for (const file of component.files) {
618
1120
  const targetPath = await resolveTargetPath(file.name, component.type, config);
619
- const filePath = path6.join(process.cwd(), targetPath);
1121
+ const filePath = path10.join(process.cwd(), targetPath);
620
1122
  try {
621
- const localContent = await fs6.readFile(filePath, "utf-8");
1123
+ const localContent = await fs10.readFile(filePath, "utf-8");
622
1124
  const registryContent = transformImports(file.content, config);
623
1125
  const contentMatches = localContent.trim() === registryContent.trim();
624
1126
  fileDiffs.push({
@@ -647,7 +1149,7 @@ async function checkComponentDiff(name, config) {
647
1149
  isInstalled: true
648
1150
  };
649
1151
  } catch (error) {
650
- console.log(chalk4.red(` \u274C Error checking ${name}`));
1152
+ console.log(chalk5.red(` \u274C Error checking ${name}`));
651
1153
  console.error(error);
652
1154
  return null;
653
1155
  }
@@ -657,59 +1159,59 @@ function displayDiffResults(results) {
657
1159
  const componentsUpToDate = results.filter((r) => !r.hasChanges);
658
1160
  console.log();
659
1161
  if (componentsWithChanges.length > 0) {
660
- console.log(chalk4.yellow(`\u{1F4DD} Components with updates available (${componentsWithChanges.length}):
1162
+ console.log(chalk5.yellow(`\u{1F4DD} Components with updates available (${componentsWithChanges.length}):
661
1163
  `));
662
1164
  for (const result of componentsWithChanges) {
663
- console.log(chalk4.yellow(` \u2022 ${chalk4.bold(result.name)}`));
1165
+ console.log(chalk5.yellow(` \u2022 ${chalk5.bold(result.name)}`));
664
1166
  for (const file of result.files) {
665
1167
  if (file.hasChanges) {
666
1168
  if (file.isMissing) {
667
- console.log(chalk4.red(` \u2514\u2500 ${file.name} (missing locally)`));
1169
+ console.log(chalk5.red(` \u2514\u2500 ${file.name} (missing locally)`));
668
1170
  } else {
669
- console.log(chalk4.dim(` \u2514\u2500 ${file.name} (modified)`));
1171
+ console.log(chalk5.dim(` \u2514\u2500 ${file.name} (modified)`));
670
1172
  }
671
1173
  }
672
1174
  }
673
1175
  }
674
1176
  console.log();
675
- console.log(chalk4.dim(`Run ${chalk4.bold("npx pittaya update <component>")} to update.`));
1177
+ console.log(chalk5.dim(`Run ${chalk5.bold("npx pittaya update <component>")} to update.`));
676
1178
  }
677
1179
  if (componentsUpToDate.length > 0) {
678
- console.log(chalk4.green(`
1180
+ console.log(chalk5.green(`
679
1181
  \u2705 Components up to date (${componentsUpToDate.length}):
680
1182
  `));
681
1183
  for (const result of componentsUpToDate) {
682
- console.log(chalk4.dim(` \u2022 ${result.name}`));
1184
+ console.log(chalk5.dim(` \u2022 ${result.name}`));
683
1185
  }
684
1186
  }
685
1187
  console.log();
686
1188
  }
687
1189
 
688
1190
  // src/commands/update.ts
689
- import chalk5 from "chalk";
690
- import ora4 from "ora";
691
- import prompts4 from "prompts";
692
- import path7 from "path";
693
- import fs7 from "fs/promises";
1191
+ import chalk6 from "chalk";
1192
+ import ora5 from "ora";
1193
+ import prompts5 from "prompts";
1194
+ import path11 from "path";
1195
+ import fs11 from "fs/promises";
694
1196
  async function update(components, options) {
695
1197
  const cwd = process.cwd();
696
- const componentsJsonPath = path7.join(cwd, "components.json");
697
1198
  let config;
698
1199
  try {
699
- const configContent = await fs7.readFile(componentsJsonPath, "utf-8");
700
- config = JSON.parse(configContent);
1200
+ const loaded = await loadProjectConfig(cwd);
1201
+ config = loaded.config;
1202
+ applyPittayaProjectConfig(loaded.pittaya);
701
1203
  } catch (error) {
702
- console.log(chalk5.red("\n\u274C components.json not found.\n"));
1204
+ console.log(chalk6.red("\n\u274C components.json not found.\n"));
703
1205
  console.log(
704
- chalk5.dim(`Run ${chalk5.bold("npx pittaya init")} first.
1206
+ chalk6.dim(`Run ${chalk6.bold("npx pittaya init")} first.
705
1207
  `)
706
1208
  );
707
1209
  return;
708
1210
  }
709
- const spinner = ora4("Fetching registry...").start();
1211
+ const spinner = ora5("Fetching registry...").start();
710
1212
  let registry;
711
1213
  try {
712
- registry = await fetchRegistry();
1214
+ registry = await fetchRegistry(config);
713
1215
  spinner.succeed("Registry loaded!");
714
1216
  } catch (error) {
715
1217
  spinner.fail("Error loading registry");
@@ -726,18 +1228,16 @@ async function update(components, options) {
726
1228
  }
727
1229
  }
728
1230
  if (componentsToUpdate.length === 0) {
729
- console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
1231
+ console.log(chalk6.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
730
1232
  return;
731
1233
  }
732
1234
  if (!options.yes && !options.force) {
733
- const { confirm } = await prompts4({
734
- type: "confirm",
735
- name: "confirm",
736
- message: `Update ${componentsToUpdate.length} component(s)?`,
737
- initial: true
738
- });
739
- if (!confirm) {
740
- console.log(chalk5.yellow("\n\u274C Update cancelled.\n"));
1235
+ const shouldUpdate = await confirm(
1236
+ `Update ${componentsToUpdate.length} component(s)?`,
1237
+ true
1238
+ );
1239
+ if (!shouldUpdate) {
1240
+ console.log(chalk6.yellow("\n\u274C Update cancelled.\n"));
741
1241
  return;
742
1242
  }
743
1243
  }
@@ -751,10 +1251,10 @@ async function update(components, options) {
751
1251
  }
752
1252
  }
753
1253
  if (installedComponents.length === 0) {
754
- console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
1254
+ console.log(chalk6.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
755
1255
  return;
756
1256
  }
757
- const { selected } = await prompts4({
1257
+ const { selected } = await prompts5({
758
1258
  type: "multiselect",
759
1259
  name: "selected",
760
1260
  message: "Select components to update:",
@@ -765,14 +1265,14 @@ async function update(components, options) {
765
1265
  min: 1
766
1266
  });
767
1267
  if (!selected || selected.length === 0) {
768
- console.log(chalk5.yellow("\n\u274C No components selected.\n"));
1268
+ console.log(chalk6.yellow("\n\u274C No components selected.\n"));
769
1269
  return;
770
1270
  }
771
1271
  componentsToUpdate = selected;
772
1272
  } else {
773
1273
  componentsToUpdate = components;
774
1274
  }
775
- console.log(chalk5.dim(`
1275
+ console.log(chalk6.dim(`
776
1276
  Checking ${componentsToUpdate.length} component(s) for updates...
777
1277
  `));
778
1278
  const results = [];
@@ -785,9 +1285,9 @@ Checking ${componentsToUpdate.length} component(s) for updates...
785
1285
  async function hasComponentChanges(component, config) {
786
1286
  for (const file of component.files) {
787
1287
  const targetPath = await resolveTargetPath(file.name, component.type, config);
788
- const filePath = path7.join(process.cwd(), targetPath);
1288
+ const filePath = path11.join(process.cwd(), targetPath);
789
1289
  try {
790
- const localContent = await fs7.readFile(filePath, "utf-8");
1290
+ const localContent = await fs11.readFile(filePath, "utf-8");
791
1291
  const registryContent = transformImports(file.content, config);
792
1292
  if (localContent.trim() !== registryContent.trim()) {
793
1293
  return true;
@@ -800,45 +1300,40 @@ async function hasComponentChanges(component, config) {
800
1300
  }
801
1301
  async function updateComponent(name, config, options) {
802
1302
  try {
803
- const component = await getRegistryComponent(name);
1303
+ const component = await getRegistryComponent(name, config);
804
1304
  if (!component) {
805
- console.log(chalk5.red(` \u274C Component "${name}" not found in registry.`));
1305
+ console.log(chalk6.red(` \u274C Component "${name}" not found in registry.`));
806
1306
  return { name, updated: false, skipped: true, reason: "not found in registry" };
807
1307
  }
808
1308
  const isInstalled = await isComponentInstalled(name, config);
809
1309
  if (!isInstalled) {
810
- console.log(chalk5.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
1310
+ console.log(chalk6.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
811
1311
  return { name, updated: false, skipped: true, reason: "not installed" };
812
1312
  }
813
1313
  const hasChanges = await hasComponentChanges(component, config);
814
1314
  if (!hasChanges && !options.force) {
815
- console.log(chalk5.dim(` \u2713 ${name} is already up to date`));
1315
+ console.log(chalk6.dim(` \u2713 ${name} is already up to date`));
816
1316
  return { name, updated: false, skipped: true, reason: "already up to date" };
817
1317
  }
818
1318
  if (!options.yes && !options.force) {
819
- const { confirm } = await prompts4({
820
- type: "confirm",
821
- name: "confirm",
822
- message: `Update ${chalk5.bold(name)}?`,
823
- initial: true
824
- });
825
- if (!confirm) {
826
- console.log(chalk5.yellow(` \u23ED\uFE0F Skipped ${name}`));
1319
+ const shouldUpdate = await confirm(`Update ${chalk6.bold(name)}?`, true);
1320
+ if (!shouldUpdate) {
1321
+ console.log(chalk6.yellow(` \u23ED\uFE0F Skipped ${name}`));
827
1322
  return { name, updated: false, skipped: true, reason: "user cancelled" };
828
1323
  }
829
1324
  }
830
- const spinner = ora4(`Updating ${chalk5.bold(name)}...`).start();
1325
+ const spinner = ora5(`Updating ${chalk6.bold(name)}...`).start();
831
1326
  for (const file of component.files) {
832
1327
  const targetPath = await resolveTargetPath(file.name, component.type, config);
833
- const filePath = path7.join(process.cwd(), targetPath);
834
- await fs7.mkdir(path7.dirname(filePath), { recursive: true });
1328
+ const filePath = path11.join(process.cwd(), targetPath);
1329
+ await fs11.mkdir(path11.dirname(filePath), { recursive: true });
835
1330
  const content = transformImports(file.content, config);
836
- await fs7.writeFile(filePath, content, "utf-8");
1331
+ await fs11.writeFile(filePath, content, "utf-8");
837
1332
  }
838
- spinner.succeed(`${chalk5.bold(name)} updated successfully!`);
1333
+ spinner.succeed(`${chalk6.bold(name)} updated successfully!`);
839
1334
  return { name, updated: true, skipped: false };
840
1335
  } catch (error) {
841
- console.log(chalk5.red(` \u274C Error updating ${name}`));
1336
+ console.log(chalk6.red(` \u274C Error updating ${name}`));
842
1337
  console.error(error);
843
1338
  return { name, updated: false, skipped: true, reason: "error" };
844
1339
  }
@@ -848,48 +1343,46 @@ function displayUpdateResults(results) {
848
1343
  const skipped = results.filter((r) => r.skipped);
849
1344
  console.log();
850
1345
  if (updated.length > 0) {
851
- console.log(chalk5.green(`\u2705 Updated ${updated.length} component(s):
1346
+ console.log(chalk6.green(`\u2705 Updated ${updated.length} component(s):
852
1347
  `));
853
1348
  for (const result of updated) {
854
- console.log(chalk5.dim(` \u2022 ${result.name}`));
1349
+ console.log(chalk6.dim(` \u2022 ${result.name}`));
855
1350
  }
856
1351
  }
857
1352
  if (skipped.length > 0) {
858
- console.log(chalk5.yellow(`
1353
+ console.log(chalk6.yellow(`
859
1354
  \u23ED\uFE0F Skipped ${skipped.length} component(s):
860
1355
  `));
861
1356
  for (const result of skipped) {
862
1357
  const reason = result.reason ? ` (${result.reason})` : "";
863
- console.log(chalk5.dim(` \u2022 ${result.name}${reason}`));
1358
+ console.log(chalk6.dim(` \u2022 ${result.name}${reason}`));
864
1359
  }
865
1360
  }
866
1361
  console.log();
867
1362
  }
868
1363
 
869
1364
  // src/commands/list.ts
870
- import chalk6 from "chalk";
871
- import ora5 from "ora";
872
- import path8 from "path";
873
- import fs8 from "fs/promises";
1365
+ import chalk7 from "chalk";
1366
+ import ora6 from "ora";
874
1367
  async function list(options) {
875
1368
  const cwd = process.cwd();
876
- const componentsJsonPath = path8.join(cwd, "components.json");
877
1369
  let config;
878
1370
  try {
879
- const configContent = await fs8.readFile(componentsJsonPath, "utf-8");
880
- config = JSON.parse(configContent);
1371
+ const loaded = await loadProjectConfig(cwd);
1372
+ config = loaded.config;
1373
+ applyPittayaProjectConfig(loaded.pittaya);
881
1374
  } catch (error) {
882
- console.log(chalk6.red("\n\u274C components.json not found.\n"));
1375
+ console.log(chalk7.red("\n\u274C components.json not found.\n"));
883
1376
  console.log(
884
- chalk6.dim(`Run ${chalk6.bold("npx pittaya init")} first.
1377
+ chalk7.dim(`Run ${chalk7.bold("npx pittaya init")} first.
885
1378
  `)
886
1379
  );
887
1380
  return;
888
1381
  }
889
- const spinner = ora5("Fetching components...").start();
1382
+ const spinner = ora6("Fetching components...").start();
890
1383
  let registry;
891
1384
  try {
892
- registry = await fetchRegistry();
1385
+ registry = await fetchRegistry(config);
893
1386
  spinner.succeed("Components loaded!");
894
1387
  } catch (error) {
895
1388
  spinner.fail("Error loading registry");
@@ -899,9 +1392,10 @@ async function list(options) {
899
1392
  const allComponents = registry.components || [];
900
1393
  const componentsWithStatus = await Promise.all(
901
1394
  allComponents.map(async (comp) => {
902
- const installed = await isComponentInstalled(comp.slug, config);
1395
+ const slug = comp.slug || comp.name;
1396
+ const installed = await isComponentInstalled(slug, config);
903
1397
  return {
904
- ...comp,
1398
+ ...comp.slug ? comp : { ...comp, slug },
905
1399
  installed
906
1400
  };
907
1401
  })
@@ -921,13 +1415,13 @@ async function list(options) {
921
1415
  function displayComponents(components, options) {
922
1416
  if (components.length === 0) {
923
1417
  if (options.installed) {
924
- console.log(chalk6.yellow("\n\u{1F4E6} No components installed yet.\n"));
925
- console.log(chalk6.dim(`Run ${chalk6.bold("npx pittaya add")} to install components.
1418
+ console.log(chalk7.yellow("\n\u{1F4E6} No components installed yet.\n"));
1419
+ console.log(chalk7.dim(`Run ${chalk7.bold("npx pittaya add")} to install components.
926
1420
  `));
927
1421
  } else if (options.available) {
928
- console.log(chalk6.yellow("\n\u2728 All components are already installed!\n"));
1422
+ console.log(chalk7.yellow("\n\u2728 All components are already installed!\n"));
929
1423
  } else {
930
- console.log(chalk6.yellow("\n\u26A0\uFE0F No components found in registry.\n"));
1424
+ console.log(chalk7.yellow("\n\u26A0\uFE0F No components found in registry.\n"));
931
1425
  }
932
1426
  return;
933
1427
  }
@@ -941,20 +1435,20 @@ function displayComponents(components, options) {
941
1435
  }, {});
942
1436
  console.log("\n");
943
1437
  if (options.installed) {
944
- console.log(chalk6.bold.green("\u{1F4E6} Installed Components\n"));
1438
+ console.log(chalk7.bold.green("\u{1F4E6} Installed Components\n"));
945
1439
  } else if (options.available) {
946
- console.log(chalk6.bold.blue("\u2728 Available Components\n"));
1440
+ console.log(chalk7.bold.blue("\u2728 Available Components\n"));
947
1441
  } else {
948
- console.log(chalk6.bold("\u{1F4CB} All Components\n"));
1442
+ console.log(chalk7.bold("\u{1F4CB} All Components\n"));
949
1443
  }
950
1444
  Object.entries(categorized).sort().forEach(([category, comps]) => {
951
- console.log(chalk6.bold.cyan(`${category}:`));
1445
+ console.log(chalk7.bold.cyan(`${category}:`));
952
1446
  comps.forEach((comp) => {
953
- const status = comp.installed ? chalk6.green("\u2713") : chalk6.dim("\u25CB");
954
- const name = comp.installed ? chalk6.bold(comp.slug) : chalk6.dim(comp.slug);
955
- const description = comp.description ? chalk6.dim(` - ${comp.description}`) : "";
956
- const deps = comp.dependencies && comp.dependencies.length > 0 ? chalk6.dim.yellow(` [${comp.dependencies.length} deps]`) : "";
957
- const internalDeps = comp.internalDependencies && comp.internalDependencies.length > 0 ? chalk6.dim.blue(` [requires: ${comp.internalDependencies.join(", ")}]`) : "";
1447
+ const status = comp.installed ? chalk7.green("\u2713") : chalk7.dim("\u25CB");
1448
+ const name = comp.installed ? chalk7.bold(comp.slug) : chalk7.dim(comp.slug);
1449
+ const description = comp.description ? chalk7.dim(` - ${comp.description}`) : "";
1450
+ const deps = comp.dependencies && comp.dependencies.length > 0 ? chalk7.dim.yellow(` [${comp.dependencies.length} deps]`) : "";
1451
+ const internalDeps = comp.internalDependencies && comp.internalDependencies.length > 0 ? chalk7.dim.blue(` [requires: ${comp.internalDependencies.join(", ")}]`) : "";
958
1452
  console.log(` ${status} ${name}${description}${deps}${internalDeps}`);
959
1453
  });
960
1454
  console.log();
@@ -962,117 +1456,142 @@ function displayComponents(components, options) {
962
1456
  const installedCount = components.filter((c) => c.installed).length;
963
1457
  const totalCount = components.length;
964
1458
  if (!options.installed && !options.available) {
965
- console.log(chalk6.dim(`Total: ${totalCount} components (${installedCount} installed, ${totalCount - installedCount} available)
1459
+ console.log(chalk7.dim(`Total: ${totalCount} components (${installedCount} installed, ${totalCount - installedCount} available)
966
1460
  `));
967
1461
  } else {
968
- console.log(chalk6.dim(`Total: ${totalCount} components
1462
+ console.log(chalk7.dim(`Total: ${totalCount} components
969
1463
  `));
970
1464
  }
971
1465
  }
972
1466
 
973
1467
  // src/commands/debug.ts
974
- import chalk7 from "chalk";
975
- import path9 from "path";
976
- import fs9 from "fs/promises";
1468
+ import chalk8 from "chalk";
1469
+ import path12 from "path";
1470
+ import fs12 from "fs/promises";
977
1471
  async function debug(options) {
978
1472
  const cwd = process.cwd();
979
- const componentsJsonPath = path9.join(cwd, "components.json");
980
- console.log(chalk7.bold("\n\u{1F50D} Pittaya UI Debug Information\n"));
981
- console.log(chalk7.dim(`Working directory: ${cwd}
1473
+ console.log(chalk8.bold("\n\u{1F50D} Pittaya UI Debug Information\n"));
1474
+ console.log(chalk8.dim(`Working directory: ${cwd}
982
1475
  `));
983
1476
  let config;
984
1477
  try {
985
- const configContent = await fs9.readFile(componentsJsonPath, "utf-8");
986
- config = JSON.parse(configContent);
987
- console.log(chalk7.green("\u2705 components.json found"));
988
- console.log(chalk7.dim(` Path: ${componentsJsonPath}`));
1478
+ const loaded = await loadProjectConfig(cwd);
1479
+ config = loaded.config;
1480
+ applyPittayaProjectConfig(loaded.pittaya);
1481
+ console.log(chalk8.green("\u2705 components.json found"));
1482
+ console.log(chalk8.dim(` Path: ${path12.join(cwd, "components.json")}`));
989
1483
  } catch (error) {
990
- console.log(chalk7.red("\u274C components.json not found\n"));
1484
+ console.log(chalk8.red("\u274C components.json not found\n"));
991
1485
  return;
992
1486
  }
993
1487
  const usesSrc = await hasSrcDirectory(cwd);
994
- console.log(chalk7.green(`\u2705 Project structure: ${usesSrc ? "src/" : "root"}`));
995
- console.log(chalk7.bold("\n\u{1F4CB} Configured Aliases:"));
996
- console.log(chalk7.dim(` components: ${config.aliases.components}`));
997
- console.log(chalk7.dim(` utils: ${config.aliases.utils}`));
998
- console.log(chalk7.dim(` ui: ${config.aliases.ui}`));
1488
+ console.log(chalk8.green(`\u2705 Project structure: ${usesSrc ? "src/" : "root"}`));
1489
+ console.log(chalk8.bold("\n\u{1F4CB} Configured Aliases:"));
1490
+ console.log(chalk8.dim(` components: ${config.aliases.components}`));
1491
+ console.log(chalk8.dim(` utils: ${config.aliases.utils}`));
1492
+ console.log(chalk8.dim(` ui: ${config.aliases.ui}`));
999
1493
  const resolvedUi = await resolveAliasPath(config.aliases.ui, cwd);
1000
1494
  const resolvedLib = await resolveAliasPath(config.aliases.lib || "@/lib", cwd);
1001
- console.log(chalk7.bold("\n\u{1F4C2} Resolved Paths:"));
1002
- console.log(chalk7.dim(` UI components: ${resolvedUi}`));
1003
- console.log(chalk7.dim(` Libraries: ${resolvedLib}`));
1495
+ console.log(chalk8.bold("\n\u{1F4C2} Resolved Paths:"));
1496
+ console.log(chalk8.dim(` UI components: ${resolvedUi}`));
1497
+ console.log(chalk8.dim(` Libraries: ${resolvedLib}`));
1004
1498
  if (options.component) {
1005
- console.log(chalk7.bold(`
1499
+ console.log(chalk8.bold(`
1006
1500
  \u{1F50D} Debugging component: ${options.component}
1007
1501
  `));
1008
1502
  try {
1009
- const component = await getRegistryComponent(options.component);
1503
+ const component = await getRegistryComponent(options.component, config);
1010
1504
  if (!component) {
1011
- console.log(chalk7.red(`\u274C Component not found in registry
1505
+ console.log(chalk8.red(`\u274C Component not found in registry
1012
1506
  `));
1013
1507
  return;
1014
1508
  }
1015
- console.log(chalk7.green(`\u2705 Component found in registry`));
1016
- console.log(chalk7.dim(` Type: ${component.type}`));
1017
- console.log(chalk7.dim(` Files: ${component.files.length}`));
1018
- console.log(chalk7.bold("\n\u{1F4C1} Expected Files:"));
1509
+ console.log(chalk8.green(`\u2705 Component found in registry`));
1510
+ console.log(chalk8.dim(` Type: ${component.type}`));
1511
+ console.log(chalk8.dim(` Files: ${component.files.length}`));
1512
+ console.log(chalk8.bold("\n\u{1F4C1} Expected Files:"));
1019
1513
  for (const file of component.files) {
1020
1514
  const targetPath = await resolveTargetPath(file.name, component.type, config);
1021
- const fullPath = path9.join(cwd, targetPath);
1022
- const exists = await fs9.access(fullPath).then(() => true).catch(() => false);
1023
- const statusIcon = exists ? chalk7.green("\u2705") : chalk7.red("\u274C");
1024
- const statusText = exists ? chalk7.green("EXISTS") : chalk7.red("NOT FOUND");
1515
+ const fullPath = path12.join(cwd, targetPath);
1516
+ const exists = await fs12.access(fullPath).then(() => true).catch(() => false);
1517
+ const statusIcon = exists ? chalk8.green("\u2705") : chalk8.red("\u274C");
1518
+ const statusText = exists ? chalk8.green("EXISTS") : chalk8.red("NOT FOUND");
1025
1519
  console.log(` ${statusIcon} ${file.name}`);
1026
- console.log(chalk7.dim(` Expected: ${fullPath}`));
1027
- console.log(chalk7.dim(` Status: ${statusText}`));
1520
+ console.log(chalk8.dim(` Expected: ${fullPath}`));
1521
+ console.log(chalk8.dim(` Status: ${statusText}`));
1028
1522
  if (!exists) {
1029
- const dir = path9.dirname(fullPath);
1523
+ const dir = path12.dirname(fullPath);
1030
1524
  try {
1031
- const dirExists = await fs9.access(dir).then(() => true).catch(() => false);
1525
+ const dirExists = await fs12.access(dir).then(() => true).catch(() => false);
1032
1526
  if (dirExists) {
1033
- const filesInDir = await fs9.readdir(dir);
1034
- const baseName = path9.basename(file.name, path9.extname(file.name));
1527
+ const filesInDir = await fs12.readdir(dir);
1528
+ const baseName = path12.basename(file.name, path12.extname(file.name));
1035
1529
  const similarFiles = filesInDir.filter(
1036
1530
  (f) => f.includes(baseName) || f.toLowerCase().includes(baseName.toLowerCase())
1037
1531
  );
1038
1532
  if (similarFiles.length > 0) {
1039
- console.log(chalk7.yellow(` \u{1F4A1} Similar files found in directory:`));
1533
+ console.log(chalk8.yellow(` \u{1F4A1} Similar files found in directory:`));
1040
1534
  similarFiles.forEach((f) => {
1041
- console.log(chalk7.dim(` - ${f}`));
1535
+ console.log(chalk8.dim(` - ${f}`));
1042
1536
  });
1043
1537
  }
1044
1538
  } else {
1045
- console.log(chalk7.red(` \u26A0\uFE0F Directory doesn't exist: ${dir}`));
1539
+ console.log(chalk8.red(` \u26A0\uFE0F Directory doesn't exist: ${dir}`));
1046
1540
  }
1047
1541
  } catch (err) {
1048
1542
  }
1049
1543
  }
1050
1544
  }
1051
1545
  const isInstalled = await isComponentInstalled(options.component, config);
1052
- console.log(chalk7.bold(`
1546
+ console.log(chalk8.bold(`
1053
1547
  \u{1F4CA} Installation Status:`));
1054
1548
  if (isInstalled) {
1055
- console.log(chalk7.green(` \u2705 Component is detected as INSTALLED`));
1549
+ console.log(chalk8.green(` \u2705 Component is detected as INSTALLED`));
1056
1550
  } else {
1057
- console.log(chalk7.red(` \u274C Component is detected as NOT INSTALLED`));
1058
- console.log(chalk7.yellow(` \u{1F4A1} All files must exist for component to be considered installed`));
1551
+ console.log(chalk8.red(` \u274C Component is detected as NOT INSTALLED`));
1552
+ console.log(chalk8.yellow(` \u{1F4A1} All files must exist for component to be considered installed`));
1059
1553
  }
1060
1554
  } catch (error) {
1061
- console.log(chalk7.red(`
1555
+ console.log(chalk8.red(`
1062
1556
  \u274C Error debugging component:`));
1063
1557
  console.error(error);
1064
1558
  }
1065
1559
  } else {
1066
- console.log(chalk7.yellow("\n\u{1F4A1} To debug a specific component, use:"));
1067
- console.log(chalk7.dim(" npx pittaya debug --component <name>\n"));
1560
+ console.log(chalk8.yellow("\n\u{1F4A1} To debug a specific component, use:"));
1561
+ console.log(chalk8.dim(" npx pittaya debug --component <name>\n"));
1562
+ }
1563
+ }
1564
+
1565
+ // src/utils/banner.ts
1566
+ import chalk9 from "chalk";
1567
+ import CFonts from "cfonts";
1568
+ import gradient from "gradient-string";
1569
+ async function showBanner() {
1570
+ try {
1571
+ const textOutput = CFonts.render("Pittaya UI", {
1572
+ font: "block",
1573
+ align: "left",
1574
+ colors: ["system"],
1575
+ background: "transparent",
1576
+ letterSpacing: 1,
1577
+ lineHeight: 1,
1578
+ space: false
1579
+ });
1580
+ const pittayaGradient = gradient(["#fda4af", "#fb7185", "#9f1239"]);
1581
+ process.stdout.write("\n" + pittayaGradient.multiline(textOutput?.string || "Pittaya UI"));
1582
+ console.log(chalk9.gray(`
1583
+ ${"\u2500".repeat(20)} Pittaya UI - Components that scale with your ideas ${"\u2500".repeat(20)}
1584
+ `));
1585
+ } catch (error) {
1586
+ CFonts.say("Pittaya UI", { font: "block", colors: ["#fb7185"] });
1068
1587
  }
1069
1588
  }
1070
1589
 
1071
1590
  // src/index.ts
1072
1591
  import { readFileSync } from "fs";
1073
- import { fileURLToPath } from "url";
1592
+ import { fileURLToPath as fileURLToPath2 } from "url";
1074
1593
  import { dirname, join } from "path";
1075
- var __filename = fileURLToPath(import.meta.url);
1594
+ var __filename = fileURLToPath2(import.meta.url);
1076
1595
  var __dirname = dirname(__filename);
1077
1596
  var packageJson = JSON.parse(
1078
1597
  readFileSync(join(__dirname, "../package.json"), "utf-8")
@@ -1081,10 +1600,22 @@ var program = new Command();
1081
1600
  program.name("pittaya").description("Add Pittaya UI components to your project").version(packageJson.version);
1082
1601
  program.command("init").description("Initialize Pittaya UI in your project").option("-y, --yes", "Skip confirmations and use default values").action(init);
1083
1602
  program.command("add").description("Add a component to your project").argument("[components...]", "Component names to add").option("-y, --yes", "Skip confirmations and overwrite existing files").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("--add-missing-deps", "Automatically install missing dependencies").action(add);
1603
+ program.command("remove").description("Remove a component from your project").argument("[components...]", "Component names to remove").option("-y, --yes", "Skip confirmation prompts").action(remove);
1084
1604
  program.command("diff").description("Check for component updates").argument("[components...]", "Component names to check (leave empty for interactive mode)").option("-a, --all", "Check all installed components").action(diff);
1085
1605
  program.command("update").description("Update components to latest version").argument("[components...]", "Component names to update (leave empty for interactive mode)").option("-a, --all", "Update all installed components").option("-y, --yes", "Skip confirmation prompts").option("-f, --force", "Force update even if no changes detected").action(update);
1086
1606
  program.command("list").description("List available and installed components").option("--installed", "Show only installed components").option("--available", "Show only available components").option("--json", "Output in JSON format").action(list);
1087
1607
  program.command("credits").description("Show Pittaya UI creators").action(credits);
1608
+ program.command("banner").description("Show the amazing Pittaya banner").action(showBanner);
1088
1609
  program.command("debug").description("Debug component installation issues").option("-c, --component <name>", "Component name to debug").action(debug);
1089
- program.parse();
1610
+ async function run() {
1611
+ const args = process.argv.slice(2);
1612
+ const isHelpOrVersion = args.some((arg) => ["--help", "-h", "--version", "-v"].includes(arg));
1613
+ const isInitCommand = args.length > 0 && args[0] === "init";
1614
+ const isCreditsCommand = args.length > 0 && args[0] === "credits";
1615
+ if (isInitCommand || isCreditsCommand) {
1616
+ await showBanner();
1617
+ }
1618
+ program.parse();
1619
+ }
1620
+ run();
1090
1621
  //# sourceMappingURL=index.js.map