@frontic/ui 0.0.7 → 0.3.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.
@@ -7,16 +7,35 @@ import { Command } from "commander";
7
7
  import chalk from "chalk";
8
8
  import ora from "ora";
9
9
  import prompts from "prompts";
10
+ import { join as join2 } from "path";
10
11
 
11
12
  // src/utils/spawn-shadcn.ts
12
13
  import { execa } from "execa";
13
14
  async function spawnShadcn(args, options = {}) {
14
- const { silent = false } = options;
15
+ const { silent = false, filterOutput = false } = options;
15
16
  try {
16
- await execa("npx", ["shadcn-vue@latest", ...args], {
17
- stdio: silent ? "pipe" : "inherit",
18
- shell: true
19
- });
17
+ if (filterOutput) {
18
+ const proc = execa("npx", ["shadcn-vue@latest", ...args], {
19
+ stdio: ["inherit", "pipe", "pipe"],
20
+ shell: true
21
+ });
22
+ proc.stdout?.on("data", (data) => {
23
+ process.stdout.write(
24
+ data.toString().replace(/shadcn-vue/gi, "frontic-ui")
25
+ );
26
+ });
27
+ proc.stderr?.on("data", (data) => {
28
+ process.stderr.write(
29
+ data.toString().replace(/shadcn-vue/gi, "frontic-ui")
30
+ );
31
+ });
32
+ await proc;
33
+ } else {
34
+ await execa("npx", ["shadcn-vue@latest", ...args], {
35
+ stdio: silent ? "pipe" : "inherit",
36
+ shell: true
37
+ });
38
+ }
20
39
  } catch (error) {
21
40
  if (!silent) {
22
41
  throw error;
@@ -32,6 +51,14 @@ import { join } from "path";
32
51
  var FRONTIC_REGISTRY_URL = process.env.FRONTIC_REGISTRY_LOCAL === "1" ? "http://localhost:3333/r/{name}.json" : "https://registry.frontic.io/r/{name}.json";
33
52
  var CONFIG_FILE = "components.json";
34
53
  var DEFAULT_BRAND_COLOR = "oklch(58% 0.25 265)";
54
+ var DEFAULT_RADIUS = "0.5rem";
55
+ var RADIUS_OPTIONS = {
56
+ none: "0",
57
+ small: "0.3rem",
58
+ medium: "0.5rem",
59
+ large: "0.75rem",
60
+ full: "1rem"
61
+ };
35
62
 
36
63
  // src/utils/config.ts
37
64
  async function configExists() {
@@ -176,9 +203,51 @@ function getForegroundColor(oklchOrHex) {
176
203
  return lightness > 0.6 ? "oklch(20% 0 0)" : "oklch(100% 0 0)";
177
204
  }
178
205
 
206
+ // src/utils/css.ts
207
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
208
+ function upsertCssVar(content, varName, value) {
209
+ const varRegex = new RegExp(`(${varName}\\s*:\\s*)([^;]+)(;)`, "g");
210
+ if (varRegex.test(content)) {
211
+ return content.replace(varRegex, `$1${value}$3`);
212
+ } else {
213
+ return content.trimEnd() + `
214
+ ${varName}: ${value};`;
215
+ }
216
+ }
217
+ async function injectCssVars(cssPath, vars) {
218
+ const content = await readFile2(cssPath, "utf-8");
219
+ const rootRegex = /:root\s*\{([^}]*)\}/;
220
+ const match = content.match(rootRegex);
221
+ if (match && match[1] !== void 0) {
222
+ let rootContent = match[1];
223
+ rootContent = upsertCssVar(rootContent, "--brand", vars.brand);
224
+ rootContent = upsertCssVar(
225
+ rootContent,
226
+ "--brand-foreground",
227
+ vars.brandForeground
228
+ );
229
+ rootContent = upsertCssVar(rootContent, "--radius", vars.radius);
230
+ const newContent = content.replace(rootRegex, `:root {${rootContent}
231
+ }`);
232
+ await writeFile2(cssPath, newContent);
233
+ } else {
234
+ const rootBlock = `:root {
235
+ --brand: ${vars.brand};
236
+ --brand-foreground: ${vars.brandForeground};
237
+ --radius: ${vars.radius};
238
+ }
239
+
240
+ `;
241
+ await writeFile2(cssPath, rootBlock + content);
242
+ }
243
+ }
244
+
179
245
  // src/commands/init.ts
180
246
  function registerInitCommand(program2) {
181
- program2.command("init").description("Initialize Frontic UI in your Vue project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").option("-f, --force", "Force overwrite of existing configuration").option("-b, --brand <color>", "Brand color in hex format (e.g., #6366f1)").action(async (options) => {
247
+ program2.command("init").description("Initialize Frontic UI in your Nuxt project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").option("-f, --force", "Force overwrite of existing configuration").option("-b, --brand <color>", "Brand color in hex format (e.g., #6366f1)").option(
248
+ "-r, --radius <option>",
249
+ "Border radius (none, small, medium, large, full)"
250
+ ).action(async (options) => {
182
251
  await init(options);
183
252
  });
184
253
  }
@@ -188,55 +257,117 @@ async function init(options) {
188
257
  console.log(chalk.dim("Initializing your project..."));
189
258
  console.log();
190
259
  const hasConfig = await configExists();
260
+ let brandColor = DEFAULT_BRAND_COLOR;
261
+ let radiusValue = DEFAULT_RADIUS;
191
262
  if (!hasConfig) {
192
- console.log(chalk.blue("Running shadcn-vue init..."));
263
+ if (options.brand) {
264
+ if (isValidHex(options.brand)) {
265
+ brandColor = hexToOklch(options.brand);
266
+ console.log(
267
+ chalk.dim(`Using brand color: ${options.brand} \u2192 ${brandColor}`)
268
+ );
269
+ } else {
270
+ console.log(
271
+ chalk.yellow(`Invalid hex color: ${options.brand}, using default`)
272
+ );
273
+ }
274
+ }
275
+ if (options.radius) {
276
+ const radiusKey = options.radius.toLowerCase();
277
+ if (radiusKey in RADIUS_OPTIONS) {
278
+ radiusValue = RADIUS_OPTIONS[radiusKey];
279
+ console.log(chalk.dim(`Using border radius: ${options.radius}`));
280
+ } else {
281
+ console.log(
282
+ chalk.yellow(
283
+ `Invalid radius option: ${options.radius}, using default (medium)`
284
+ )
285
+ );
286
+ }
287
+ }
288
+ if (!options.yes && !options.defaults) {
289
+ const response = await prompts([
290
+ {
291
+ type: options.brand ? null : "text",
292
+ name: "brand",
293
+ message: "Brand color (hex, e.g., #6366f1)",
294
+ initial: "#6366f1",
295
+ validate: (value) => {
296
+ if (!value) return true;
297
+ return isValidHex(value) || "Please enter a valid hex color (e.g., #6366f1)";
298
+ }
299
+ },
300
+ {
301
+ type: options.radius ? null : "select",
302
+ name: "radius",
303
+ message: "Border radius",
304
+ choices: [
305
+ { title: "None", value: "none" },
306
+ { title: "Small", value: "small" },
307
+ { title: "Medium (recommended)", value: "medium" },
308
+ { title: "Large", value: "large" },
309
+ { title: "Full", value: "full" }
310
+ ],
311
+ initial: 2
312
+ }
313
+ ]);
314
+ if (response.brand && isValidHex(response.brand)) {
315
+ brandColor = hexToOklch(response.brand);
316
+ console.log(chalk.dim(`Converted: ${response.brand} \u2192 ${brandColor}`));
317
+ }
318
+ if (response.radius) {
319
+ radiusValue = RADIUS_OPTIONS[response.radius];
320
+ }
321
+ }
322
+ console.log();
323
+ console.log(chalk.blue("Setting up your project..."));
193
324
  console.log();
194
325
  const args = ["init"];
195
326
  if (options.yes) args.push("--yes");
196
327
  if (options.defaults) args.push("--defaults");
197
328
  if (options.force) args.push("--force");
198
329
  try {
199
- await spawnShadcn(args);
330
+ await spawnShadcn(args, { filterOutput: true });
200
331
  } catch {
201
332
  console.log();
202
- console.log(chalk.red("Failed to initialize shadcn-vue."));
333
+ console.log(chalk.red("Failed to initialize project."));
203
334
  console.log();
204
335
  console.log(chalk.yellow("Common issues:"));
205
- console.log(chalk.dim(" \u2022 Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss"));
336
+ console.log(
337
+ chalk.dim(
338
+ " \u2022 Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss"
339
+ )
340
+ );
206
341
  console.log(chalk.dim(" \u2022 Not in a Vue/Nuxt project root directory"));
207
- console.log(chalk.dim(" \u2022 Existing components.json with invalid config - try: npx @frontic/ui init --force"));
342
+ console.log(
343
+ chalk.dim(
344
+ " \u2022 Existing components.json with invalid config - try: npx @frontic/ui init --force"
345
+ )
346
+ );
208
347
  console.log();
209
348
  process.exit(1);
210
349
  }
211
350
  console.log();
212
351
  }
213
- let brandColor = DEFAULT_BRAND_COLOR;
214
- if (options.brand) {
215
- if (isValidHex(options.brand)) {
216
- brandColor = hexToOklch(options.brand);
217
- console.log(chalk.dim(`Using brand color: ${options.brand} \u2192 ${brandColor}`));
218
- } else {
219
- console.log(chalk.yellow(`Invalid hex color: ${options.brand}, using default`));
220
- }
221
- } else if (!options.yes && !options.defaults) {
222
- const response = await prompts([
223
- {
224
- type: "text",
225
- name: "brand",
226
- message: "Brand color (hex, e.g., #6366f1)",
227
- initial: "#6366f1",
228
- validate: (value) => {
229
- if (!value) return true;
230
- return isValidHex(value) || "Please enter a valid hex color (e.g., #6366f1)";
231
- }
232
- }
233
- ]);
234
- if (response.brand && isValidHex(response.brand)) {
235
- brandColor = hexToOklch(response.brand);
236
- console.log(chalk.dim(`Converted: ${response.brand} \u2192 ${brandColor}`));
352
+ const brandForeground = getForegroundColor(brandColor);
353
+ const config = await readConfig();
354
+ const cssPath = config?.tailwind?.css;
355
+ if (cssPath) {
356
+ const cssSpinner = ora("Injecting theme variables...").start();
357
+ try {
358
+ const fullCssPath = join2(process.cwd(), cssPath);
359
+ await injectCssVars(fullCssPath, {
360
+ brand: brandColor,
361
+ brandForeground,
362
+ radius: radiusValue
363
+ });
364
+ cssSpinner.succeed("Theme variables injected");
365
+ } catch {
366
+ cssSpinner.warn(
367
+ "Could not inject theme variables (you may need to add them manually)"
368
+ );
237
369
  }
238
370
  }
239
- const brandForeground = getForegroundColor(brandColor);
240
371
  const spinner = ora("Configuring Frontic registry...").start();
241
372
  try {
242
373
  await updateConfig({
@@ -256,23 +387,23 @@ async function init(options) {
256
387
  await spawnShadcn(["add", "@frontic/theme", "--yes"], { silent: true });
257
388
  themeSpinner.succeed("Frontic theme installed");
258
389
  } catch {
259
- themeSpinner.warn("Theme installation skipped (may already exist or registry not available)");
390
+ themeSpinner.warn(
391
+ "Theme installation skipped (may already exist or registry not available)"
392
+ );
260
393
  }
261
394
  console.log();
262
395
  console.log(chalk.green("\u2713 Frontic UI initialized successfully!"));
263
396
  console.log();
264
- console.log(chalk.dim("Your brand color:"));
397
+ console.log(chalk.dim("Your theme settings:"));
265
398
  console.log(` --brand: ${chalk.cyan(brandColor)}`);
266
399
  console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);
400
+ console.log(` --radius: ${chalk.cyan(radiusValue)}`);
267
401
  console.log();
268
402
  console.log("Next steps:");
269
403
  console.log(chalk.dim(" 1. Add components:"));
270
404
  console.log(` ${chalk.cyan("npx @frontic/ui add button")}`);
271
405
  console.log();
272
- console.log(chalk.dim(" 2. Customize your brand color in your CSS:"));
273
- console.log(` ${chalk.cyan("--brand: " + brandColor + ";")}`);
274
- console.log();
275
- console.log(chalk.dim(" 3. Set up MCP for AI assistants (optional):"));
406
+ console.log(chalk.dim(" 2. Set up MCP for AI assistants (optional):"));
276
407
  console.log(` ${chalk.cyan("npx @frontic/ui mcp init")}`);
277
408
  console.log();
278
409
  }
@@ -346,9 +477,9 @@ async function add(components, options) {
346
477
  // src/commands/mcp.ts
347
478
  import chalk3 from "chalk";
348
479
  import ora3 from "ora";
349
- import { writeFile as writeFile2, readFile as readFile2, mkdir } from "fs/promises";
480
+ import { writeFile as writeFile3, readFile as readFile3, mkdir } from "fs/promises";
350
481
  import { existsSync } from "fs";
351
- import { join as join2 } from "path";
482
+ import { join as join3 } from "path";
352
483
  import prompts2 from "prompts";
353
484
  function registerMcpCommand(program2) {
354
485
  const mcp = program2.command("mcp").description("MCP (Model Context Protocol) commands");
@@ -399,14 +530,14 @@ async function initMcp(options) {
399
530
  async function createMcpConfig(client) {
400
531
  const config = getMcpConfig();
401
532
  const configPath = getMcpConfigPath(client);
402
- const configDir = join2(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
533
+ const configDir = join3(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
403
534
  if (!existsSync(configDir)) {
404
535
  await mkdir(configDir, { recursive: true });
405
536
  }
406
- const fullPath = join2(process.cwd(), configPath);
537
+ const fullPath = join3(process.cwd(), configPath);
407
538
  let existingConfig = {};
408
539
  try {
409
- const content = await readFile2(fullPath, "utf-8");
540
+ const content = await readFile3(fullPath, "utf-8");
410
541
  existingConfig = JSON.parse(content);
411
542
  } catch {
412
543
  }
@@ -417,7 +548,7 @@ async function createMcpConfig(client) {
417
548
  ...config.mcpServers
418
549
  }
419
550
  };
420
- await writeFile2(fullPath, JSON.stringify(mergedConfig, null, 2));
551
+ await writeFile3(fullPath, JSON.stringify(mergedConfig, null, 2));
421
552
  console.log(chalk3.dim(` Config written to: ${configPath}`));
422
553
  }
423
554
  function getMcpConfigPath(client) {
@@ -446,7 +577,7 @@ function getMcpConfig() {
446
577
 
447
578
  // src/index.ts
448
579
  var program = new Command();
449
- program.name("frontic-ui").description("CLI for adding Frontic UI components to your Vue project").version("0.0.7");
580
+ program.name("frontic-ui").description("CLI for adding Frontic UI components to your Nuxt project").version("0.3.1");
450
581
  registerInitCommand(program);
451
582
  registerAddCommand(program);
452
583
  registerMcpCommand(program);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/commands/init.ts","../../src/utils/spawn-shadcn.ts","../../src/utils/config.ts","../../src/utils/constants.ts","../../src/utils/colors.ts","../../src/commands/add.ts","../../src/commands/mcp.ts","../../bin/frontic-ui.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerAddCommand } from \"./commands/add.js\";\nimport { registerMcpCommand } from \"./commands/mcp.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"frontic-ui\")\n .description(\"CLI for adding Frontic UI components to your Vue project\")\n .version(\"0.0.7\");\n\nregisterInitCommand(program);\nregisterAddCommand(program);\nregisterMcpCommand(program);\n\nexport function run() {\n program.parse();\n}\n\nexport { program };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists } from \"../utils/config.js\";\nimport { FRONTIC_REGISTRY_URL, DEFAULT_BRAND_COLOR } from \"../utils/constants.js\";\nimport { hexToOklch, isValidHex, getForegroundColor } from \"../utils/colors.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\n force?: boolean;\n brand?: string;\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Frontic UI in your Vue project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"-d, --defaults\", \"Use default configuration\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\"-b, --brand <color>\", \"Brand color in hex format (e.g., #6366f1)\")\n .action(async (options: InitOptions) => {\n await init(options);\n });\n}\n\nasync function init(options: InitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI\"));\n console.log(chalk.dim(\"Initializing your project...\"));\n console.log();\n\n const hasConfig = await configExists();\n\n // Run shadcn-vue init if no config exists\n if (!hasConfig) {\n console.log(chalk.blue(\"Running shadcn-vue init...\"));\n console.log();\n\n const args = [\"init\"];\n if (options.yes) args.push(\"--yes\");\n if (options.defaults) args.push(\"--defaults\");\n if (options.force) args.push(\"--force\");\n\n try {\n await spawnShadcn(args);\n } catch {\n console.log();\n console.log(chalk.red(\"Failed to initialize shadcn-vue.\"));\n console.log();\n console.log(chalk.yellow(\"Common issues:\"));\n console.log(chalk.dim(\" • Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss\"));\n console.log(chalk.dim(\" • Not in a Vue/Nuxt project root directory\"));\n console.log(chalk.dim(\" • Existing components.json with invalid config - try: npx @frontic/ui init --force\"));\n console.log();\n process.exit(1);\n }\n console.log();\n }\n\n // Get brand color\n let brandColor = DEFAULT_BRAND_COLOR;\n\n // Check if brand was provided via CLI flag\n if (options.brand) {\n if (isValidHex(options.brand)) {\n brandColor = hexToOklch(options.brand);\n console.log(chalk.dim(`Using brand color: ${options.brand} → ${brandColor}`));\n } else {\n console.log(chalk.yellow(`Invalid hex color: ${options.brand}, using default`));\n }\n } else if (!options.yes && !options.defaults) {\n // Prompt for brand color\n const response = await prompts([\n {\n type: \"text\",\n name: \"brand\",\n message: \"Brand color (hex, e.g., #6366f1)\",\n initial: \"#6366f1\",\n validate: (value: string) => {\n if (!value) return true; // Allow empty to use default\n return isValidHex(value) || \"Please enter a valid hex color (e.g., #6366f1)\";\n },\n },\n ]);\n\n if (response.brand && isValidHex(response.brand)) {\n brandColor = hexToOklch(response.brand);\n console.log(chalk.dim(`Converted: ${response.brand} → ${brandColor}`));\n }\n }\n\n // Calculate foreground color based on brand\n const brandForeground = getForegroundColor(brandColor);\n\n // Update components.json with Frontic registry\n const spinner = ora(\"Configuring Frontic registry...\").start();\n\n try {\n await updateConfig({\n registries: {\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n spinner.succeed(\"Frontic registry configured\");\n } catch (error) {\n spinner.fail(\"Failed to configure registry\");\n throw error;\n }\n\n // Install Frontic theme from registry\n const themeSpinner = ora(\"Installing Frontic theme...\").start();\n try {\n await spawnShadcn([\"add\", \"@frontic/theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Frontic theme installed\");\n } catch {\n themeSpinner.warn(\"Theme installation skipped (may already exist or registry not available)\");\n }\n\n // TODO: In future, inject brand color into user's CSS\n // For now, we log it so users know what to set\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\n console.log();\n console.log(chalk.dim(\"Your brand color:\"));\n console.log(` --brand: ${chalk.cyan(brandColor)}`);\n console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1. Add components:\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log();\n console.log(chalk.dim(\" 2. Customize your brand color in your CSS:\"));\n console.log(` ${chalk.cyan(\"--brand: \" + brandColor + \";\")}`);\n console.log();\n console.log(chalk.dim(\" 3. Set up MCP for AI assistants (optional):\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui mcp init\")}`);\n console.log();\n}\n","import { execa } from \"execa\";\n\ninterface SpawnOptions {\n silent?: boolean;\n}\n\nexport async function spawnShadcn(\n args: string[],\n options: SpawnOptions = {}\n): Promise<void> {\n const { silent = false } = options;\n\n try {\n await execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: silent ? \"pipe\" : \"inherit\",\n shell: true,\n });\n } catch (error) {\n if (!silent) {\n throw error;\n }\n // Silently ignore errors when silent mode is enabled\n }\n}\n","import { readFile, writeFile, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { CONFIG_FILE, FRONTIC_REGISTRY_URL } from \"./constants.js\";\n\nexport interface ComponentsConfig {\n $schema?: string;\n style?: string;\n typescript?: boolean;\n tailwind?: {\n css?: string;\n baseColor?: string;\n cssVariables?: boolean;\n };\n aliases?: {\n components?: string;\n utils?: string;\n ui?: string;\n lib?: string;\n composables?: string;\n };\n registries?: {\n [key: string]: {\n url: string;\n };\n };\n}\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(join(process.cwd(), CONFIG_FILE));\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<ComponentsConfig | null> {\n try {\n const content = await readFile(join(process.cwd(), CONFIG_FILE), \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(config: ComponentsConfig): Promise<void> {\n await writeFile(\n join(process.cwd(), CONFIG_FILE),\n JSON.stringify(config, null, 2)\n );\n}\n\nexport async function updateConfig(\n updates: Partial<ComponentsConfig>\n): Promise<void> {\n const existing = await readConfig();\n\n if (!existing) {\n throw new Error(\n \"components.json not found. Run `npx @frontic/ui init` first.\"\n );\n }\n\n const merged = deepMerge(existing, updates);\n await writeConfig(merged);\n}\n\nexport async function ensureFronticRegistry(): Promise<void> {\n const config = await readConfig();\n\n if (!config) {\n throw new Error(\"components.json not found\");\n }\n\n // Check if Frontic registry is already configured\n if (config.registries?.[\"@frontic\"]?.url === FRONTIC_REGISTRY_URL) {\n return;\n }\n\n // Add Frontic registry\n await updateConfig({\n registries: {\n ...config.registries,\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n}\n\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n","// Use FRONTIC_REGISTRY_LOCAL=1 to test with local registry\nexport const FRONTIC_REGISTRY_URL =\n process.env.FRONTIC_REGISTRY_LOCAL === \"1\"\n ? \"http://localhost:3333/r/{name}.json\"\n : \"https://registry.frontic.io/r/{name}.json\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n// Default brand color (purple - similar to Indigo 500)\nexport const DEFAULT_BRAND_COLOR = \"oklch(58% 0.25 265)\";\n","/**\n * Color conversion utilities for Frontic UI CLI\n * Converts hex colors to OKLCH format for CSS variables\n */\n\n/**\n * Validates a hex color string\n * Accepts formats: #RGB, #RRGGBB, RGB, RRGGBB\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = hex.replace(/^#/, \"\");\n return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);\n}\n\n/**\n * Normalizes a hex color to 6-character format without #\n */\nfunction normalizeHex(hex: string): string {\n const cleanHex = hex.replace(/^#/, \"\");\n if (cleanHex.length === 3) {\n return cleanHex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return cleanHex;\n}\n\n/**\n * Converts hex color to RGB values (0-255)\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalizedHex = normalizeHex(hex);\n return {\n r: parseInt(normalizedHex.slice(0, 2), 16),\n g: parseInt(normalizedHex.slice(2, 4), 16),\n b: parseInt(normalizedHex.slice(4, 6), 16),\n };\n}\n\n/**\n * Converts sRGB to linear RGB\n */\nfunction srgbToLinear(value: number): number {\n const normalized = value / 255;\n return normalized <= 0.04045\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts linear RGB to XYZ color space\n */\nfunction linearRgbToXyz(r: number, g: number, b: number): { x: number; y: number; z: number } {\n return {\n x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,\n y: 0.2126729 * r + 0.7151522 * g + 0.0721750 * b,\n z: 0.0193339 * r + 0.1191920 * g + 0.9503041 * b,\n };\n}\n\n/**\n * Converts XYZ to OKLAB color space\n */\nfunction xyzToOklab(x: number, y: number, z: number): { l: number; a: number; b: number } {\n const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);\n const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);\n const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);\n\n return {\n l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n };\n}\n\n/**\n * Converts OKLAB to OKLCH color space\n */\nfunction oklabToOklch(l: number, a: number, b: number): { l: number; c: number; h: number } {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) * (180 / Math.PI);\n if (h < 0) h += 360;\n\n return { l, c, h };\n}\n\n/**\n * Converts a hex color to OKLCH format string\n * @param hex - Hex color (e.g., \"#6366f1\" or \"6366f1\")\n * @returns OKLCH string (e.g., \"oklch(55% 0.24 265)\")\n */\nexport function hexToOklch(hex: string): string {\n if (!isValidHex(hex)) {\n throw new Error(`Invalid hex color: ${hex}`);\n }\n\n const { r, g, b } = hexToRgb(hex);\n\n // Convert to linear RGB\n const linearR = srgbToLinear(r);\n const linearG = srgbToLinear(g);\n const linearB = srgbToLinear(b);\n\n // Convert to XYZ\n const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);\n\n // Convert to OKLAB\n const oklab = xyzToOklab(x, y, z);\n\n // Convert to OKLCH\n const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);\n\n // Format as OKLCH string\n // Lightness as percentage, chroma with 2 decimals, hue as integer\n const lightness = Math.round(l * 100);\n const chroma = Math.round(c * 100) / 100;\n const hue = Math.round(h);\n\n return `oklch(${lightness}% ${chroma} ${hue})`;\n}\n\n/**\n * Calculates appropriate foreground color (black or white) based on background lightness\n * @param oklchOrHex - Either an OKLCH string or hex color\n * @returns OKLCH string for foreground (white or dark)\n */\nexport function getForegroundColor(oklchOrHex: string): string {\n let lightness: number;\n\n if (oklchOrHex.startsWith(\"oklch\")) {\n // Parse OKLCH string\n const match = oklchOrHex.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n } else {\n // Convert hex to get lightness\n const oklch = hexToOklch(oklchOrHex);\n const match = oklch.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n }\n\n // Use white foreground for dark backgrounds, dark for light backgrounds\n return lightness > 0.6 ? \"oklch(20% 0 0)\" : \"oklch(100% 0 0)\";\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { ensureFronticRegistry } from \"../utils/config.js\";\n\ninterface AddOptions {\n overwrite?: boolean;\n all?: boolean;\n path?: string;\n yes?: boolean;\n}\n\n/**\n * Resolves component names to their @frontic/ prefixed form.\n *\n * All components go through the Frontic registry proxy which:\n * - Serves Frontic components if available (theme, button, fancy-button, etc.)\n * - Proxies to shadcn-vue for all other components (card, dialog, etc.)\n *\n * This allows the proxy to control routing centrally without CLI updates.\n */\nfunction resolveComponentNames(components: string[]): string[] {\n return components.map((component) => {\n // Already has a registry prefix - leave as-is\n if (component.startsWith(\"@\")) {\n return component;\n }\n // Prefix with @frontic/ - proxy handles the routing\n return `@frontic/${component}`;\n });\n}\n\nexport function registerAddCommand(program: Command) {\n program\n .command(\"add\")\n .description(\"Add components to your project\")\n .argument(\"[components...]\", \"Components to add\")\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .option(\"-a, --all\", \"Add all available components\")\n .option(\"-p, --path <path>\", \"Custom installation path\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (components: string[], options: AddOptions) => {\n await add(components, options);\n });\n}\n\nasync function add(components: string[], options: AddOptions) {\n // Validate input\n if (!options.all && components.length === 0) {\n console.log(chalk.red(\"Error: Please specify components to add or use --all\"));\n console.log();\n console.log(\"Usage:\");\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button dialog card\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add --all\")}`);\n process.exit(1);\n }\n\n // Ensure Frontic registry is configured\n const spinner = ora(\"Checking configuration...\").start();\n try {\n await ensureFronticRegistry();\n spinner.succeed(\"Configuration verified\");\n } catch {\n spinner.fail(\"Configuration error\");\n console.log();\n console.log(chalk.yellow(\"Run `npx @frontic/ui init` first to set up your project.\"));\n process.exit(1);\n }\n\n // Resolve component names (prefix with @frontic/ for proxy routing)\n const resolvedComponents = resolveComponentNames(components);\n\n // Show what we're adding\n if (resolvedComponents.length > 0) {\n console.log(\n chalk.cyan(\"Components:\"),\n resolvedComponents.map((c) => c.replace(\"@frontic/\", \"\")).join(\", \")\n );\n }\n\n // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...resolvedComponents);\n }\n\n if (options.overwrite) {\n args.push(\"--overwrite\");\n }\n\n if (options.path) {\n args.push(\"--path\", options.path);\n }\n\n if (options.yes) {\n args.push(\"--yes\");\n }\n\n console.log();\n console.log(chalk.blue(\"Adding components...\"));\n console.log();\n\n // Run shadcn-vue add\n await spawnShadcn(args);\n\n console.log();\n console.log(chalk.green(\"✓ Components added successfully!\"));\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile, readFile, mkdir } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport prompts from \"prompts\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ntype McpClient = \"claude\" | \"cursor\" | \"vscode\";\n\ninterface McpInitOptions {\n client?: McpClient;\n}\n\nexport function registerMcpCommand(program: Command) {\n const mcp = program\n .command(\"mcp\")\n .description(\"MCP (Model Context Protocol) commands\");\n\n mcp\n .command(\"init\")\n .description(\"Set up MCP for AI assistants\")\n .option(\"-c, --client <client>\", \"Target client (claude, cursor, vscode)\")\n .action(async (options: McpInitOptions) => {\n await initMcp(options);\n });\n}\n\nasync function initMcp(options: McpInitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI - MCP Setup\"));\n console.log(chalk.dim(\"Configure AI assistant integration\"));\n console.log();\n\n let client = options.client as McpClient | undefined;\n\n // Prompt for client if not specified\n if (!client) {\n const response = await prompts({\n type: \"select\",\n name: \"client\",\n message: \"Select your AI client:\",\n choices: [\n { title: \"Claude Code\", value: \"claude\" },\n { title: \"Cursor\", value: \"cursor\" },\n { title: \"VS Code\", value: \"vscode\" },\n ],\n });\n\n client = response.client;\n\n if (!client) {\n console.log(chalk.yellow(\"Setup cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Creating MCP configuration...\").start();\n\n try {\n await createMcpConfig(client);\n spinner.succeed(\"MCP configuration created\");\n } catch (error) {\n spinner.fail(\"Failed to create MCP configuration\");\n throw error;\n }\n\n console.log();\n console.log(chalk.green(\"✓ MCP configured successfully!\"));\n console.log();\n console.log(\"Your AI assistant can now:\");\n console.log(chalk.dim(\" • Browse available Frontic UI components\"));\n console.log(chalk.dim(\" • Add components using natural language\"));\n console.log(chalk.dim(' • Example: \"Add a button component\"'));\n console.log();\n}\n\nasync function createMcpConfig(client: McpClient) {\n const config = getMcpConfig();\n const configPath = getMcpConfigPath(client);\n const configDir = join(process.cwd(), configPath.split(\"/\").slice(0, -1).join(\"/\"));\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n await mkdir(configDir, { recursive: true });\n }\n\n const fullPath = join(process.cwd(), configPath);\n\n // Read existing config or create new\n let existingConfig: Record<string, unknown> = {};\n try {\n const content = await readFile(fullPath, \"utf-8\");\n existingConfig = JSON.parse(content);\n } catch {\n // File doesn't exist, use empty config\n }\n\n // Merge with existing config\n const mergedConfig = {\n ...existingConfig,\n mcpServers: {\n ...(existingConfig.mcpServers as Record<string, unknown> || {}),\n ...config.mcpServers,\n },\n };\n\n await writeFile(fullPath, JSON.stringify(mergedConfig, null, 2));\n\n console.log(chalk.dim(` Config written to: ${configPath}`));\n}\n\nfunction getMcpConfigPath(client: McpClient): string {\n switch (client) {\n case \"claude\":\n return \".mcp.json\";\n case \"cursor\":\n return \".cursor/mcp.json\";\n case \"vscode\":\n return \".vscode/mcp.json\";\n }\n}\n\nfunction getMcpConfig() {\n return {\n mcpServers: {\n \"frontic-ui\": {\n command: \"npx\",\n args: [\"shadcn-vue@latest\", \"mcp\"],\n env: {\n SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL,\n },\n },\n },\n };\n}\n","#!/usr/bin/env node\nimport { run } from '../src/index.js'\n\nrun()\n"],"mappings":"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","names":["program","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/commands/init.ts","../../src/utils/spawn-shadcn.ts","../../src/utils/config.ts","../../src/utils/constants.ts","../../src/utils/colors.ts","../../src/utils/css.ts","../../src/commands/add.ts","../../src/commands/mcp.ts","../../bin/frontic-ui.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerAddCommand } from \"./commands/add.js\";\nimport { registerMcpCommand } from \"./commands/mcp.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"frontic-ui\")\n .description(\"CLI for adding Frontic UI components to your Nuxt project\")\n .version(\"0.3.1\");\n\nregisterInitCommand(program);\nregisterAddCommand(program);\nregisterMcpCommand(program);\n\nexport function run() {\n program.parse();\n}\n\nexport { program };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport { join } from \"path\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists, readConfig } from \"../utils/config.js\";\nimport {\n FRONTIC_REGISTRY_URL,\n DEFAULT_BRAND_COLOR,\n DEFAULT_RADIUS,\n RADIUS_OPTIONS,\n type RadiusOption,\n} from \"../utils/constants.js\";\nimport { hexToOklch, isValidHex, getForegroundColor } from \"../utils/colors.js\";\nimport { injectCssVars } from \"../utils/css.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\n force?: boolean;\n brand?: string;\n radius?: string;\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Frontic UI in your Nuxt project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"-d, --defaults\", \"Use default configuration\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\"-b, --brand <color>\", \"Brand color in hex format (e.g., #6366f1)\")\n .option(\n \"-r, --radius <option>\",\n \"Border radius (none, small, medium, large, full)\"\n )\n .action(async (options: InitOptions) => {\n await init(options);\n });\n}\n\nasync function init(options: InitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI\"));\n console.log(chalk.dim(\"Initializing your project...\"));\n console.log();\n\n const hasConfig = await configExists();\n\n // Collect preferences BEFORE running shadcn-vue init\n let brandColor = DEFAULT_BRAND_COLOR;\n let radiusValue = DEFAULT_RADIUS;\n\n if (!hasConfig) {\n // Get brand color from CLI flag or prompt\n if (options.brand) {\n if (isValidHex(options.brand)) {\n brandColor = hexToOklch(options.brand);\n console.log(\n chalk.dim(`Using brand color: ${options.brand} → ${brandColor}`)\n );\n } else {\n console.log(\n chalk.yellow(`Invalid hex color: ${options.brand}, using default`)\n );\n }\n }\n\n // Get radius from CLI flag or validate it\n if (options.radius) {\n const radiusKey = options.radius.toLowerCase() as RadiusOption;\n if (radiusKey in RADIUS_OPTIONS) {\n radiusValue = RADIUS_OPTIONS[radiusKey];\n console.log(chalk.dim(`Using border radius: ${options.radius}`));\n } else {\n console.log(\n chalk.yellow(\n `Invalid radius option: ${options.radius}, using default (medium)`\n )\n );\n }\n }\n\n // Interactive prompts if not using --yes or --defaults\n if (!options.yes && !options.defaults) {\n const response = await prompts([\n {\n type: options.brand ? null : \"text\",\n name: \"brand\",\n message: \"Brand color (hex, e.g., #6366f1)\",\n initial: \"#6366f1\",\n validate: (value: string) => {\n if (!value) return true;\n return (\n isValidHex(value) ||\n \"Please enter a valid hex color (e.g., #6366f1)\"\n );\n },\n },\n {\n type: options.radius ? null : \"select\",\n name: \"radius\",\n message: \"Border radius\",\n choices: [\n { title: \"None\", value: \"none\" },\n { title: \"Small\", value: \"small\" },\n { title: \"Medium (recommended)\", value: \"medium\" },\n { title: \"Large\", value: \"large\" },\n { title: \"Full\", value: \"full\" },\n ],\n initial: 2,\n },\n ]);\n\n if (response.brand && isValidHex(response.brand)) {\n brandColor = hexToOklch(response.brand);\n console.log(chalk.dim(`Converted: ${response.brand} → ${brandColor}`));\n }\n\n if (response.radius) {\n radiusValue = RADIUS_OPTIONS[response.radius as RadiusOption];\n }\n }\n\n // Now run shadcn-vue init with output filtering\n console.log();\n console.log(chalk.blue(\"Setting up your project...\"));\n console.log();\n\n const args = [\"init\"];\n if (options.yes) args.push(\"--yes\");\n if (options.defaults) args.push(\"--defaults\");\n if (options.force) args.push(\"--force\");\n\n try {\n await spawnShadcn(args, { filterOutput: true });\n } catch {\n console.log();\n console.log(chalk.red(\"Failed to initialize project.\"));\n console.log();\n console.log(chalk.yellow(\"Common issues:\"));\n console.log(\n chalk.dim(\n \" • Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss\"\n )\n );\n console.log(chalk.dim(\" • Not in a Vue/Nuxt project root directory\"));\n console.log(\n chalk.dim(\n \" • Existing components.json with invalid config - try: npx @frontic/ui init --force\"\n )\n );\n console.log();\n process.exit(1);\n }\n console.log();\n }\n\n // Calculate foreground color based on brand\n const brandForeground = getForegroundColor(brandColor);\n\n // Read config to get CSS file path\n const config = await readConfig();\n const cssPath = config?.tailwind?.css;\n\n // Inject CSS variables into the user's CSS file\n if (cssPath) {\n const cssSpinner = ora(\"Injecting theme variables...\").start();\n try {\n const fullCssPath = join(process.cwd(), cssPath);\n await injectCssVars(fullCssPath, {\n brand: brandColor,\n brandForeground: brandForeground,\n radius: radiusValue,\n });\n cssSpinner.succeed(\"Theme variables injected\");\n } catch {\n cssSpinner.warn(\n \"Could not inject theme variables (you may need to add them manually)\"\n );\n }\n }\n\n // Update components.json with Frontic registry\n const spinner = ora(\"Configuring Frontic registry...\").start();\n\n try {\n await updateConfig({\n registries: {\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n spinner.succeed(\"Frontic registry configured\");\n } catch (error) {\n spinner.fail(\"Failed to configure registry\");\n throw error;\n }\n\n // Install Frontic theme from registry\n const themeSpinner = ora(\"Installing Frontic theme...\").start();\n try {\n await spawnShadcn([\"add\", \"@frontic/theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Frontic theme installed\");\n } catch {\n themeSpinner.warn(\n \"Theme installation skipped (may already exist or registry not available)\"\n );\n }\n\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\n console.log();\n console.log(chalk.dim(\"Your theme settings:\"));\n console.log(` --brand: ${chalk.cyan(brandColor)}`);\n console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);\n console.log(` --radius: ${chalk.cyan(radiusValue)}`);\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1. Add components:\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log();\n console.log(chalk.dim(\" 2. Set up MCP for AI assistants (optional):\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui mcp init\")}`);\n console.log();\n}\n","import { execa } from \"execa\";\n\ninterface SpawnOptions {\n silent?: boolean;\n filterOutput?: boolean;\n}\n\nexport async function spawnShadcn(\n args: string[],\n options: SpawnOptions = {}\n): Promise<void> {\n const { silent = false, filterOutput = false } = options;\n\n try {\n if (filterOutput) {\n // Capture output, replace \"shadcn-vue\" → \"frontic-ui\", forward to stdout\n const proc = execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: [\"inherit\", \"pipe\", \"pipe\"],\n shell: true,\n });\n\n proc.stdout?.on(\"data\", (data: Buffer) => {\n process.stdout.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n proc.stderr?.on(\"data\", (data: Buffer) => {\n process.stderr.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n await proc;\n } else {\n await execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: silent ? \"pipe\" : \"inherit\",\n shell: true,\n });\n }\n } catch (error) {\n if (!silent) {\n throw error;\n }\n // Silently ignore errors when silent mode is enabled\n }\n}\n","import { readFile, writeFile, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { CONFIG_FILE, FRONTIC_REGISTRY_URL } from \"./constants.js\";\n\nexport interface ComponentsConfig {\n $schema?: string;\n style?: string;\n typescript?: boolean;\n tailwind?: {\n css?: string;\n baseColor?: string;\n cssVariables?: boolean;\n };\n aliases?: {\n components?: string;\n utils?: string;\n ui?: string;\n lib?: string;\n composables?: string;\n };\n registries?: {\n [key: string]: {\n url: string;\n };\n };\n}\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(join(process.cwd(), CONFIG_FILE));\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<ComponentsConfig | null> {\n try {\n const content = await readFile(join(process.cwd(), CONFIG_FILE), \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(config: ComponentsConfig): Promise<void> {\n await writeFile(\n join(process.cwd(), CONFIG_FILE),\n JSON.stringify(config, null, 2)\n );\n}\n\nexport async function updateConfig(\n updates: Partial<ComponentsConfig>\n): Promise<void> {\n const existing = await readConfig();\n\n if (!existing) {\n throw new Error(\n \"components.json not found. Run `npx @frontic/ui init` first.\"\n );\n }\n\n const merged = deepMerge(existing, updates);\n await writeConfig(merged);\n}\n\nexport async function ensureFronticRegistry(): Promise<void> {\n const config = await readConfig();\n\n if (!config) {\n throw new Error(\"components.json not found\");\n }\n\n // Check if Frontic registry is already configured\n if (config.registries?.[\"@frontic\"]?.url === FRONTIC_REGISTRY_URL) {\n return;\n }\n\n // Add Frontic registry\n await updateConfig({\n registries: {\n ...config.registries,\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n}\n\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n","// Use FRONTIC_REGISTRY_LOCAL=1 to test with local registry\nexport const FRONTIC_REGISTRY_URL =\n process.env.FRONTIC_REGISTRY_LOCAL === \"1\"\n ? \"http://localhost:3333/r/{name}.json\"\n : \"https://registry.frontic.io/r/{name}.json\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n// Default brand color (purple - similar to Indigo 500)\nexport const DEFAULT_BRAND_COLOR = \"oklch(58% 0.25 265)\";\n\n// Default radius (medium)\nexport const DEFAULT_RADIUS = \"0.5rem\";\n\n// Radius options for CLI prompt\n// These are base values for --radius. The derived Tailwind vars (--radius-sm, etc.)\n// are calculated by shadcn's @theme inline block using calc() offsets.\nexport const RADIUS_OPTIONS = {\n none: \"0\",\n small: \"0.3rem\",\n medium: \"0.5rem\",\n large: \"0.75rem\",\n full: \"1rem\",\n} as const;\n\nexport type RadiusOption = keyof typeof RADIUS_OPTIONS;\n","/**\n * Color conversion utilities for Frontic UI CLI\n * Converts hex colors to OKLCH format for CSS variables\n */\n\n/**\n * Validates a hex color string\n * Accepts formats: #RGB, #RRGGBB, RGB, RRGGBB\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = hex.replace(/^#/, \"\");\n return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);\n}\n\n/**\n * Normalizes a hex color to 6-character format without #\n */\nfunction normalizeHex(hex: string): string {\n const cleanHex = hex.replace(/^#/, \"\");\n if (cleanHex.length === 3) {\n return cleanHex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return cleanHex;\n}\n\n/**\n * Converts hex color to RGB values (0-255)\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalizedHex = normalizeHex(hex);\n return {\n r: parseInt(normalizedHex.slice(0, 2), 16),\n g: parseInt(normalizedHex.slice(2, 4), 16),\n b: parseInt(normalizedHex.slice(4, 6), 16),\n };\n}\n\n/**\n * Converts sRGB to linear RGB\n */\nfunction srgbToLinear(value: number): number {\n const normalized = value / 255;\n return normalized <= 0.04045\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts linear RGB to XYZ color space\n */\nfunction linearRgbToXyz(r: number, g: number, b: number): { x: number; y: number; z: number } {\n return {\n x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,\n y: 0.2126729 * r + 0.7151522 * g + 0.0721750 * b,\n z: 0.0193339 * r + 0.1191920 * g + 0.9503041 * b,\n };\n}\n\n/**\n * Converts XYZ to OKLAB color space\n */\nfunction xyzToOklab(x: number, y: number, z: number): { l: number; a: number; b: number } {\n const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);\n const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);\n const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);\n\n return {\n l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n };\n}\n\n/**\n * Converts OKLAB to OKLCH color space\n */\nfunction oklabToOklch(l: number, a: number, b: number): { l: number; c: number; h: number } {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) * (180 / Math.PI);\n if (h < 0) h += 360;\n\n return { l, c, h };\n}\n\n/**\n * Converts a hex color to OKLCH format string\n * @param hex - Hex color (e.g., \"#6366f1\" or \"6366f1\")\n * @returns OKLCH string (e.g., \"oklch(55% 0.24 265)\")\n */\nexport function hexToOklch(hex: string): string {\n if (!isValidHex(hex)) {\n throw new Error(`Invalid hex color: ${hex}`);\n }\n\n const { r, g, b } = hexToRgb(hex);\n\n // Convert to linear RGB\n const linearR = srgbToLinear(r);\n const linearG = srgbToLinear(g);\n const linearB = srgbToLinear(b);\n\n // Convert to XYZ\n const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);\n\n // Convert to OKLAB\n const oklab = xyzToOklab(x, y, z);\n\n // Convert to OKLCH\n const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);\n\n // Format as OKLCH string\n // Lightness as percentage, chroma with 2 decimals, hue as integer\n const lightness = Math.round(l * 100);\n const chroma = Math.round(c * 100) / 100;\n const hue = Math.round(h);\n\n return `oklch(${lightness}% ${chroma} ${hue})`;\n}\n\n/**\n * Calculates appropriate foreground color (black or white) based on background lightness\n * @param oklchOrHex - Either an OKLCH string or hex color\n * @returns OKLCH string for foreground (white or dark)\n */\nexport function getForegroundColor(oklchOrHex: string): string {\n let lightness: number;\n\n if (oklchOrHex.startsWith(\"oklch\")) {\n // Parse OKLCH string\n const match = oklchOrHex.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n } else {\n // Convert hex to get lightness\n const oklch = hexToOklch(oklchOrHex);\n const match = oklch.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n }\n\n // Use white foreground for dark backgrounds, dark for light backgrounds\n return lightness > 0.6 ? \"oklch(20% 0 0)\" : \"oklch(100% 0 0)\";\n}\n","import { readFile, writeFile } from \"fs/promises\";\n\n/**\n * Upsert a CSS variable in a CSS content string.\n * If the variable exists, replace its value. If not, add it at the end.\n */\nfunction upsertCssVar(content: string, varName: string, value: string): string {\n const varRegex = new RegExp(`(${varName}\\\\s*:\\\\s*)([^;]+)(;)`, \"g\");\n\n if (varRegex.test(content)) {\n // Variable exists, replace its value\n return content.replace(varRegex, `$1${value}$3`);\n } else {\n // Variable doesn't exist, add it before the closing brace area\n // Add with proper indentation\n return content.trimEnd() + `\\n ${varName}: ${value};`;\n }\n}\n\n/**\n * Inject CSS variables into the :root block of a CSS file.\n * Handles both adding new variables and updating existing ones.\n */\nexport async function injectCssVars(\n cssPath: string,\n vars: { brand: string; brandForeground: string; radius: string }\n): Promise<void> {\n const content = await readFile(cssPath, \"utf-8\");\n\n // Match :root { ... } block - use a more robust pattern that handles nested content\n const rootRegex = /:root\\s*\\{([^}]*)\\}/;\n const match = content.match(rootRegex);\n\n if (match && match[1] !== undefined) {\n let rootContent = match[1];\n\n // Add or replace --brand, --brand-foreground, --radius\n rootContent = upsertCssVar(rootContent, \"--brand\", vars.brand);\n rootContent = upsertCssVar(\n rootContent,\n \"--brand-foreground\",\n vars.brandForeground\n );\n rootContent = upsertCssVar(rootContent, \"--radius\", vars.radius);\n\n const newContent = content.replace(rootRegex, `:root {${rootContent}\\n}`);\n await writeFile(cssPath, newContent);\n } else {\n // No :root block found, create one at the beginning\n const rootBlock = `:root {\n --brand: ${vars.brand};\n --brand-foreground: ${vars.brandForeground};\n --radius: ${vars.radius};\n}\n\n`;\n await writeFile(cssPath, rootBlock + content);\n }\n}\n\n/**\n * Get the CSS file path from components.json config.\n */\nexport function getCssPathFromConfig(config: {\n tailwind?: { css?: string };\n}): string | null {\n return config.tailwind?.css || null;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { ensureFronticRegistry } from \"../utils/config.js\";\n\ninterface AddOptions {\n overwrite?: boolean;\n all?: boolean;\n path?: string;\n yes?: boolean;\n}\n\n/**\n * Resolves component names to their @frontic/ prefixed form.\n *\n * All components go through the Frontic registry proxy which:\n * - Serves Frontic components if available (theme, button, fancy-button, etc.)\n * - Proxies to shadcn-vue for all other components (card, dialog, etc.)\n *\n * This allows the proxy to control routing centrally without CLI updates.\n */\nfunction resolveComponentNames(components: string[]): string[] {\n return components.map((component) => {\n // Already has a registry prefix - leave as-is\n if (component.startsWith(\"@\")) {\n return component;\n }\n // Prefix with @frontic/ - proxy handles the routing\n return `@frontic/${component}`;\n });\n}\n\nexport function registerAddCommand(program: Command) {\n program\n .command(\"add\")\n .description(\"Add components to your project\")\n .argument(\"[components...]\", \"Components to add\")\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .option(\"-a, --all\", \"Add all available components\")\n .option(\"-p, --path <path>\", \"Custom installation path\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (components: string[], options: AddOptions) => {\n await add(components, options);\n });\n}\n\nasync function add(components: string[], options: AddOptions) {\n // Validate input\n if (!options.all && components.length === 0) {\n console.log(chalk.red(\"Error: Please specify components to add or use --all\"));\n console.log();\n console.log(\"Usage:\");\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button dialog card\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add --all\")}`);\n process.exit(1);\n }\n\n // Ensure Frontic registry is configured\n const spinner = ora(\"Checking configuration...\").start();\n try {\n await ensureFronticRegistry();\n spinner.succeed(\"Configuration verified\");\n } catch {\n spinner.fail(\"Configuration error\");\n console.log();\n console.log(chalk.yellow(\"Run `npx @frontic/ui init` first to set up your project.\"));\n process.exit(1);\n }\n\n // Resolve component names (prefix with @frontic/ for proxy routing)\n const resolvedComponents = resolveComponentNames(components);\n\n // Show what we're adding\n if (resolvedComponents.length > 0) {\n console.log(\n chalk.cyan(\"Components:\"),\n resolvedComponents.map((c) => c.replace(\"@frontic/\", \"\")).join(\", \")\n );\n }\n\n // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...resolvedComponents);\n }\n\n if (options.overwrite) {\n args.push(\"--overwrite\");\n }\n\n if (options.path) {\n args.push(\"--path\", options.path);\n }\n\n if (options.yes) {\n args.push(\"--yes\");\n }\n\n console.log();\n console.log(chalk.blue(\"Adding components...\"));\n console.log();\n\n // Run shadcn-vue add\n await spawnShadcn(args);\n\n console.log();\n console.log(chalk.green(\"✓ Components added successfully!\"));\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile, readFile, mkdir } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport prompts from \"prompts\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ntype McpClient = \"claude\" | \"cursor\" | \"vscode\";\n\ninterface McpInitOptions {\n client?: McpClient;\n}\n\nexport function registerMcpCommand(program: Command) {\n const mcp = program\n .command(\"mcp\")\n .description(\"MCP (Model Context Protocol) commands\");\n\n mcp\n .command(\"init\")\n .description(\"Set up MCP for AI assistants\")\n .option(\"-c, --client <client>\", \"Target client (claude, cursor, vscode)\")\n .action(async (options: McpInitOptions) => {\n await initMcp(options);\n });\n}\n\nasync function initMcp(options: McpInitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI - MCP Setup\"));\n console.log(chalk.dim(\"Configure AI assistant integration\"));\n console.log();\n\n let client = options.client as McpClient | undefined;\n\n // Prompt for client if not specified\n if (!client) {\n const response = await prompts({\n type: \"select\",\n name: \"client\",\n message: \"Select your AI client:\",\n choices: [\n { title: \"Claude Code\", value: \"claude\" },\n { title: \"Cursor\", value: \"cursor\" },\n { title: \"VS Code\", value: \"vscode\" },\n ],\n });\n\n client = response.client;\n\n if (!client) {\n console.log(chalk.yellow(\"Setup cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Creating MCP configuration...\").start();\n\n try {\n await createMcpConfig(client);\n spinner.succeed(\"MCP configuration created\");\n } catch (error) {\n spinner.fail(\"Failed to create MCP configuration\");\n throw error;\n }\n\n console.log();\n console.log(chalk.green(\"✓ MCP configured successfully!\"));\n console.log();\n console.log(\"Your AI assistant can now:\");\n console.log(chalk.dim(\" • Browse available Frontic UI components\"));\n console.log(chalk.dim(\" • Add components using natural language\"));\n console.log(chalk.dim(' • Example: \"Add a button component\"'));\n console.log();\n}\n\nasync function createMcpConfig(client: McpClient) {\n const config = getMcpConfig();\n const configPath = getMcpConfigPath(client);\n const configDir = join(process.cwd(), configPath.split(\"/\").slice(0, -1).join(\"/\"));\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n await mkdir(configDir, { recursive: true });\n }\n\n const fullPath = join(process.cwd(), configPath);\n\n // Read existing config or create new\n let existingConfig: Record<string, unknown> = {};\n try {\n const content = await readFile(fullPath, \"utf-8\");\n existingConfig = JSON.parse(content);\n } catch {\n // File doesn't exist, use empty config\n }\n\n // Merge with existing config\n const mergedConfig = {\n ...existingConfig,\n mcpServers: {\n ...(existingConfig.mcpServers as Record<string, unknown> || {}),\n ...config.mcpServers,\n },\n };\n\n await writeFile(fullPath, JSON.stringify(mergedConfig, null, 2));\n\n console.log(chalk.dim(` Config written to: ${configPath}`));\n}\n\nfunction getMcpConfigPath(client: McpClient): string {\n switch (client) {\n case \"claude\":\n return \".mcp.json\";\n case \"cursor\":\n return \".cursor/mcp.json\";\n case \"vscode\":\n return \".vscode/mcp.json\";\n }\n}\n\nfunction getMcpConfig() {\n return {\n mcpServers: {\n \"frontic-ui\": {\n command: \"npx\",\n args: [\"shadcn-vue@latest\", \"mcp\"],\n env: {\n SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL,\n },\n },\n },\n };\n}\n","#!/usr/bin/env node\nimport { run } from '../src/index.js'\n\nrun()\n"],"mappings":"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","names":["join","readFile","writeFile","program","join","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
package/dist/index.js CHANGED
@@ -5,16 +5,35 @@ import { Command } from "commander";
5
5
  import chalk from "chalk";
6
6
  import ora from "ora";
7
7
  import prompts from "prompts";
8
+ import { join as join2 } from "path";
8
9
 
9
10
  // src/utils/spawn-shadcn.ts
10
11
  import { execa } from "execa";
11
12
  async function spawnShadcn(args, options = {}) {
12
- const { silent = false } = options;
13
+ const { silent = false, filterOutput = false } = options;
13
14
  try {
14
- await execa("npx", ["shadcn-vue@latest", ...args], {
15
- stdio: silent ? "pipe" : "inherit",
16
- shell: true
17
- });
15
+ if (filterOutput) {
16
+ const proc = execa("npx", ["shadcn-vue@latest", ...args], {
17
+ stdio: ["inherit", "pipe", "pipe"],
18
+ shell: true
19
+ });
20
+ proc.stdout?.on("data", (data) => {
21
+ process.stdout.write(
22
+ data.toString().replace(/shadcn-vue/gi, "frontic-ui")
23
+ );
24
+ });
25
+ proc.stderr?.on("data", (data) => {
26
+ process.stderr.write(
27
+ data.toString().replace(/shadcn-vue/gi, "frontic-ui")
28
+ );
29
+ });
30
+ await proc;
31
+ } else {
32
+ await execa("npx", ["shadcn-vue@latest", ...args], {
33
+ stdio: silent ? "pipe" : "inherit",
34
+ shell: true
35
+ });
36
+ }
18
37
  } catch (error) {
19
38
  if (!silent) {
20
39
  throw error;
@@ -30,6 +49,14 @@ import { join } from "path";
30
49
  var FRONTIC_REGISTRY_URL = process.env.FRONTIC_REGISTRY_LOCAL === "1" ? "http://localhost:3333/r/{name}.json" : "https://registry.frontic.io/r/{name}.json";
31
50
  var CONFIG_FILE = "components.json";
32
51
  var DEFAULT_BRAND_COLOR = "oklch(58% 0.25 265)";
52
+ var DEFAULT_RADIUS = "0.5rem";
53
+ var RADIUS_OPTIONS = {
54
+ none: "0",
55
+ small: "0.3rem",
56
+ medium: "0.5rem",
57
+ large: "0.75rem",
58
+ full: "1rem"
59
+ };
33
60
 
34
61
  // src/utils/config.ts
35
62
  async function configExists() {
@@ -174,9 +201,51 @@ function getForegroundColor(oklchOrHex) {
174
201
  return lightness > 0.6 ? "oklch(20% 0 0)" : "oklch(100% 0 0)";
175
202
  }
176
203
 
204
+ // src/utils/css.ts
205
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
206
+ function upsertCssVar(content, varName, value) {
207
+ const varRegex = new RegExp(`(${varName}\\s*:\\s*)([^;]+)(;)`, "g");
208
+ if (varRegex.test(content)) {
209
+ return content.replace(varRegex, `$1${value}$3`);
210
+ } else {
211
+ return content.trimEnd() + `
212
+ ${varName}: ${value};`;
213
+ }
214
+ }
215
+ async function injectCssVars(cssPath, vars) {
216
+ const content = await readFile2(cssPath, "utf-8");
217
+ const rootRegex = /:root\s*\{([^}]*)\}/;
218
+ const match = content.match(rootRegex);
219
+ if (match && match[1] !== void 0) {
220
+ let rootContent = match[1];
221
+ rootContent = upsertCssVar(rootContent, "--brand", vars.brand);
222
+ rootContent = upsertCssVar(
223
+ rootContent,
224
+ "--brand-foreground",
225
+ vars.brandForeground
226
+ );
227
+ rootContent = upsertCssVar(rootContent, "--radius", vars.radius);
228
+ const newContent = content.replace(rootRegex, `:root {${rootContent}
229
+ }`);
230
+ await writeFile2(cssPath, newContent);
231
+ } else {
232
+ const rootBlock = `:root {
233
+ --brand: ${vars.brand};
234
+ --brand-foreground: ${vars.brandForeground};
235
+ --radius: ${vars.radius};
236
+ }
237
+
238
+ `;
239
+ await writeFile2(cssPath, rootBlock + content);
240
+ }
241
+ }
242
+
177
243
  // src/commands/init.ts
178
244
  function registerInitCommand(program2) {
179
- program2.command("init").description("Initialize Frontic UI in your Vue project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").option("-f, --force", "Force overwrite of existing configuration").option("-b, --brand <color>", "Brand color in hex format (e.g., #6366f1)").action(async (options) => {
245
+ program2.command("init").description("Initialize Frontic UI in your Nuxt project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").option("-f, --force", "Force overwrite of existing configuration").option("-b, --brand <color>", "Brand color in hex format (e.g., #6366f1)").option(
246
+ "-r, --radius <option>",
247
+ "Border radius (none, small, medium, large, full)"
248
+ ).action(async (options) => {
180
249
  await init(options);
181
250
  });
182
251
  }
@@ -186,55 +255,117 @@ async function init(options) {
186
255
  console.log(chalk.dim("Initializing your project..."));
187
256
  console.log();
188
257
  const hasConfig = await configExists();
258
+ let brandColor = DEFAULT_BRAND_COLOR;
259
+ let radiusValue = DEFAULT_RADIUS;
189
260
  if (!hasConfig) {
190
- console.log(chalk.blue("Running shadcn-vue init..."));
261
+ if (options.brand) {
262
+ if (isValidHex(options.brand)) {
263
+ brandColor = hexToOklch(options.brand);
264
+ console.log(
265
+ chalk.dim(`Using brand color: ${options.brand} \u2192 ${brandColor}`)
266
+ );
267
+ } else {
268
+ console.log(
269
+ chalk.yellow(`Invalid hex color: ${options.brand}, using default`)
270
+ );
271
+ }
272
+ }
273
+ if (options.radius) {
274
+ const radiusKey = options.radius.toLowerCase();
275
+ if (radiusKey in RADIUS_OPTIONS) {
276
+ radiusValue = RADIUS_OPTIONS[radiusKey];
277
+ console.log(chalk.dim(`Using border radius: ${options.radius}`));
278
+ } else {
279
+ console.log(
280
+ chalk.yellow(
281
+ `Invalid radius option: ${options.radius}, using default (medium)`
282
+ )
283
+ );
284
+ }
285
+ }
286
+ if (!options.yes && !options.defaults) {
287
+ const response = await prompts([
288
+ {
289
+ type: options.brand ? null : "text",
290
+ name: "brand",
291
+ message: "Brand color (hex, e.g., #6366f1)",
292
+ initial: "#6366f1",
293
+ validate: (value) => {
294
+ if (!value) return true;
295
+ return isValidHex(value) || "Please enter a valid hex color (e.g., #6366f1)";
296
+ }
297
+ },
298
+ {
299
+ type: options.radius ? null : "select",
300
+ name: "radius",
301
+ message: "Border radius",
302
+ choices: [
303
+ { title: "None", value: "none" },
304
+ { title: "Small", value: "small" },
305
+ { title: "Medium (recommended)", value: "medium" },
306
+ { title: "Large", value: "large" },
307
+ { title: "Full", value: "full" }
308
+ ],
309
+ initial: 2
310
+ }
311
+ ]);
312
+ if (response.brand && isValidHex(response.brand)) {
313
+ brandColor = hexToOklch(response.brand);
314
+ console.log(chalk.dim(`Converted: ${response.brand} \u2192 ${brandColor}`));
315
+ }
316
+ if (response.radius) {
317
+ radiusValue = RADIUS_OPTIONS[response.radius];
318
+ }
319
+ }
320
+ console.log();
321
+ console.log(chalk.blue("Setting up your project..."));
191
322
  console.log();
192
323
  const args = ["init"];
193
324
  if (options.yes) args.push("--yes");
194
325
  if (options.defaults) args.push("--defaults");
195
326
  if (options.force) args.push("--force");
196
327
  try {
197
- await spawnShadcn(args);
328
+ await spawnShadcn(args, { filterOutput: true });
198
329
  } catch {
199
330
  console.log();
200
- console.log(chalk.red("Failed to initialize shadcn-vue."));
331
+ console.log(chalk.red("Failed to initialize project."));
201
332
  console.log();
202
333
  console.log(chalk.yellow("Common issues:"));
203
- console.log(chalk.dim(" \u2022 Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss"));
334
+ console.log(
335
+ chalk.dim(
336
+ " \u2022 Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss"
337
+ )
338
+ );
204
339
  console.log(chalk.dim(" \u2022 Not in a Vue/Nuxt project root directory"));
205
- console.log(chalk.dim(" \u2022 Existing components.json with invalid config - try: npx @frontic/ui init --force"));
340
+ console.log(
341
+ chalk.dim(
342
+ " \u2022 Existing components.json with invalid config - try: npx @frontic/ui init --force"
343
+ )
344
+ );
206
345
  console.log();
207
346
  process.exit(1);
208
347
  }
209
348
  console.log();
210
349
  }
211
- let brandColor = DEFAULT_BRAND_COLOR;
212
- if (options.brand) {
213
- if (isValidHex(options.brand)) {
214
- brandColor = hexToOklch(options.brand);
215
- console.log(chalk.dim(`Using brand color: ${options.brand} \u2192 ${brandColor}`));
216
- } else {
217
- console.log(chalk.yellow(`Invalid hex color: ${options.brand}, using default`));
218
- }
219
- } else if (!options.yes && !options.defaults) {
220
- const response = await prompts([
221
- {
222
- type: "text",
223
- name: "brand",
224
- message: "Brand color (hex, e.g., #6366f1)",
225
- initial: "#6366f1",
226
- validate: (value) => {
227
- if (!value) return true;
228
- return isValidHex(value) || "Please enter a valid hex color (e.g., #6366f1)";
229
- }
230
- }
231
- ]);
232
- if (response.brand && isValidHex(response.brand)) {
233
- brandColor = hexToOklch(response.brand);
234
- console.log(chalk.dim(`Converted: ${response.brand} \u2192 ${brandColor}`));
350
+ const brandForeground = getForegroundColor(brandColor);
351
+ const config = await readConfig();
352
+ const cssPath = config?.tailwind?.css;
353
+ if (cssPath) {
354
+ const cssSpinner = ora("Injecting theme variables...").start();
355
+ try {
356
+ const fullCssPath = join2(process.cwd(), cssPath);
357
+ await injectCssVars(fullCssPath, {
358
+ brand: brandColor,
359
+ brandForeground,
360
+ radius: radiusValue
361
+ });
362
+ cssSpinner.succeed("Theme variables injected");
363
+ } catch {
364
+ cssSpinner.warn(
365
+ "Could not inject theme variables (you may need to add them manually)"
366
+ );
235
367
  }
236
368
  }
237
- const brandForeground = getForegroundColor(brandColor);
238
369
  const spinner = ora("Configuring Frontic registry...").start();
239
370
  try {
240
371
  await updateConfig({
@@ -254,23 +385,23 @@ async function init(options) {
254
385
  await spawnShadcn(["add", "@frontic/theme", "--yes"], { silent: true });
255
386
  themeSpinner.succeed("Frontic theme installed");
256
387
  } catch {
257
- themeSpinner.warn("Theme installation skipped (may already exist or registry not available)");
388
+ themeSpinner.warn(
389
+ "Theme installation skipped (may already exist or registry not available)"
390
+ );
258
391
  }
259
392
  console.log();
260
393
  console.log(chalk.green("\u2713 Frontic UI initialized successfully!"));
261
394
  console.log();
262
- console.log(chalk.dim("Your brand color:"));
395
+ console.log(chalk.dim("Your theme settings:"));
263
396
  console.log(` --brand: ${chalk.cyan(brandColor)}`);
264
397
  console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);
398
+ console.log(` --radius: ${chalk.cyan(radiusValue)}`);
265
399
  console.log();
266
400
  console.log("Next steps:");
267
401
  console.log(chalk.dim(" 1. Add components:"));
268
402
  console.log(` ${chalk.cyan("npx @frontic/ui add button")}`);
269
403
  console.log();
270
- console.log(chalk.dim(" 2. Customize your brand color in your CSS:"));
271
- console.log(` ${chalk.cyan("--brand: " + brandColor + ";")}`);
272
- console.log();
273
- console.log(chalk.dim(" 3. Set up MCP for AI assistants (optional):"));
404
+ console.log(chalk.dim(" 2. Set up MCP for AI assistants (optional):"));
274
405
  console.log(` ${chalk.cyan("npx @frontic/ui mcp init")}`);
275
406
  console.log();
276
407
  }
@@ -344,9 +475,9 @@ async function add(components, options) {
344
475
  // src/commands/mcp.ts
345
476
  import chalk3 from "chalk";
346
477
  import ora3 from "ora";
347
- import { writeFile as writeFile2, readFile as readFile2, mkdir } from "fs/promises";
478
+ import { writeFile as writeFile3, readFile as readFile3, mkdir } from "fs/promises";
348
479
  import { existsSync } from "fs";
349
- import { join as join2 } from "path";
480
+ import { join as join3 } from "path";
350
481
  import prompts2 from "prompts";
351
482
  function registerMcpCommand(program2) {
352
483
  const mcp = program2.command("mcp").description("MCP (Model Context Protocol) commands");
@@ -397,14 +528,14 @@ async function initMcp(options) {
397
528
  async function createMcpConfig(client) {
398
529
  const config = getMcpConfig();
399
530
  const configPath = getMcpConfigPath(client);
400
- const configDir = join2(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
531
+ const configDir = join3(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
401
532
  if (!existsSync(configDir)) {
402
533
  await mkdir(configDir, { recursive: true });
403
534
  }
404
- const fullPath = join2(process.cwd(), configPath);
535
+ const fullPath = join3(process.cwd(), configPath);
405
536
  let existingConfig = {};
406
537
  try {
407
- const content = await readFile2(fullPath, "utf-8");
538
+ const content = await readFile3(fullPath, "utf-8");
408
539
  existingConfig = JSON.parse(content);
409
540
  } catch {
410
541
  }
@@ -415,7 +546,7 @@ async function createMcpConfig(client) {
415
546
  ...config.mcpServers
416
547
  }
417
548
  };
418
- await writeFile2(fullPath, JSON.stringify(mergedConfig, null, 2));
549
+ await writeFile3(fullPath, JSON.stringify(mergedConfig, null, 2));
419
550
  console.log(chalk3.dim(` Config written to: ${configPath}`));
420
551
  }
421
552
  function getMcpConfigPath(client) {
@@ -444,7 +575,7 @@ function getMcpConfig() {
444
575
 
445
576
  // src/index.ts
446
577
  var program = new Command();
447
- program.name("frontic-ui").description("CLI for adding Frontic UI components to your Vue project").version("0.0.7");
578
+ program.name("frontic-ui").description("CLI for adding Frontic UI components to your Nuxt project").version("0.3.1");
448
579
  registerInitCommand(program);
449
580
  registerAddCommand(program);
450
581
  registerMcpCommand(program);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/spawn-shadcn.ts","../src/utils/config.ts","../src/utils/constants.ts","../src/utils/colors.ts","../src/commands/add.ts","../src/commands/mcp.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerAddCommand } from \"./commands/add.js\";\nimport { registerMcpCommand } from \"./commands/mcp.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"frontic-ui\")\n .description(\"CLI for adding Frontic UI components to your Vue project\")\n .version(\"0.0.7\");\n\nregisterInitCommand(program);\nregisterAddCommand(program);\nregisterMcpCommand(program);\n\nexport function run() {\n program.parse();\n}\n\nexport { program };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists } from \"../utils/config.js\";\nimport { FRONTIC_REGISTRY_URL, DEFAULT_BRAND_COLOR } from \"../utils/constants.js\";\nimport { hexToOklch, isValidHex, getForegroundColor } from \"../utils/colors.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\n force?: boolean;\n brand?: string;\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Frontic UI in your Vue project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"-d, --defaults\", \"Use default configuration\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\"-b, --brand <color>\", \"Brand color in hex format (e.g., #6366f1)\")\n .action(async (options: InitOptions) => {\n await init(options);\n });\n}\n\nasync function init(options: InitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI\"));\n console.log(chalk.dim(\"Initializing your project...\"));\n console.log();\n\n const hasConfig = await configExists();\n\n // Run shadcn-vue init if no config exists\n if (!hasConfig) {\n console.log(chalk.blue(\"Running shadcn-vue init...\"));\n console.log();\n\n const args = [\"init\"];\n if (options.yes) args.push(\"--yes\");\n if (options.defaults) args.push(\"--defaults\");\n if (options.force) args.push(\"--force\");\n\n try {\n await spawnShadcn(args);\n } catch {\n console.log();\n console.log(chalk.red(\"Failed to initialize shadcn-vue.\"));\n console.log();\n console.log(chalk.yellow(\"Common issues:\"));\n console.log(chalk.dim(\" • Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss\"));\n console.log(chalk.dim(\" • Not in a Vue/Nuxt project root directory\"));\n console.log(chalk.dim(\" • Existing components.json with invalid config - try: npx @frontic/ui init --force\"));\n console.log();\n process.exit(1);\n }\n console.log();\n }\n\n // Get brand color\n let brandColor = DEFAULT_BRAND_COLOR;\n\n // Check if brand was provided via CLI flag\n if (options.brand) {\n if (isValidHex(options.brand)) {\n brandColor = hexToOklch(options.brand);\n console.log(chalk.dim(`Using brand color: ${options.brand} → ${brandColor}`));\n } else {\n console.log(chalk.yellow(`Invalid hex color: ${options.brand}, using default`));\n }\n } else if (!options.yes && !options.defaults) {\n // Prompt for brand color\n const response = await prompts([\n {\n type: \"text\",\n name: \"brand\",\n message: \"Brand color (hex, e.g., #6366f1)\",\n initial: \"#6366f1\",\n validate: (value: string) => {\n if (!value) return true; // Allow empty to use default\n return isValidHex(value) || \"Please enter a valid hex color (e.g., #6366f1)\";\n },\n },\n ]);\n\n if (response.brand && isValidHex(response.brand)) {\n brandColor = hexToOklch(response.brand);\n console.log(chalk.dim(`Converted: ${response.brand} → ${brandColor}`));\n }\n }\n\n // Calculate foreground color based on brand\n const brandForeground = getForegroundColor(brandColor);\n\n // Update components.json with Frontic registry\n const spinner = ora(\"Configuring Frontic registry...\").start();\n\n try {\n await updateConfig({\n registries: {\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n spinner.succeed(\"Frontic registry configured\");\n } catch (error) {\n spinner.fail(\"Failed to configure registry\");\n throw error;\n }\n\n // Install Frontic theme from registry\n const themeSpinner = ora(\"Installing Frontic theme...\").start();\n try {\n await spawnShadcn([\"add\", \"@frontic/theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Frontic theme installed\");\n } catch {\n themeSpinner.warn(\"Theme installation skipped (may already exist or registry not available)\");\n }\n\n // TODO: In future, inject brand color into user's CSS\n // For now, we log it so users know what to set\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\n console.log();\n console.log(chalk.dim(\"Your brand color:\"));\n console.log(` --brand: ${chalk.cyan(brandColor)}`);\n console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1. Add components:\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log();\n console.log(chalk.dim(\" 2. Customize your brand color in your CSS:\"));\n console.log(` ${chalk.cyan(\"--brand: \" + brandColor + \";\")}`);\n console.log();\n console.log(chalk.dim(\" 3. Set up MCP for AI assistants (optional):\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui mcp init\")}`);\n console.log();\n}\n","import { execa } from \"execa\";\n\ninterface SpawnOptions {\n silent?: boolean;\n}\n\nexport async function spawnShadcn(\n args: string[],\n options: SpawnOptions = {}\n): Promise<void> {\n const { silent = false } = options;\n\n try {\n await execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: silent ? \"pipe\" : \"inherit\",\n shell: true,\n });\n } catch (error) {\n if (!silent) {\n throw error;\n }\n // Silently ignore errors when silent mode is enabled\n }\n}\n","import { readFile, writeFile, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { CONFIG_FILE, FRONTIC_REGISTRY_URL } from \"./constants.js\";\n\nexport interface ComponentsConfig {\n $schema?: string;\n style?: string;\n typescript?: boolean;\n tailwind?: {\n css?: string;\n baseColor?: string;\n cssVariables?: boolean;\n };\n aliases?: {\n components?: string;\n utils?: string;\n ui?: string;\n lib?: string;\n composables?: string;\n };\n registries?: {\n [key: string]: {\n url: string;\n };\n };\n}\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(join(process.cwd(), CONFIG_FILE));\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<ComponentsConfig | null> {\n try {\n const content = await readFile(join(process.cwd(), CONFIG_FILE), \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(config: ComponentsConfig): Promise<void> {\n await writeFile(\n join(process.cwd(), CONFIG_FILE),\n JSON.stringify(config, null, 2)\n );\n}\n\nexport async function updateConfig(\n updates: Partial<ComponentsConfig>\n): Promise<void> {\n const existing = await readConfig();\n\n if (!existing) {\n throw new Error(\n \"components.json not found. Run `npx @frontic/ui init` first.\"\n );\n }\n\n const merged = deepMerge(existing, updates);\n await writeConfig(merged);\n}\n\nexport async function ensureFronticRegistry(): Promise<void> {\n const config = await readConfig();\n\n if (!config) {\n throw new Error(\"components.json not found\");\n }\n\n // Check if Frontic registry is already configured\n if (config.registries?.[\"@frontic\"]?.url === FRONTIC_REGISTRY_URL) {\n return;\n }\n\n // Add Frontic registry\n await updateConfig({\n registries: {\n ...config.registries,\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n}\n\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n","// Use FRONTIC_REGISTRY_LOCAL=1 to test with local registry\nexport const FRONTIC_REGISTRY_URL =\n process.env.FRONTIC_REGISTRY_LOCAL === \"1\"\n ? \"http://localhost:3333/r/{name}.json\"\n : \"https://registry.frontic.io/r/{name}.json\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n// Default brand color (purple - similar to Indigo 500)\nexport const DEFAULT_BRAND_COLOR = \"oklch(58% 0.25 265)\";\n","/**\n * Color conversion utilities for Frontic UI CLI\n * Converts hex colors to OKLCH format for CSS variables\n */\n\n/**\n * Validates a hex color string\n * Accepts formats: #RGB, #RRGGBB, RGB, RRGGBB\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = hex.replace(/^#/, \"\");\n return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);\n}\n\n/**\n * Normalizes a hex color to 6-character format without #\n */\nfunction normalizeHex(hex: string): string {\n const cleanHex = hex.replace(/^#/, \"\");\n if (cleanHex.length === 3) {\n return cleanHex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return cleanHex;\n}\n\n/**\n * Converts hex color to RGB values (0-255)\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalizedHex = normalizeHex(hex);\n return {\n r: parseInt(normalizedHex.slice(0, 2), 16),\n g: parseInt(normalizedHex.slice(2, 4), 16),\n b: parseInt(normalizedHex.slice(4, 6), 16),\n };\n}\n\n/**\n * Converts sRGB to linear RGB\n */\nfunction srgbToLinear(value: number): number {\n const normalized = value / 255;\n return normalized <= 0.04045\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts linear RGB to XYZ color space\n */\nfunction linearRgbToXyz(r: number, g: number, b: number): { x: number; y: number; z: number } {\n return {\n x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,\n y: 0.2126729 * r + 0.7151522 * g + 0.0721750 * b,\n z: 0.0193339 * r + 0.1191920 * g + 0.9503041 * b,\n };\n}\n\n/**\n * Converts XYZ to OKLAB color space\n */\nfunction xyzToOklab(x: number, y: number, z: number): { l: number; a: number; b: number } {\n const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);\n const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);\n const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);\n\n return {\n l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n };\n}\n\n/**\n * Converts OKLAB to OKLCH color space\n */\nfunction oklabToOklch(l: number, a: number, b: number): { l: number; c: number; h: number } {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) * (180 / Math.PI);\n if (h < 0) h += 360;\n\n return { l, c, h };\n}\n\n/**\n * Converts a hex color to OKLCH format string\n * @param hex - Hex color (e.g., \"#6366f1\" or \"6366f1\")\n * @returns OKLCH string (e.g., \"oklch(55% 0.24 265)\")\n */\nexport function hexToOklch(hex: string): string {\n if (!isValidHex(hex)) {\n throw new Error(`Invalid hex color: ${hex}`);\n }\n\n const { r, g, b } = hexToRgb(hex);\n\n // Convert to linear RGB\n const linearR = srgbToLinear(r);\n const linearG = srgbToLinear(g);\n const linearB = srgbToLinear(b);\n\n // Convert to XYZ\n const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);\n\n // Convert to OKLAB\n const oklab = xyzToOklab(x, y, z);\n\n // Convert to OKLCH\n const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);\n\n // Format as OKLCH string\n // Lightness as percentage, chroma with 2 decimals, hue as integer\n const lightness = Math.round(l * 100);\n const chroma = Math.round(c * 100) / 100;\n const hue = Math.round(h);\n\n return `oklch(${lightness}% ${chroma} ${hue})`;\n}\n\n/**\n * Calculates appropriate foreground color (black or white) based on background lightness\n * @param oklchOrHex - Either an OKLCH string or hex color\n * @returns OKLCH string for foreground (white or dark)\n */\nexport function getForegroundColor(oklchOrHex: string): string {\n let lightness: number;\n\n if (oklchOrHex.startsWith(\"oklch\")) {\n // Parse OKLCH string\n const match = oklchOrHex.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n } else {\n // Convert hex to get lightness\n const oklch = hexToOklch(oklchOrHex);\n const match = oklch.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n }\n\n // Use white foreground for dark backgrounds, dark for light backgrounds\n return lightness > 0.6 ? \"oklch(20% 0 0)\" : \"oklch(100% 0 0)\";\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { ensureFronticRegistry } from \"../utils/config.js\";\n\ninterface AddOptions {\n overwrite?: boolean;\n all?: boolean;\n path?: string;\n yes?: boolean;\n}\n\n/**\n * Resolves component names to their @frontic/ prefixed form.\n *\n * All components go through the Frontic registry proxy which:\n * - Serves Frontic components if available (theme, button, fancy-button, etc.)\n * - Proxies to shadcn-vue for all other components (card, dialog, etc.)\n *\n * This allows the proxy to control routing centrally without CLI updates.\n */\nfunction resolveComponentNames(components: string[]): string[] {\n return components.map((component) => {\n // Already has a registry prefix - leave as-is\n if (component.startsWith(\"@\")) {\n return component;\n }\n // Prefix with @frontic/ - proxy handles the routing\n return `@frontic/${component}`;\n });\n}\n\nexport function registerAddCommand(program: Command) {\n program\n .command(\"add\")\n .description(\"Add components to your project\")\n .argument(\"[components...]\", \"Components to add\")\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .option(\"-a, --all\", \"Add all available components\")\n .option(\"-p, --path <path>\", \"Custom installation path\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (components: string[], options: AddOptions) => {\n await add(components, options);\n });\n}\n\nasync function add(components: string[], options: AddOptions) {\n // Validate input\n if (!options.all && components.length === 0) {\n console.log(chalk.red(\"Error: Please specify components to add or use --all\"));\n console.log();\n console.log(\"Usage:\");\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button dialog card\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add --all\")}`);\n process.exit(1);\n }\n\n // Ensure Frontic registry is configured\n const spinner = ora(\"Checking configuration...\").start();\n try {\n await ensureFronticRegistry();\n spinner.succeed(\"Configuration verified\");\n } catch {\n spinner.fail(\"Configuration error\");\n console.log();\n console.log(chalk.yellow(\"Run `npx @frontic/ui init` first to set up your project.\"));\n process.exit(1);\n }\n\n // Resolve component names (prefix with @frontic/ for proxy routing)\n const resolvedComponents = resolveComponentNames(components);\n\n // Show what we're adding\n if (resolvedComponents.length > 0) {\n console.log(\n chalk.cyan(\"Components:\"),\n resolvedComponents.map((c) => c.replace(\"@frontic/\", \"\")).join(\", \")\n );\n }\n\n // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...resolvedComponents);\n }\n\n if (options.overwrite) {\n args.push(\"--overwrite\");\n }\n\n if (options.path) {\n args.push(\"--path\", options.path);\n }\n\n if (options.yes) {\n args.push(\"--yes\");\n }\n\n console.log();\n console.log(chalk.blue(\"Adding components...\"));\n console.log();\n\n // Run shadcn-vue add\n await spawnShadcn(args);\n\n console.log();\n console.log(chalk.green(\"✓ Components added successfully!\"));\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile, readFile, mkdir } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport prompts from \"prompts\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ntype McpClient = \"claude\" | \"cursor\" | \"vscode\";\n\ninterface McpInitOptions {\n client?: McpClient;\n}\n\nexport function registerMcpCommand(program: Command) {\n const mcp = program\n .command(\"mcp\")\n .description(\"MCP (Model Context Protocol) commands\");\n\n mcp\n .command(\"init\")\n .description(\"Set up MCP for AI assistants\")\n .option(\"-c, --client <client>\", \"Target client (claude, cursor, vscode)\")\n .action(async (options: McpInitOptions) => {\n await initMcp(options);\n });\n}\n\nasync function initMcp(options: McpInitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI - MCP Setup\"));\n console.log(chalk.dim(\"Configure AI assistant integration\"));\n console.log();\n\n let client = options.client as McpClient | undefined;\n\n // Prompt for client if not specified\n if (!client) {\n const response = await prompts({\n type: \"select\",\n name: \"client\",\n message: \"Select your AI client:\",\n choices: [\n { title: \"Claude Code\", value: \"claude\" },\n { title: \"Cursor\", value: \"cursor\" },\n { title: \"VS Code\", value: \"vscode\" },\n ],\n });\n\n client = response.client;\n\n if (!client) {\n console.log(chalk.yellow(\"Setup cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Creating MCP configuration...\").start();\n\n try {\n await createMcpConfig(client);\n spinner.succeed(\"MCP configuration created\");\n } catch (error) {\n spinner.fail(\"Failed to create MCP configuration\");\n throw error;\n }\n\n console.log();\n console.log(chalk.green(\"✓ MCP configured successfully!\"));\n console.log();\n console.log(\"Your AI assistant can now:\");\n console.log(chalk.dim(\" • Browse available Frontic UI components\"));\n console.log(chalk.dim(\" • Add components using natural language\"));\n console.log(chalk.dim(' • Example: \"Add a button component\"'));\n console.log();\n}\n\nasync function createMcpConfig(client: McpClient) {\n const config = getMcpConfig();\n const configPath = getMcpConfigPath(client);\n const configDir = join(process.cwd(), configPath.split(\"/\").slice(0, -1).join(\"/\"));\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n await mkdir(configDir, { recursive: true });\n }\n\n const fullPath = join(process.cwd(), configPath);\n\n // Read existing config or create new\n let existingConfig: Record<string, unknown> = {};\n try {\n const content = await readFile(fullPath, \"utf-8\");\n existingConfig = JSON.parse(content);\n } catch {\n // File doesn't exist, use empty config\n }\n\n // Merge with existing config\n const mergedConfig = {\n ...existingConfig,\n mcpServers: {\n ...(existingConfig.mcpServers as Record<string, unknown> || {}),\n ...config.mcpServers,\n },\n };\n\n await writeFile(fullPath, JSON.stringify(mergedConfig, null, 2));\n\n console.log(chalk.dim(` Config written to: ${configPath}`));\n}\n\nfunction getMcpConfigPath(client: McpClient): string {\n switch (client) {\n case \"claude\":\n return \".mcp.json\";\n case \"cursor\":\n return \".cursor/mcp.json\";\n case \"vscode\":\n return \".vscode/mcp.json\";\n }\n}\n\nfunction getMcpConfig() {\n return {\n mcpServers: {\n \"frontic-ui\": {\n command: \"npx\",\n args: [\"shadcn-vue@latest\", \"mcp\"],\n env: {\n SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL,\n },\n },\n },\n };\n}\n"],"mappings":";AAAA,SAAS,eAAe;;;ACCxB,OAAO,WAAW;AAClB,OAAO,SAAS;AAChB,OAAO,aAAa;;;ACHpB,SAAS,aAAa;AAMtB,eAAsB,YACpB,MACA,UAAwB,CAAC,GACV;AACf,QAAM,EAAE,SAAS,MAAM,IAAI;AAE3B,MAAI;AACF,UAAM,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,GAAG;AAAA,MACjD,OAAO,SAAS,SAAS;AAAA,MACzB,OAAO;AAAA,IACT,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,CAAC,QAAQ;AACX,YAAM;AAAA,IACR;AAAA,EAEF;AACF;;;ACvBA,SAAS,UAAU,WAAW,cAAc;AAC5C,SAAS,YAAY;;;ACAd,IAAM,uBACX,QAAQ,IAAI,2BAA2B,MACnC,wCACA;AAEC,IAAM,cAAc;AAGpB,IAAM,sBAAsB;;;ADkBnC,eAAsB,eAAiC;AACrD,MAAI;AACF,UAAM,OAAO,KAAK,QAAQ,IAAI,GAAG,WAAW,CAAC;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,aAA+C;AACnE,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,KAAK,QAAQ,IAAI,GAAG,WAAW,GAAG,OAAO;AACxE,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,YAAY,QAAyC;AACzE,QAAM;AAAA,IACJ,KAAK,QAAQ,IAAI,GAAG,WAAW;AAAA,IAC/B,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EAChC;AACF;AAEA,eAAsB,aACpB,SACe;AACf,QAAM,WAAW,MAAM,WAAW;AAElC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,UAAU,UAAU,OAAO;AAC1C,QAAM,YAAY,MAAM;AAC1B;AAEA,eAAsB,wBAAuC;AAC3D,QAAM,SAAS,MAAM,WAAW;AAEhC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AAGA,MAAI,OAAO,aAAa,UAAU,GAAG,QAAQ,sBAAsB;AACjE;AAAA,EACF;AAGA,QAAM,aAAa;AAAA,IACjB,YAAY;AAAA,MACV,GAAG,OAAO;AAAA,MACV,YAAY;AAAA,QACV,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,UAA4B,QAAW,QAAuB;AACrE,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,QAAQ;AACxB,UAAM,cAAc,OAAO,GAAG;AAC9B,UAAM,cAAc,OAAO,GAAG;AAE9B,QACE,eACA,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,KAC1B,eACA,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,GAC1B;AACA,MAAC,OAAmC,GAAG,IAAI;AAAA,QACzC;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,MAAC,OAAmC,GAAG,IAAI;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AACT;;;AE1GO,SAAS,WAAW,KAAsB;AAC/C,QAAM,WAAW,IAAI,QAAQ,MAAM,EAAE;AACrC,SAAO,oCAAoC,KAAK,QAAQ;AAC1D;AAKA,SAAS,aAAa,KAAqB;AACzC,QAAM,WAAW,IAAI,QAAQ,MAAM,EAAE;AACrC,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,SACJ,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,IAAI,CAAC,EAChB,KAAK,EAAE;AAAA,EACZ;AACA,SAAO;AACT;AAKA,SAAS,SAAS,KAAkD;AAClE,QAAM,gBAAgB,aAAa,GAAG;AACtC,SAAO;AAAA,IACL,GAAG,SAAS,cAAc,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACzC,GAAG,SAAS,cAAc,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACzC,GAAG,SAAS,cAAc,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EAC3C;AACF;AAKA,SAAS,aAAa,OAAuB;AAC3C,QAAM,aAAa,QAAQ;AAC3B,SAAO,cAAc,UACjB,aAAa,QACb,KAAK,KAAK,aAAa,SAAS,OAAO,GAAG;AAChD;AAKA,SAAS,eAAe,GAAW,GAAW,GAAgD;AAC5F,SAAO;AAAA,IACL,GAAG,YAAY,IAAI,YAAY,IAAI,YAAY;AAAA,IAC/C,GAAG,YAAY,IAAI,YAAY,IAAI,WAAY;AAAA,IAC/C,GAAG,YAAY,IAAI,WAAY,IAAI,YAAY;AAAA,EACjD;AACF;AAKA,SAAS,WAAW,GAAW,GAAW,GAAgD;AACxF,QAAM,KAAK,KAAK,KAAK,eAAe,IAAI,eAAe,IAAI,eAAe,CAAC;AAC3E,QAAM,KAAK,KAAK,KAAK,eAAe,IAAI,eAAe,IAAI,eAAe,CAAC;AAC3E,QAAM,KAAK,KAAK,KAAK,gBAAgB,IAAI,eAAe,IAAI,cAAe,CAAC;AAE5E,SAAO;AAAA,IACL,GAAG,eAAe,KAAK,cAAe,KAAK,eAAe;AAAA,IAC1D,GAAG,eAAe,KAAK,cAAe,KAAK,eAAe;AAAA,IAC1D,GAAG,eAAe,KAAK,eAAe,KAAK,cAAe;AAAA,EAC5D;AACF;AAKA,SAAS,aAAa,GAAW,GAAW,GAAgD;AAC1F,QAAM,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC;AACjC,MAAI,IAAI,KAAK,MAAM,GAAG,CAAC,KAAK,MAAM,KAAK;AACvC,MAAI,IAAI,EAAG,MAAK;AAEhB,SAAO,EAAE,GAAG,GAAG,EAAE;AACnB;AAOO,SAAS,WAAW,KAAqB;AAC9C,MAAI,CAAC,WAAW,GAAG,GAAG;AACpB,UAAM,IAAI,MAAM,sBAAsB,GAAG,EAAE;AAAA,EAC7C;AAEA,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,SAAS,GAAG;AAGhC,QAAM,UAAU,aAAa,CAAC;AAC9B,QAAM,UAAU,aAAa,CAAC;AAC9B,QAAM,UAAU,aAAa,CAAC;AAG9B,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,eAAe,SAAS,SAAS,OAAO;AAG5D,QAAM,QAAQ,WAAW,GAAG,GAAG,CAAC;AAGhC,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,aAAa,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAI1D,QAAM,YAAY,KAAK,MAAM,IAAI,GAAG;AACpC,QAAM,SAAS,KAAK,MAAM,IAAI,GAAG,IAAI;AACrC,QAAM,MAAM,KAAK,MAAM,CAAC;AAExB,SAAO,SAAS,SAAS,KAAK,MAAM,IAAI,GAAG;AAC7C;AAOO,SAAS,mBAAmB,YAA4B;AAC7D,MAAI;AAEJ,MAAI,WAAW,WAAW,OAAO,GAAG;AAElC,UAAM,QAAQ,WAAW,MAAM,eAAe;AAC9C,gBAAY,QAAQ,CAAC,IAAI,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI,MAAM;AAAA,EAC1D,OAAO;AAEL,UAAM,QAAQ,WAAW,UAAU;AACnC,UAAM,QAAQ,MAAM,MAAM,eAAe;AACzC,gBAAY,QAAQ,CAAC,IAAI,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI,MAAM;AAAA,EAC1D;AAGA,SAAO,YAAY,MAAM,mBAAmB;AAC9C;;;AJ/HO,SAAS,oBAAoBA,UAAkB;AACpD,EAAAA,SACG,QAAQ,MAAM,EACd,YAAY,2CAA2C,EACvD,OAAO,aAAa,2BAA2B,EAC/C,OAAO,kBAAkB,2BAA2B,EACpD,OAAO,eAAe,2CAA2C,EACjE,OAAO,uBAAuB,2CAA2C,EACzE,OAAO,OAAO,YAAyB;AACtC,UAAM,KAAK,OAAO;AAAA,EACpB,CAAC;AACL;AAEA,eAAe,KAAK,SAAsB;AACxC,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,KAAK,YAAY,CAAC;AACpC,UAAQ,IAAI,MAAM,IAAI,8BAA8B,CAAC;AACrD,UAAQ,IAAI;AAEZ,QAAM,YAAY,MAAM,aAAa;AAGrC,MAAI,CAAC,WAAW;AACd,YAAQ,IAAI,MAAM,KAAK,4BAA4B,CAAC;AACpD,YAAQ,IAAI;AAEZ,UAAM,OAAO,CAAC,MAAM;AACpB,QAAI,QAAQ,IAAK,MAAK,KAAK,OAAO;AAClC,QAAI,QAAQ,SAAU,MAAK,KAAK,YAAY;AAC5C,QAAI,QAAQ,MAAO,MAAK,KAAK,SAAS;AAEtC,QAAI;AACF,YAAM,YAAY,IAAI;AAAA,IACxB,QAAQ;AACN,cAAQ,IAAI;AACZ,cAAQ,IAAI,MAAM,IAAI,kCAAkC,CAAC;AACzD,cAAQ,IAAI;AACZ,cAAQ,IAAI,MAAM,OAAO,gBAAgB,CAAC;AAC1C,cAAQ,IAAI,MAAM,IAAI,oFAA+E,CAAC;AACtG,cAAQ,IAAI,MAAM,IAAI,mDAA8C,CAAC;AACrE,cAAQ,IAAI,MAAM,IAAI,2FAAsF,CAAC;AAC7G,cAAQ,IAAI;AACZ,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,IAAI;AAAA,EACd;AAGA,MAAI,aAAa;AAGjB,MAAI,QAAQ,OAAO;AACjB,QAAI,WAAW,QAAQ,KAAK,GAAG;AAC7B,mBAAa,WAAW,QAAQ,KAAK;AACrC,cAAQ,IAAI,MAAM,IAAI,sBAAsB,QAAQ,KAAK,WAAM,UAAU,EAAE,CAAC;AAAA,IAC9E,OAAO;AACL,cAAQ,IAAI,MAAM,OAAO,sBAAsB,QAAQ,KAAK,iBAAiB,CAAC;AAAA,IAChF;AAAA,EACF,WAAW,CAAC,QAAQ,OAAO,CAAC,QAAQ,UAAU;AAE5C,UAAM,WAAW,MAAM,QAAQ;AAAA,MAC7B;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU,CAAC,UAAkB;AAC3B,cAAI,CAAC,MAAO,QAAO;AACnB,iBAAO,WAAW,KAAK,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,SAAS,SAAS,WAAW,SAAS,KAAK,GAAG;AAChD,mBAAa,WAAW,SAAS,KAAK;AACtC,cAAQ,IAAI,MAAM,IAAI,cAAc,SAAS,KAAK,WAAM,UAAU,EAAE,CAAC;AAAA,IACvE;AAAA,EACF;AAGA,QAAM,kBAAkB,mBAAmB,UAAU;AAGrD,QAAM,UAAU,IAAI,iCAAiC,EAAE,MAAM;AAE7D,MAAI;AACF,UAAM,aAAa;AAAA,MACjB,YAAY;AAAA,QACV,YAAY;AAAA,UACV,KAAK;AAAA,QACP;AAAA,MACF;AAAA,IACF,CAAC;AACD,YAAQ,QAAQ,6BAA6B;AAAA,EAC/C,SAAS,OAAO;AACd,YAAQ,KAAK,8BAA8B;AAC3C,UAAM;AAAA,EACR;AAGA,QAAM,eAAe,IAAI,6BAA6B,EAAE,MAAM;AAC9D,MAAI;AACF,UAAM,YAAY,CAAC,OAAO,kBAAkB,OAAO,GAAG,EAAE,QAAQ,KAAK,CAAC;AACtE,iBAAa,QAAQ,yBAAyB;AAAA,EAChD,QAAQ;AACN,iBAAa,KAAK,0EAA0E;AAAA,EAC9F;AAIA,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,MAAM,6CAAwC,CAAC;AACjE,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,IAAI,mBAAmB,CAAC;AAC1C,UAAQ,IAAI,cAAc,MAAM,KAAK,UAAU,CAAC,EAAE;AAClD,UAAQ,IAAI,yBAAyB,MAAM,KAAK,eAAe,CAAC,EAAE;AAClE,UAAQ,IAAI;AACZ,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI,MAAM,IAAI,sBAAsB,CAAC;AAC7C,UAAQ,IAAI,QAAQ,MAAM,KAAK,4BAA4B,CAAC,EAAE;AAC9D,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,IAAI,8CAA8C,CAAC;AACrE,UAAQ,IAAI,QAAQ,MAAM,KAAK,cAAc,aAAa,GAAG,CAAC,EAAE;AAChE,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,IAAI,+CAA+C,CAAC;AACtE,UAAQ,IAAI,QAAQ,MAAM,KAAK,0BAA0B,CAAC,EAAE;AAC5D,UAAQ,IAAI;AACd;;;AK9IA,OAAOC,YAAW;AAClB,OAAOC,UAAS;AAoBhB,SAAS,sBAAsB,YAAgC;AAC7D,SAAO,WAAW,IAAI,CAAC,cAAc;AAEnC,QAAI,UAAU,WAAW,GAAG,GAAG;AAC7B,aAAO;AAAA,IACT;AAEA,WAAO,YAAY,SAAS;AAAA,EAC9B,CAAC;AACH;AAEO,SAAS,mBAAmBC,UAAkB;AACnD,EAAAA,SACG,QAAQ,KAAK,EACb,YAAY,gCAAgC,EAC5C,SAAS,mBAAmB,mBAAmB,EAC/C,OAAO,mBAAmB,0BAA0B,EACpD,OAAO,aAAa,8BAA8B,EAClD,OAAO,qBAAqB,0BAA0B,EACtD,OAAO,aAAa,2BAA2B,EAC/C,OAAO,OAAO,YAAsB,YAAwB;AAC3D,UAAM,IAAI,YAAY,OAAO;AAAA,EAC/B,CAAC;AACL;AAEA,eAAe,IAAI,YAAsB,SAAqB;AAE5D,MAAI,CAAC,QAAQ,OAAO,WAAW,WAAW,GAAG;AAC3C,YAAQ,IAAIC,OAAM,IAAI,sDAAsD,CAAC;AAC7E,YAAQ,IAAI;AACZ,YAAQ,IAAI,QAAQ;AACpB,YAAQ,IAAI,KAAKA,OAAM,KAAK,4BAA4B,CAAC,EAAE;AAC3D,YAAQ,IAAI,KAAKA,OAAM,KAAK,wCAAwC,CAAC,EAAE;AACvE,YAAQ,IAAI,KAAKA,OAAM,KAAK,2BAA2B,CAAC,EAAE;AAC1D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAUC,KAAI,2BAA2B,EAAE,MAAM;AACvD,MAAI;AACF,UAAM,sBAAsB;AAC5B,YAAQ,QAAQ,wBAAwB;AAAA,EAC1C,QAAQ;AACN,YAAQ,KAAK,qBAAqB;AAClC,YAAQ,IAAI;AACZ,YAAQ,IAAID,OAAM,OAAO,0DAA0D,CAAC;AACpF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,qBAAqB,sBAAsB,UAAU;AAG3D,MAAI,mBAAmB,SAAS,GAAG;AACjC,YAAQ;AAAA,MACNA,OAAM,KAAK,aAAa;AAAA,MACxB,mBAAmB,IAAI,CAAC,MAAM,EAAE,QAAQ,aAAa,EAAE,CAAC,EAAE,KAAK,IAAI;AAAA,IACrE;AAAA,EACF;AAGA,QAAM,OAAO,CAAC,KAAK;AAEnB,MAAI,QAAQ,KAAK;AACf,SAAK,KAAK,OAAO;AAAA,EACnB,OAAO;AACL,SAAK,KAAK,GAAG,kBAAkB;AAAA,EACjC;AAEA,MAAI,QAAQ,WAAW;AACrB,SAAK,KAAK,aAAa;AAAA,EACzB;AAEA,MAAI,QAAQ,MAAM;AAChB,SAAK,KAAK,UAAU,QAAQ,IAAI;AAAA,EAClC;AAEA,MAAI,QAAQ,KAAK;AACf,SAAK,KAAK,OAAO;AAAA,EACnB;AAEA,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,sBAAsB,CAAC;AAC9C,UAAQ,IAAI;AAGZ,QAAM,YAAY,IAAI;AAEtB,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,MAAM,uCAAkC,CAAC;AAC7D;;;AC/GA,OAAOE,YAAW;AAClB,OAAOC,UAAS;AAChB,SAAS,aAAAC,YAAW,YAAAC,WAAU,aAAa;AAC3C,SAAS,kBAAkB;AAC3B,SAAS,QAAAC,aAAY;AACrB,OAAOC,cAAa;AASb,SAAS,mBAAmBC,UAAkB;AACnD,QAAM,MAAMA,SACT,QAAQ,KAAK,EACb,YAAY,uCAAuC;AAEtD,MACG,QAAQ,MAAM,EACd,YAAY,8BAA8B,EAC1C,OAAO,yBAAyB,wCAAwC,EACxE,OAAO,OAAO,YAA4B;AACzC,UAAM,QAAQ,OAAO;AAAA,EACvB,CAAC;AACL;AAEA,eAAe,QAAQ,SAAyB;AAC9C,UAAQ,IAAI;AACZ,UAAQ,IAAIC,OAAM,KAAK,wBAAwB,CAAC;AAChD,UAAQ,IAAIA,OAAM,IAAI,oCAAoC,CAAC;AAC3D,UAAQ,IAAI;AAEZ,MAAI,SAAS,QAAQ;AAGrB,MAAI,CAAC,QAAQ;AACX,UAAM,WAAW,MAAMC,SAAQ;AAAA,MAC7B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,OAAO,eAAe,OAAO,SAAS;AAAA,QACxC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,QACnC,EAAE,OAAO,WAAW,OAAO,SAAS;AAAA,MACtC;AAAA,IACF,CAAC;AAED,aAAS,SAAS;AAElB,QAAI,CAAC,QAAQ;AACX,cAAQ,IAAID,OAAM,OAAO,kBAAkB,CAAC;AAC5C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAUE,KAAI,+BAA+B,EAAE,MAAM;AAE3D,MAAI;AACF,UAAM,gBAAgB,MAAM;AAC5B,YAAQ,QAAQ,2BAA2B;AAAA,EAC7C,SAAS,OAAO;AACd,YAAQ,KAAK,oCAAoC;AACjD,UAAM;AAAA,EACR;AAEA,UAAQ,IAAI;AACZ,UAAQ,IAAIF,OAAM,MAAM,qCAAgC,CAAC;AACzD,UAAQ,IAAI;AACZ,UAAQ,IAAI,4BAA4B;AACxC,UAAQ,IAAIA,OAAM,IAAI,iDAA4C,CAAC;AACnE,UAAQ,IAAIA,OAAM,IAAI,gDAA2C,CAAC;AAClE,UAAQ,IAAIA,OAAM,IAAI,4CAAuC,CAAC;AAC9D,UAAQ,IAAI;AACd;AAEA,eAAe,gBAAgB,QAAmB;AAChD,QAAM,SAAS,aAAa;AAC5B,QAAM,aAAa,iBAAiB,MAAM;AAC1C,QAAM,YAAYG,MAAK,QAAQ,IAAI,GAAG,WAAW,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC;AAGlF,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC5C;AAEA,QAAM,WAAWA,MAAK,QAAQ,IAAI,GAAG,UAAU;AAG/C,MAAI,iBAA0C,CAAC;AAC/C,MAAI;AACF,UAAM,UAAU,MAAMC,UAAS,UAAU,OAAO;AAChD,qBAAiB,KAAK,MAAM,OAAO;AAAA,EACrC,QAAQ;AAAA,EAER;AAGA,QAAM,eAAe;AAAA,IACnB,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAI,eAAe,cAAyC,CAAC;AAAA,MAC7D,GAAG,OAAO;AAAA,IACZ;AAAA,EACF;AAEA,QAAMC,WAAU,UAAU,KAAK,UAAU,cAAc,MAAM,CAAC,CAAC;AAE/D,UAAQ,IAAIL,OAAM,IAAI,wBAAwB,UAAU,EAAE,CAAC;AAC7D;AAEA,SAAS,iBAAiB,QAA2B;AACnD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAAS,eAAe;AACtB,SAAO;AAAA,IACL,YAAY;AAAA,MACV,cAAc;AAAA,QACZ,SAAS;AAAA,QACT,MAAM,CAAC,qBAAqB,KAAK;AAAA,QACjC,KAAK;AAAA,UACH,qBAAqB;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;APnIA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,YAAY,EACjB,YAAY,0DAA0D,EACtE,QAAQ,OAAO;AAElB,oBAAoB,OAAO;AAC3B,mBAAmB,OAAO;AAC1B,mBAAmB,OAAO;AAEnB,SAAS,MAAM;AACpB,UAAQ,MAAM;AAChB;","names":["program","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/spawn-shadcn.ts","../src/utils/config.ts","../src/utils/constants.ts","../src/utils/colors.ts","../src/utils/css.ts","../src/commands/add.ts","../src/commands/mcp.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerAddCommand } from \"./commands/add.js\";\nimport { registerMcpCommand } from \"./commands/mcp.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"frontic-ui\")\n .description(\"CLI for adding Frontic UI components to your Nuxt project\")\n .version(\"0.3.1\");\n\nregisterInitCommand(program);\nregisterAddCommand(program);\nregisterMcpCommand(program);\n\nexport function run() {\n program.parse();\n}\n\nexport { program };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport { join } from \"path\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists, readConfig } from \"../utils/config.js\";\nimport {\n FRONTIC_REGISTRY_URL,\n DEFAULT_BRAND_COLOR,\n DEFAULT_RADIUS,\n RADIUS_OPTIONS,\n type RadiusOption,\n} from \"../utils/constants.js\";\nimport { hexToOklch, isValidHex, getForegroundColor } from \"../utils/colors.js\";\nimport { injectCssVars } from \"../utils/css.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\n force?: boolean;\n brand?: string;\n radius?: string;\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Frontic UI in your Nuxt project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"-d, --defaults\", \"Use default configuration\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\"-b, --brand <color>\", \"Brand color in hex format (e.g., #6366f1)\")\n .option(\n \"-r, --radius <option>\",\n \"Border radius (none, small, medium, large, full)\"\n )\n .action(async (options: InitOptions) => {\n await init(options);\n });\n}\n\nasync function init(options: InitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI\"));\n console.log(chalk.dim(\"Initializing your project...\"));\n console.log();\n\n const hasConfig = await configExists();\n\n // Collect preferences BEFORE running shadcn-vue init\n let brandColor = DEFAULT_BRAND_COLOR;\n let radiusValue = DEFAULT_RADIUS;\n\n if (!hasConfig) {\n // Get brand color from CLI flag or prompt\n if (options.brand) {\n if (isValidHex(options.brand)) {\n brandColor = hexToOklch(options.brand);\n console.log(\n chalk.dim(`Using brand color: ${options.brand} → ${brandColor}`)\n );\n } else {\n console.log(\n chalk.yellow(`Invalid hex color: ${options.brand}, using default`)\n );\n }\n }\n\n // Get radius from CLI flag or validate it\n if (options.radius) {\n const radiusKey = options.radius.toLowerCase() as RadiusOption;\n if (radiusKey in RADIUS_OPTIONS) {\n radiusValue = RADIUS_OPTIONS[radiusKey];\n console.log(chalk.dim(`Using border radius: ${options.radius}`));\n } else {\n console.log(\n chalk.yellow(\n `Invalid radius option: ${options.radius}, using default (medium)`\n )\n );\n }\n }\n\n // Interactive prompts if not using --yes or --defaults\n if (!options.yes && !options.defaults) {\n const response = await prompts([\n {\n type: options.brand ? null : \"text\",\n name: \"brand\",\n message: \"Brand color (hex, e.g., #6366f1)\",\n initial: \"#6366f1\",\n validate: (value: string) => {\n if (!value) return true;\n return (\n isValidHex(value) ||\n \"Please enter a valid hex color (e.g., #6366f1)\"\n );\n },\n },\n {\n type: options.radius ? null : \"select\",\n name: \"radius\",\n message: \"Border radius\",\n choices: [\n { title: \"None\", value: \"none\" },\n { title: \"Small\", value: \"small\" },\n { title: \"Medium (recommended)\", value: \"medium\" },\n { title: \"Large\", value: \"large\" },\n { title: \"Full\", value: \"full\" },\n ],\n initial: 2,\n },\n ]);\n\n if (response.brand && isValidHex(response.brand)) {\n brandColor = hexToOklch(response.brand);\n console.log(chalk.dim(`Converted: ${response.brand} → ${brandColor}`));\n }\n\n if (response.radius) {\n radiusValue = RADIUS_OPTIONS[response.radius as RadiusOption];\n }\n }\n\n // Now run shadcn-vue init with output filtering\n console.log();\n console.log(chalk.blue(\"Setting up your project...\"));\n console.log();\n\n const args = [\"init\"];\n if (options.yes) args.push(\"--yes\");\n if (options.defaults) args.push(\"--defaults\");\n if (options.force) args.push(\"--force\");\n\n try {\n await spawnShadcn(args, { filterOutput: true });\n } catch {\n console.log();\n console.log(chalk.red(\"Failed to initialize project.\"));\n console.log();\n console.log(chalk.yellow(\"Common issues:\"));\n console.log(\n chalk.dim(\n \" • Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss\"\n )\n );\n console.log(chalk.dim(\" • Not in a Vue/Nuxt project root directory\"));\n console.log(\n chalk.dim(\n \" • Existing components.json with invalid config - try: npx @frontic/ui init --force\"\n )\n );\n console.log();\n process.exit(1);\n }\n console.log();\n }\n\n // Calculate foreground color based on brand\n const brandForeground = getForegroundColor(brandColor);\n\n // Read config to get CSS file path\n const config = await readConfig();\n const cssPath = config?.tailwind?.css;\n\n // Inject CSS variables into the user's CSS file\n if (cssPath) {\n const cssSpinner = ora(\"Injecting theme variables...\").start();\n try {\n const fullCssPath = join(process.cwd(), cssPath);\n await injectCssVars(fullCssPath, {\n brand: brandColor,\n brandForeground: brandForeground,\n radius: radiusValue,\n });\n cssSpinner.succeed(\"Theme variables injected\");\n } catch {\n cssSpinner.warn(\n \"Could not inject theme variables (you may need to add them manually)\"\n );\n }\n }\n\n // Update components.json with Frontic registry\n const spinner = ora(\"Configuring Frontic registry...\").start();\n\n try {\n await updateConfig({\n registries: {\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n spinner.succeed(\"Frontic registry configured\");\n } catch (error) {\n spinner.fail(\"Failed to configure registry\");\n throw error;\n }\n\n // Install Frontic theme from registry\n const themeSpinner = ora(\"Installing Frontic theme...\").start();\n try {\n await spawnShadcn([\"add\", \"@frontic/theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Frontic theme installed\");\n } catch {\n themeSpinner.warn(\n \"Theme installation skipped (may already exist or registry not available)\"\n );\n }\n\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\n console.log();\n console.log(chalk.dim(\"Your theme settings:\"));\n console.log(` --brand: ${chalk.cyan(brandColor)}`);\n console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);\n console.log(` --radius: ${chalk.cyan(radiusValue)}`);\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1. Add components:\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log();\n console.log(chalk.dim(\" 2. Set up MCP for AI assistants (optional):\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui mcp init\")}`);\n console.log();\n}\n","import { execa } from \"execa\";\n\ninterface SpawnOptions {\n silent?: boolean;\n filterOutput?: boolean;\n}\n\nexport async function spawnShadcn(\n args: string[],\n options: SpawnOptions = {}\n): Promise<void> {\n const { silent = false, filterOutput = false } = options;\n\n try {\n if (filterOutput) {\n // Capture output, replace \"shadcn-vue\" → \"frontic-ui\", forward to stdout\n const proc = execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: [\"inherit\", \"pipe\", \"pipe\"],\n shell: true,\n });\n\n proc.stdout?.on(\"data\", (data: Buffer) => {\n process.stdout.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n proc.stderr?.on(\"data\", (data: Buffer) => {\n process.stderr.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n await proc;\n } else {\n await execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: silent ? \"pipe\" : \"inherit\",\n shell: true,\n });\n }\n } catch (error) {\n if (!silent) {\n throw error;\n }\n // Silently ignore errors when silent mode is enabled\n }\n}\n","import { readFile, writeFile, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { CONFIG_FILE, FRONTIC_REGISTRY_URL } from \"./constants.js\";\n\nexport interface ComponentsConfig {\n $schema?: string;\n style?: string;\n typescript?: boolean;\n tailwind?: {\n css?: string;\n baseColor?: string;\n cssVariables?: boolean;\n };\n aliases?: {\n components?: string;\n utils?: string;\n ui?: string;\n lib?: string;\n composables?: string;\n };\n registries?: {\n [key: string]: {\n url: string;\n };\n };\n}\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(join(process.cwd(), CONFIG_FILE));\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<ComponentsConfig | null> {\n try {\n const content = await readFile(join(process.cwd(), CONFIG_FILE), \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(config: ComponentsConfig): Promise<void> {\n await writeFile(\n join(process.cwd(), CONFIG_FILE),\n JSON.stringify(config, null, 2)\n );\n}\n\nexport async function updateConfig(\n updates: Partial<ComponentsConfig>\n): Promise<void> {\n const existing = await readConfig();\n\n if (!existing) {\n throw new Error(\n \"components.json not found. Run `npx @frontic/ui init` first.\"\n );\n }\n\n const merged = deepMerge(existing, updates);\n await writeConfig(merged);\n}\n\nexport async function ensureFronticRegistry(): Promise<void> {\n const config = await readConfig();\n\n if (!config) {\n throw new Error(\"components.json not found\");\n }\n\n // Check if Frontic registry is already configured\n if (config.registries?.[\"@frontic\"]?.url === FRONTIC_REGISTRY_URL) {\n return;\n }\n\n // Add Frontic registry\n await updateConfig({\n registries: {\n ...config.registries,\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n}\n\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n","// Use FRONTIC_REGISTRY_LOCAL=1 to test with local registry\nexport const FRONTIC_REGISTRY_URL =\n process.env.FRONTIC_REGISTRY_LOCAL === \"1\"\n ? \"http://localhost:3333/r/{name}.json\"\n : \"https://registry.frontic.io/r/{name}.json\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n// Default brand color (purple - similar to Indigo 500)\nexport const DEFAULT_BRAND_COLOR = \"oklch(58% 0.25 265)\";\n\n// Default radius (medium)\nexport const DEFAULT_RADIUS = \"0.5rem\";\n\n// Radius options for CLI prompt\n// These are base values for --radius. The derived Tailwind vars (--radius-sm, etc.)\n// are calculated by shadcn's @theme inline block using calc() offsets.\nexport const RADIUS_OPTIONS = {\n none: \"0\",\n small: \"0.3rem\",\n medium: \"0.5rem\",\n large: \"0.75rem\",\n full: \"1rem\",\n} as const;\n\nexport type RadiusOption = keyof typeof RADIUS_OPTIONS;\n","/**\n * Color conversion utilities for Frontic UI CLI\n * Converts hex colors to OKLCH format for CSS variables\n */\n\n/**\n * Validates a hex color string\n * Accepts formats: #RGB, #RRGGBB, RGB, RRGGBB\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = hex.replace(/^#/, \"\");\n return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);\n}\n\n/**\n * Normalizes a hex color to 6-character format without #\n */\nfunction normalizeHex(hex: string): string {\n const cleanHex = hex.replace(/^#/, \"\");\n if (cleanHex.length === 3) {\n return cleanHex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return cleanHex;\n}\n\n/**\n * Converts hex color to RGB values (0-255)\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalizedHex = normalizeHex(hex);\n return {\n r: parseInt(normalizedHex.slice(0, 2), 16),\n g: parseInt(normalizedHex.slice(2, 4), 16),\n b: parseInt(normalizedHex.slice(4, 6), 16),\n };\n}\n\n/**\n * Converts sRGB to linear RGB\n */\nfunction srgbToLinear(value: number): number {\n const normalized = value / 255;\n return normalized <= 0.04045\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts linear RGB to XYZ color space\n */\nfunction linearRgbToXyz(r: number, g: number, b: number): { x: number; y: number; z: number } {\n return {\n x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,\n y: 0.2126729 * r + 0.7151522 * g + 0.0721750 * b,\n z: 0.0193339 * r + 0.1191920 * g + 0.9503041 * b,\n };\n}\n\n/**\n * Converts XYZ to OKLAB color space\n */\nfunction xyzToOklab(x: number, y: number, z: number): { l: number; a: number; b: number } {\n const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);\n const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);\n const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);\n\n return {\n l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n };\n}\n\n/**\n * Converts OKLAB to OKLCH color space\n */\nfunction oklabToOklch(l: number, a: number, b: number): { l: number; c: number; h: number } {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) * (180 / Math.PI);\n if (h < 0) h += 360;\n\n return { l, c, h };\n}\n\n/**\n * Converts a hex color to OKLCH format string\n * @param hex - Hex color (e.g., \"#6366f1\" or \"6366f1\")\n * @returns OKLCH string (e.g., \"oklch(55% 0.24 265)\")\n */\nexport function hexToOklch(hex: string): string {\n if (!isValidHex(hex)) {\n throw new Error(`Invalid hex color: ${hex}`);\n }\n\n const { r, g, b } = hexToRgb(hex);\n\n // Convert to linear RGB\n const linearR = srgbToLinear(r);\n const linearG = srgbToLinear(g);\n const linearB = srgbToLinear(b);\n\n // Convert to XYZ\n const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);\n\n // Convert to OKLAB\n const oklab = xyzToOklab(x, y, z);\n\n // Convert to OKLCH\n const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);\n\n // Format as OKLCH string\n // Lightness as percentage, chroma with 2 decimals, hue as integer\n const lightness = Math.round(l * 100);\n const chroma = Math.round(c * 100) / 100;\n const hue = Math.round(h);\n\n return `oklch(${lightness}% ${chroma} ${hue})`;\n}\n\n/**\n * Calculates appropriate foreground color (black or white) based on background lightness\n * @param oklchOrHex - Either an OKLCH string or hex color\n * @returns OKLCH string for foreground (white or dark)\n */\nexport function getForegroundColor(oklchOrHex: string): string {\n let lightness: number;\n\n if (oklchOrHex.startsWith(\"oklch\")) {\n // Parse OKLCH string\n const match = oklchOrHex.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n } else {\n // Convert hex to get lightness\n const oklch = hexToOklch(oklchOrHex);\n const match = oklch.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n }\n\n // Use white foreground for dark backgrounds, dark for light backgrounds\n return lightness > 0.6 ? \"oklch(20% 0 0)\" : \"oklch(100% 0 0)\";\n}\n","import { readFile, writeFile } from \"fs/promises\";\n\n/**\n * Upsert a CSS variable in a CSS content string.\n * If the variable exists, replace its value. If not, add it at the end.\n */\nfunction upsertCssVar(content: string, varName: string, value: string): string {\n const varRegex = new RegExp(`(${varName}\\\\s*:\\\\s*)([^;]+)(;)`, \"g\");\n\n if (varRegex.test(content)) {\n // Variable exists, replace its value\n return content.replace(varRegex, `$1${value}$3`);\n } else {\n // Variable doesn't exist, add it before the closing brace area\n // Add with proper indentation\n return content.trimEnd() + `\\n ${varName}: ${value};`;\n }\n}\n\n/**\n * Inject CSS variables into the :root block of a CSS file.\n * Handles both adding new variables and updating existing ones.\n */\nexport async function injectCssVars(\n cssPath: string,\n vars: { brand: string; brandForeground: string; radius: string }\n): Promise<void> {\n const content = await readFile(cssPath, \"utf-8\");\n\n // Match :root { ... } block - use a more robust pattern that handles nested content\n const rootRegex = /:root\\s*\\{([^}]*)\\}/;\n const match = content.match(rootRegex);\n\n if (match && match[1] !== undefined) {\n let rootContent = match[1];\n\n // Add or replace --brand, --brand-foreground, --radius\n rootContent = upsertCssVar(rootContent, \"--brand\", vars.brand);\n rootContent = upsertCssVar(\n rootContent,\n \"--brand-foreground\",\n vars.brandForeground\n );\n rootContent = upsertCssVar(rootContent, \"--radius\", vars.radius);\n\n const newContent = content.replace(rootRegex, `:root {${rootContent}\\n}`);\n await writeFile(cssPath, newContent);\n } else {\n // No :root block found, create one at the beginning\n const rootBlock = `:root {\n --brand: ${vars.brand};\n --brand-foreground: ${vars.brandForeground};\n --radius: ${vars.radius};\n}\n\n`;\n await writeFile(cssPath, rootBlock + content);\n }\n}\n\n/**\n * Get the CSS file path from components.json config.\n */\nexport function getCssPathFromConfig(config: {\n tailwind?: { css?: string };\n}): string | null {\n return config.tailwind?.css || null;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { ensureFronticRegistry } from \"../utils/config.js\";\n\ninterface AddOptions {\n overwrite?: boolean;\n all?: boolean;\n path?: string;\n yes?: boolean;\n}\n\n/**\n * Resolves component names to their @frontic/ prefixed form.\n *\n * All components go through the Frontic registry proxy which:\n * - Serves Frontic components if available (theme, button, fancy-button, etc.)\n * - Proxies to shadcn-vue for all other components (card, dialog, etc.)\n *\n * This allows the proxy to control routing centrally without CLI updates.\n */\nfunction resolveComponentNames(components: string[]): string[] {\n return components.map((component) => {\n // Already has a registry prefix - leave as-is\n if (component.startsWith(\"@\")) {\n return component;\n }\n // Prefix with @frontic/ - proxy handles the routing\n return `@frontic/${component}`;\n });\n}\n\nexport function registerAddCommand(program: Command) {\n program\n .command(\"add\")\n .description(\"Add components to your project\")\n .argument(\"[components...]\", \"Components to add\")\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .option(\"-a, --all\", \"Add all available components\")\n .option(\"-p, --path <path>\", \"Custom installation path\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (components: string[], options: AddOptions) => {\n await add(components, options);\n });\n}\n\nasync function add(components: string[], options: AddOptions) {\n // Validate input\n if (!options.all && components.length === 0) {\n console.log(chalk.red(\"Error: Please specify components to add or use --all\"));\n console.log();\n console.log(\"Usage:\");\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button dialog card\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add --all\")}`);\n process.exit(1);\n }\n\n // Ensure Frontic registry is configured\n const spinner = ora(\"Checking configuration...\").start();\n try {\n await ensureFronticRegistry();\n spinner.succeed(\"Configuration verified\");\n } catch {\n spinner.fail(\"Configuration error\");\n console.log();\n console.log(chalk.yellow(\"Run `npx @frontic/ui init` first to set up your project.\"));\n process.exit(1);\n }\n\n // Resolve component names (prefix with @frontic/ for proxy routing)\n const resolvedComponents = resolveComponentNames(components);\n\n // Show what we're adding\n if (resolvedComponents.length > 0) {\n console.log(\n chalk.cyan(\"Components:\"),\n resolvedComponents.map((c) => c.replace(\"@frontic/\", \"\")).join(\", \")\n );\n }\n\n // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...resolvedComponents);\n }\n\n if (options.overwrite) {\n args.push(\"--overwrite\");\n }\n\n if (options.path) {\n args.push(\"--path\", options.path);\n }\n\n if (options.yes) {\n args.push(\"--yes\");\n }\n\n console.log();\n console.log(chalk.blue(\"Adding components...\"));\n console.log();\n\n // Run shadcn-vue add\n await spawnShadcn(args);\n\n console.log();\n console.log(chalk.green(\"✓ Components added successfully!\"));\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile, readFile, mkdir } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport prompts from \"prompts\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ntype McpClient = \"claude\" | \"cursor\" | \"vscode\";\n\ninterface McpInitOptions {\n client?: McpClient;\n}\n\nexport function registerMcpCommand(program: Command) {\n const mcp = program\n .command(\"mcp\")\n .description(\"MCP (Model Context Protocol) commands\");\n\n mcp\n .command(\"init\")\n .description(\"Set up MCP for AI assistants\")\n .option(\"-c, --client <client>\", \"Target client (claude, cursor, vscode)\")\n .action(async (options: McpInitOptions) => {\n await initMcp(options);\n });\n}\n\nasync function initMcp(options: McpInitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI - MCP Setup\"));\n console.log(chalk.dim(\"Configure AI assistant integration\"));\n console.log();\n\n let client = options.client as McpClient | undefined;\n\n // Prompt for client if not specified\n if (!client) {\n const response = await prompts({\n type: \"select\",\n name: \"client\",\n message: \"Select your AI client:\",\n choices: [\n { title: \"Claude Code\", value: \"claude\" },\n { title: \"Cursor\", value: \"cursor\" },\n { title: \"VS Code\", value: \"vscode\" },\n ],\n });\n\n client = response.client;\n\n if (!client) {\n console.log(chalk.yellow(\"Setup cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Creating MCP configuration...\").start();\n\n try {\n await createMcpConfig(client);\n spinner.succeed(\"MCP configuration created\");\n } catch (error) {\n spinner.fail(\"Failed to create MCP configuration\");\n throw error;\n }\n\n console.log();\n console.log(chalk.green(\"✓ MCP configured successfully!\"));\n console.log();\n console.log(\"Your AI assistant can now:\");\n console.log(chalk.dim(\" • Browse available Frontic UI components\"));\n console.log(chalk.dim(\" • Add components using natural language\"));\n console.log(chalk.dim(' • Example: \"Add a button component\"'));\n console.log();\n}\n\nasync function createMcpConfig(client: McpClient) {\n const config = getMcpConfig();\n const configPath = getMcpConfigPath(client);\n const configDir = join(process.cwd(), configPath.split(\"/\").slice(0, -1).join(\"/\"));\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n await mkdir(configDir, { recursive: true });\n }\n\n const fullPath = join(process.cwd(), configPath);\n\n // Read existing config or create new\n let existingConfig: Record<string, unknown> = {};\n try {\n const content = await readFile(fullPath, \"utf-8\");\n existingConfig = JSON.parse(content);\n } catch {\n // File doesn't exist, use empty config\n }\n\n // Merge with existing config\n const mergedConfig = {\n ...existingConfig,\n mcpServers: {\n ...(existingConfig.mcpServers as Record<string, unknown> || {}),\n ...config.mcpServers,\n },\n };\n\n await writeFile(fullPath, JSON.stringify(mergedConfig, null, 2));\n\n console.log(chalk.dim(` Config written to: ${configPath}`));\n}\n\nfunction getMcpConfigPath(client: McpClient): string {\n switch (client) {\n case \"claude\":\n return \".mcp.json\";\n case \"cursor\":\n return \".cursor/mcp.json\";\n case \"vscode\":\n return \".vscode/mcp.json\";\n }\n}\n\nfunction getMcpConfig() {\n return {\n mcpServers: {\n \"frontic-ui\": {\n command: \"npx\",\n args: [\"shadcn-vue@latest\", \"mcp\"],\n env: {\n SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL,\n },\n },\n },\n };\n}\n"],"mappings":"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","names":["join","readFile","writeFile","program","join","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontic/ui",
3
- "version": "0.0.7",
3
+ "version": "0.3.1",
4
4
  "description": "CLI for adding Frontic UI components to your Vue project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,7 +48,6 @@
48
48
  "typecheck": "tsc --noEmit",
49
49
  "test": "vitest run",
50
50
  "test:unit": "vitest run tests/unit",
51
- "test:integration": "vitest run tests/integration",
52
51
  "test:e2e": "vitest run tests/e2e",
53
52
  "test:watch": "vitest",
54
53
  "clean": "rm -rf dist"