@frontic/ui 0.0.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.
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # @frontic/ui
2
+
3
+ CLI for adding Frontic UI components to your Vue project.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Use directly with npx (recommended)
9
+ npx @frontic/ui init
10
+
11
+ # Or install globally
12
+ npm install -g @frontic/ui
13
+ ```
14
+
15
+ ## Commands
16
+
17
+ ### init
18
+
19
+ Initialize Frontic UI in your Vue project:
20
+
21
+ ```bash
22
+ npx @frontic/ui init
23
+ ```
24
+
25
+ This will:
26
+
27
+ 1. Run `shadcn-vue init` if needed
28
+ 2. Configure the Frontic registry
29
+ 3. Set up theme colors
30
+
31
+ Options:
32
+
33
+ - `--yes, -y` - Skip confirmation prompts
34
+ - `--defaults, -d` - Use default configuration
35
+
36
+ ### add
37
+
38
+ Add components to your project:
39
+
40
+ ```bash
41
+ # Add single component
42
+ npx @frontic/ui add button
43
+
44
+ # Add multiple components
45
+ npx @frontic/ui add button dialog card
46
+
47
+ # Add all components
48
+ npx @frontic/ui add --all
49
+ ```
50
+
51
+ Options:
52
+
53
+ - `--overwrite, -o` - Overwrite existing files
54
+ - `--all, -a` - Add all available components
55
+ - `--path, -p` - Custom installation path
56
+
57
+ ### mcp init
58
+
59
+ Set up MCP (Model Context Protocol) for AI assistants:
60
+
61
+ ```bash
62
+ npx @frontic/ui mcp init
63
+ ```
64
+
65
+ This creates the MCP configuration for tools like Claude Code, Cursor, or VS Code.
66
+
67
+ Options:
68
+
69
+ - `--client, -c` - Target client (claude, cursor, vscode)
70
+
71
+ ## Configuration
72
+
73
+ After running `init`, your `components.json` will include:
74
+
75
+ ```json
76
+ {
77
+ "registries": {
78
+ "frontic": {
79
+ "url": "https://registry.frontic.io/r"
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## Theme Colors
86
+
87
+ Frontic UI includes additional theme colors:
88
+
89
+ ```css
90
+ bg-brand text-brand border-brand
91
+ bg-success text-success border-success
92
+ bg-warning text-warning border-warning
93
+ bg-info text-info border-info
94
+ ```
95
+
96
+ These are configured during `init` and can be customized in your CSS.
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ # Install dependencies
102
+ pnpm install
103
+
104
+ # Build
105
+ pnpm build
106
+
107
+ # Run in development
108
+ pnpm dev
109
+
110
+ # Run tests
111
+ pnpm test
112
+
113
+ # Link globally for local testing
114
+ pnpm link --global
115
+ ```
116
+
117
+ ## License
118
+
119
+ MIT
@@ -0,0 +1,373 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/init.ts
7
+ import chalk from "chalk";
8
+ import ora from "ora";
9
+ import prompts from "prompts";
10
+
11
+ // src/utils/spawn-shadcn.ts
12
+ import { execa } from "execa";
13
+ async function spawnShadcn(args, options = {}) {
14
+ const { silent = false } = options;
15
+ try {
16
+ await execa("npx", ["shadcn-vue@latest", ...args], {
17
+ stdio: silent ? "pipe" : "inherit",
18
+ shell: true
19
+ });
20
+ } catch (error) {
21
+ if (!silent) {
22
+ throw error;
23
+ }
24
+ }
25
+ }
26
+
27
+ // src/utils/config.ts
28
+ import { readFile, writeFile, access } from "fs/promises";
29
+ import { join } from "path";
30
+
31
+ // src/utils/constants.ts
32
+ var FRONTIC_REGISTRY_URL = "https://registry.frontic.io/r";
33
+ var CONFIG_FILE = "components.json";
34
+
35
+ // src/utils/config.ts
36
+ async function configExists() {
37
+ try {
38
+ await access(join(process.cwd(), CONFIG_FILE));
39
+ return true;
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+ async function readConfig() {
45
+ try {
46
+ const content = await readFile(join(process.cwd(), CONFIG_FILE), "utf-8");
47
+ return JSON.parse(content);
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ async function writeConfig(config) {
53
+ await writeFile(
54
+ join(process.cwd(), CONFIG_FILE),
55
+ JSON.stringify(config, null, 2)
56
+ );
57
+ }
58
+ async function updateConfig(updates) {
59
+ const existing = await readConfig();
60
+ if (!existing) {
61
+ throw new Error(
62
+ "components.json not found. Run `npx @frontic/ui init` first."
63
+ );
64
+ }
65
+ const merged = deepMerge(existing, updates);
66
+ await writeConfig(merged);
67
+ }
68
+ async function ensureFronticRegistry() {
69
+ const config = await readConfig();
70
+ if (!config) {
71
+ throw new Error("components.json not found");
72
+ }
73
+ if (config.registries?.frontic?.url === FRONTIC_REGISTRY_URL) {
74
+ return;
75
+ }
76
+ await updateConfig({
77
+ registries: {
78
+ ...config.registries,
79
+ frontic: {
80
+ url: FRONTIC_REGISTRY_URL
81
+ }
82
+ }
83
+ });
84
+ }
85
+ function deepMerge(target, source) {
86
+ const result = { ...target };
87
+ for (const key in source) {
88
+ const sourceValue = source[key];
89
+ const targetValue = target[key];
90
+ if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
91
+ result[key] = deepMerge(
92
+ targetValue,
93
+ sourceValue
94
+ );
95
+ } else {
96
+ result[key] = sourceValue;
97
+ }
98
+ }
99
+ return result;
100
+ }
101
+
102
+ // src/commands/init.ts
103
+ function registerInitCommand(program2) {
104
+ program2.command("init").description("Initialize Frontic UI in your Vue project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").action(async (options) => {
105
+ await init(options);
106
+ });
107
+ }
108
+ async function init(options) {
109
+ console.log();
110
+ console.log(chalk.bold("Frontic UI"));
111
+ console.log(chalk.dim("Initializing your project..."));
112
+ console.log();
113
+ const hasConfig = await configExists();
114
+ if (!hasConfig) {
115
+ console.log(chalk.blue("Running shadcn-vue init..."));
116
+ console.log();
117
+ const args = ["init"];
118
+ if (options.yes) args.push("--yes");
119
+ if (options.defaults) args.push("--defaults");
120
+ await spawnShadcn(args);
121
+ console.log();
122
+ }
123
+ let themeColors = getDefaultThemeColors();
124
+ if (!options.yes && !options.defaults) {
125
+ const response = await prompts([
126
+ {
127
+ type: "confirm",
128
+ name: "customizeColors",
129
+ message: "Would you like to customize theme colors?",
130
+ initial: false
131
+ }
132
+ ]);
133
+ if (response.customizeColors) {
134
+ const colorResponse = await prompts([
135
+ {
136
+ type: "text",
137
+ name: "brand",
138
+ message: "Brand color (OKLCH)",
139
+ initial: themeColors.brand
140
+ },
141
+ {
142
+ type: "text",
143
+ name: "success",
144
+ message: "Success color (OKLCH)",
145
+ initial: themeColors.success
146
+ },
147
+ {
148
+ type: "text",
149
+ name: "warning",
150
+ message: "Warning color (OKLCH)",
151
+ initial: themeColors.warning
152
+ },
153
+ {
154
+ type: "text",
155
+ name: "info",
156
+ message: "Info color (OKLCH)",
157
+ initial: themeColors.info
158
+ }
159
+ ]);
160
+ themeColors = {
161
+ brand: colorResponse.brand || themeColors.brand,
162
+ success: colorResponse.success || themeColors.success,
163
+ warning: colorResponse.warning || themeColors.warning,
164
+ info: colorResponse.info || themeColors.info
165
+ };
166
+ }
167
+ }
168
+ const spinner = ora("Configuring Frontic registry...").start();
169
+ try {
170
+ await updateConfig({
171
+ registries: {
172
+ frontic: {
173
+ url: FRONTIC_REGISTRY_URL
174
+ }
175
+ }
176
+ });
177
+ spinner.succeed("Frontic registry configured");
178
+ } catch (error) {
179
+ spinner.fail("Failed to configure registry");
180
+ throw error;
181
+ }
182
+ const themeSpinner = ora("Installing theme...").start();
183
+ try {
184
+ await spawnShadcn(["add", "theme", "--yes"], { silent: true });
185
+ themeSpinner.succeed("Theme installed");
186
+ } catch {
187
+ themeSpinner.warn("Theme installation skipped (may already exist)");
188
+ }
189
+ console.log();
190
+ console.log(chalk.green("\u2713 Frontic UI initialized successfully!"));
191
+ console.log();
192
+ console.log("Next steps:");
193
+ console.log(chalk.dim(" 1. Add components:"));
194
+ console.log(` ${chalk.cyan("npx @frontic/ui add button")}`);
195
+ console.log();
196
+ console.log(chalk.dim(" 2. Set up MCP for AI assistants (optional):"));
197
+ console.log(` ${chalk.cyan("npx @frontic/ui mcp init")}`);
198
+ console.log();
199
+ }
200
+ function getDefaultThemeColors() {
201
+ return {
202
+ brand: "oklch(58% 0.25 265)",
203
+ success: "oklch(55% 0.2 145)",
204
+ warning: "oklch(75% 0.18 85)",
205
+ info: "oklch(60% 0.2 230)"
206
+ };
207
+ }
208
+
209
+ // src/commands/add.ts
210
+ import chalk2 from "chalk";
211
+ import ora2 from "ora";
212
+ function registerAddCommand(program2) {
213
+ program2.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("-p, --path <path>", "Custom installation path").option("-y, --yes", "Skip confirmation prompts").action(async (components, options) => {
214
+ await add(components, options);
215
+ });
216
+ }
217
+ async function add(components, options) {
218
+ if (!options.all && components.length === 0) {
219
+ console.log(chalk2.red("Error: Please specify components to add or use --all"));
220
+ console.log();
221
+ console.log("Usage:");
222
+ console.log(` ${chalk2.cyan("npx @frontic/ui add button")}`);
223
+ console.log(` ${chalk2.cyan("npx @frontic/ui add button dialog card")}`);
224
+ console.log(` ${chalk2.cyan("npx @frontic/ui add --all")}`);
225
+ process.exit(1);
226
+ }
227
+ const spinner = ora2("Checking configuration...").start();
228
+ try {
229
+ await ensureFronticRegistry();
230
+ spinner.succeed("Configuration verified");
231
+ } catch {
232
+ spinner.fail("Configuration error");
233
+ console.log();
234
+ console.log(chalk2.yellow("Run `npx @frontic/ui init` first to set up your project."));
235
+ process.exit(1);
236
+ }
237
+ const args = ["add"];
238
+ if (options.all) {
239
+ args.push("--all");
240
+ } else {
241
+ args.push(...components);
242
+ }
243
+ if (options.overwrite) {
244
+ args.push("--overwrite");
245
+ }
246
+ if (options.path) {
247
+ args.push("--path", options.path);
248
+ }
249
+ if (options.yes) {
250
+ args.push("--yes");
251
+ }
252
+ console.log();
253
+ console.log(chalk2.blue("Adding components..."));
254
+ console.log();
255
+ await spawnShadcn(args);
256
+ console.log();
257
+ console.log(chalk2.green("\u2713 Components added successfully!"));
258
+ }
259
+
260
+ // src/commands/mcp.ts
261
+ import chalk3 from "chalk";
262
+ import ora3 from "ora";
263
+ import { writeFile as writeFile2, readFile as readFile2, mkdir } from "fs/promises";
264
+ import { existsSync } from "fs";
265
+ import { join as join2 } from "path";
266
+ import prompts2 from "prompts";
267
+ function registerMcpCommand(program2) {
268
+ const mcp = program2.command("mcp").description("MCP (Model Context Protocol) commands");
269
+ mcp.command("init").description("Set up MCP for AI assistants").option("-c, --client <client>", "Target client (claude, cursor, vscode)").action(async (options) => {
270
+ await initMcp(options);
271
+ });
272
+ }
273
+ async function initMcp(options) {
274
+ console.log();
275
+ console.log(chalk3.bold("Frontic UI - MCP Setup"));
276
+ console.log(chalk3.dim("Configure AI assistant integration"));
277
+ console.log();
278
+ let client = options.client;
279
+ if (!client) {
280
+ const response = await prompts2({
281
+ type: "select",
282
+ name: "client",
283
+ message: "Select your AI client:",
284
+ choices: [
285
+ { title: "Claude Code", value: "claude" },
286
+ { title: "Cursor", value: "cursor" },
287
+ { title: "VS Code", value: "vscode" }
288
+ ]
289
+ });
290
+ client = response.client;
291
+ if (!client) {
292
+ console.log(chalk3.yellow("Setup cancelled."));
293
+ return;
294
+ }
295
+ }
296
+ const spinner = ora3("Creating MCP configuration...").start();
297
+ try {
298
+ await createMcpConfig(client);
299
+ spinner.succeed("MCP configuration created");
300
+ } catch (error) {
301
+ spinner.fail("Failed to create MCP configuration");
302
+ throw error;
303
+ }
304
+ console.log();
305
+ console.log(chalk3.green("\u2713 MCP configured successfully!"));
306
+ console.log();
307
+ console.log("Your AI assistant can now:");
308
+ console.log(chalk3.dim(" \u2022 Browse available Frontic UI components"));
309
+ console.log(chalk3.dim(" \u2022 Add components using natural language"));
310
+ console.log(chalk3.dim(' \u2022 Example: "Add a button component"'));
311
+ console.log();
312
+ }
313
+ async function createMcpConfig(client) {
314
+ const config = getMcpConfig();
315
+ const configPath = getMcpConfigPath(client);
316
+ const configDir = join2(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
317
+ if (!existsSync(configDir)) {
318
+ await mkdir(configDir, { recursive: true });
319
+ }
320
+ const fullPath = join2(process.cwd(), configPath);
321
+ let existingConfig = {};
322
+ try {
323
+ const content = await readFile2(fullPath, "utf-8");
324
+ existingConfig = JSON.parse(content);
325
+ } catch {
326
+ }
327
+ const mergedConfig = {
328
+ ...existingConfig,
329
+ mcpServers: {
330
+ ...existingConfig.mcpServers || {},
331
+ ...config.mcpServers
332
+ }
333
+ };
334
+ await writeFile2(fullPath, JSON.stringify(mergedConfig, null, 2));
335
+ console.log(chalk3.dim(` Config written to: ${configPath}`));
336
+ }
337
+ function getMcpConfigPath(client) {
338
+ switch (client) {
339
+ case "claude":
340
+ return ".mcp.json";
341
+ case "cursor":
342
+ return ".cursor/mcp.json";
343
+ case "vscode":
344
+ return ".vscode/mcp.json";
345
+ }
346
+ }
347
+ function getMcpConfig() {
348
+ return {
349
+ mcpServers: {
350
+ "frontic-ui": {
351
+ command: "npx",
352
+ args: ["shadcn-vue@latest", "mcp"],
353
+ env: {
354
+ SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL
355
+ }
356
+ }
357
+ }
358
+ };
359
+ }
360
+
361
+ // src/index.ts
362
+ var program = new Command();
363
+ program.name("frontic-ui").description("CLI for adding Frontic UI components to your Vue project").version("0.0.1");
364
+ registerInitCommand(program);
365
+ registerAddCommand(program);
366
+ registerMcpCommand(program);
367
+ function run() {
368
+ program.parse();
369
+ }
370
+
371
+ // bin/frontic-ui.ts
372
+ run();
373
+ //# sourceMappingURL=frontic-ui.js.map
@@ -0,0 +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/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.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 { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists } from \"../utils/config.js\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\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 .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\n await spawnShadcn(args);\n console.log();\n }\n\n // Prompt for theme colors (unless skipped)\n let themeColors = getDefaultThemeColors();\n\n if (!options.yes && !options.defaults) {\n const response = await prompts([\n {\n type: \"confirm\",\n name: \"customizeColors\",\n message: \"Would you like to customize theme colors?\",\n initial: false,\n },\n ]);\n\n if (response.customizeColors) {\n const colorResponse = await prompts([\n {\n type: \"text\",\n name: \"brand\",\n message: \"Brand color (OKLCH)\",\n initial: themeColors.brand,\n },\n {\n type: \"text\",\n name: \"success\",\n message: \"Success color (OKLCH)\",\n initial: themeColors.success,\n },\n {\n type: \"text\",\n name: \"warning\",\n message: \"Warning color (OKLCH)\",\n initial: themeColors.warning,\n },\n {\n type: \"text\",\n name: \"info\",\n message: \"Info color (OKLCH)\",\n initial: themeColors.info,\n },\n ]);\n\n themeColors = {\n brand: colorResponse.brand || themeColors.brand,\n success: colorResponse.success || themeColors.success,\n warning: colorResponse.warning || themeColors.warning,\n info: colorResponse.info || themeColors.info,\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 theme\n const themeSpinner = ora(\"Installing theme...\").start();\n try {\n await spawnShadcn([\"add\", \"theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Theme installed\");\n } catch {\n themeSpinner.warn(\"Theme installation skipped (may already exist)\");\n }\n\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\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\nfunction getDefaultThemeColors() {\n return {\n brand: \"oklch(58% 0.25 265)\",\n success: \"oklch(55% 0.2 145)\",\n warning: \"oklch(75% 0.18 85)\",\n info: \"oklch(60% 0.2 230)\",\n };\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","export const FRONTIC_REGISTRY_URL = \"https://registry.frontic.io/r\";\n\nexport const CONFIG_FILE = \"components.json\";\n\nexport const DEFAULT_THEME_COLORS = {\n brand: \"oklch(58% 0.25 265)\",\n \"brand-foreground\": \"oklch(100% 0 0)\",\n success: \"oklch(55% 0.2 145)\",\n \"success-foreground\": \"oklch(100% 0 0)\",\n warning: \"oklch(75% 0.18 85)\",\n \"warning-foreground\": \"oklch(20% 0 0)\",\n info: \"oklch(60% 0.2 230)\",\n \"info-foreground\": \"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\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 // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...components);\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"]}
@@ -0,0 +1,6 @@
1
+ import { Command } from 'commander';
2
+
3
+ declare const program: Command;
4
+ declare function run(): void;
5
+
6
+ export { program, run };
package/dist/index.js ADDED
@@ -0,0 +1,372 @@
1
+ // src/index.ts
2
+ import { Command } from "commander";
3
+
4
+ // src/commands/init.ts
5
+ import chalk from "chalk";
6
+ import ora from "ora";
7
+ import prompts from "prompts";
8
+
9
+ // src/utils/spawn-shadcn.ts
10
+ import { execa } from "execa";
11
+ async function spawnShadcn(args, options = {}) {
12
+ const { silent = false } = options;
13
+ try {
14
+ await execa("npx", ["shadcn-vue@latest", ...args], {
15
+ stdio: silent ? "pipe" : "inherit",
16
+ shell: true
17
+ });
18
+ } catch (error) {
19
+ if (!silent) {
20
+ throw error;
21
+ }
22
+ }
23
+ }
24
+
25
+ // src/utils/config.ts
26
+ import { readFile, writeFile, access } from "fs/promises";
27
+ import { join } from "path";
28
+
29
+ // src/utils/constants.ts
30
+ var FRONTIC_REGISTRY_URL = "https://registry.frontic.io/r";
31
+ var CONFIG_FILE = "components.json";
32
+
33
+ // src/utils/config.ts
34
+ async function configExists() {
35
+ try {
36
+ await access(join(process.cwd(), CONFIG_FILE));
37
+ return true;
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ async function readConfig() {
43
+ try {
44
+ const content = await readFile(join(process.cwd(), CONFIG_FILE), "utf-8");
45
+ return JSON.parse(content);
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+ async function writeConfig(config) {
51
+ await writeFile(
52
+ join(process.cwd(), CONFIG_FILE),
53
+ JSON.stringify(config, null, 2)
54
+ );
55
+ }
56
+ async function updateConfig(updates) {
57
+ const existing = await readConfig();
58
+ if (!existing) {
59
+ throw new Error(
60
+ "components.json not found. Run `npx @frontic/ui init` first."
61
+ );
62
+ }
63
+ const merged = deepMerge(existing, updates);
64
+ await writeConfig(merged);
65
+ }
66
+ async function ensureFronticRegistry() {
67
+ const config = await readConfig();
68
+ if (!config) {
69
+ throw new Error("components.json not found");
70
+ }
71
+ if (config.registries?.frontic?.url === FRONTIC_REGISTRY_URL) {
72
+ return;
73
+ }
74
+ await updateConfig({
75
+ registries: {
76
+ ...config.registries,
77
+ frontic: {
78
+ url: FRONTIC_REGISTRY_URL
79
+ }
80
+ }
81
+ });
82
+ }
83
+ function deepMerge(target, source) {
84
+ const result = { ...target };
85
+ for (const key in source) {
86
+ const sourceValue = source[key];
87
+ const targetValue = target[key];
88
+ if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
89
+ result[key] = deepMerge(
90
+ targetValue,
91
+ sourceValue
92
+ );
93
+ } else {
94
+ result[key] = sourceValue;
95
+ }
96
+ }
97
+ return result;
98
+ }
99
+
100
+ // src/commands/init.ts
101
+ function registerInitCommand(program2) {
102
+ program2.command("init").description("Initialize Frontic UI in your Vue project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").action(async (options) => {
103
+ await init(options);
104
+ });
105
+ }
106
+ async function init(options) {
107
+ console.log();
108
+ console.log(chalk.bold("Frontic UI"));
109
+ console.log(chalk.dim("Initializing your project..."));
110
+ console.log();
111
+ const hasConfig = await configExists();
112
+ if (!hasConfig) {
113
+ console.log(chalk.blue("Running shadcn-vue init..."));
114
+ console.log();
115
+ const args = ["init"];
116
+ if (options.yes) args.push("--yes");
117
+ if (options.defaults) args.push("--defaults");
118
+ await spawnShadcn(args);
119
+ console.log();
120
+ }
121
+ let themeColors = getDefaultThemeColors();
122
+ if (!options.yes && !options.defaults) {
123
+ const response = await prompts([
124
+ {
125
+ type: "confirm",
126
+ name: "customizeColors",
127
+ message: "Would you like to customize theme colors?",
128
+ initial: false
129
+ }
130
+ ]);
131
+ if (response.customizeColors) {
132
+ const colorResponse = await prompts([
133
+ {
134
+ type: "text",
135
+ name: "brand",
136
+ message: "Brand color (OKLCH)",
137
+ initial: themeColors.brand
138
+ },
139
+ {
140
+ type: "text",
141
+ name: "success",
142
+ message: "Success color (OKLCH)",
143
+ initial: themeColors.success
144
+ },
145
+ {
146
+ type: "text",
147
+ name: "warning",
148
+ message: "Warning color (OKLCH)",
149
+ initial: themeColors.warning
150
+ },
151
+ {
152
+ type: "text",
153
+ name: "info",
154
+ message: "Info color (OKLCH)",
155
+ initial: themeColors.info
156
+ }
157
+ ]);
158
+ themeColors = {
159
+ brand: colorResponse.brand || themeColors.brand,
160
+ success: colorResponse.success || themeColors.success,
161
+ warning: colorResponse.warning || themeColors.warning,
162
+ info: colorResponse.info || themeColors.info
163
+ };
164
+ }
165
+ }
166
+ const spinner = ora("Configuring Frontic registry...").start();
167
+ try {
168
+ await updateConfig({
169
+ registries: {
170
+ frontic: {
171
+ url: FRONTIC_REGISTRY_URL
172
+ }
173
+ }
174
+ });
175
+ spinner.succeed("Frontic registry configured");
176
+ } catch (error) {
177
+ spinner.fail("Failed to configure registry");
178
+ throw error;
179
+ }
180
+ const themeSpinner = ora("Installing theme...").start();
181
+ try {
182
+ await spawnShadcn(["add", "theme", "--yes"], { silent: true });
183
+ themeSpinner.succeed("Theme installed");
184
+ } catch {
185
+ themeSpinner.warn("Theme installation skipped (may already exist)");
186
+ }
187
+ console.log();
188
+ console.log(chalk.green("\u2713 Frontic UI initialized successfully!"));
189
+ console.log();
190
+ console.log("Next steps:");
191
+ console.log(chalk.dim(" 1. Add components:"));
192
+ console.log(` ${chalk.cyan("npx @frontic/ui add button")}`);
193
+ console.log();
194
+ console.log(chalk.dim(" 2. Set up MCP for AI assistants (optional):"));
195
+ console.log(` ${chalk.cyan("npx @frontic/ui mcp init")}`);
196
+ console.log();
197
+ }
198
+ function getDefaultThemeColors() {
199
+ return {
200
+ brand: "oklch(58% 0.25 265)",
201
+ success: "oklch(55% 0.2 145)",
202
+ warning: "oklch(75% 0.18 85)",
203
+ info: "oklch(60% 0.2 230)"
204
+ };
205
+ }
206
+
207
+ // src/commands/add.ts
208
+ import chalk2 from "chalk";
209
+ import ora2 from "ora";
210
+ function registerAddCommand(program2) {
211
+ program2.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("-p, --path <path>", "Custom installation path").option("-y, --yes", "Skip confirmation prompts").action(async (components, options) => {
212
+ await add(components, options);
213
+ });
214
+ }
215
+ async function add(components, options) {
216
+ if (!options.all && components.length === 0) {
217
+ console.log(chalk2.red("Error: Please specify components to add or use --all"));
218
+ console.log();
219
+ console.log("Usage:");
220
+ console.log(` ${chalk2.cyan("npx @frontic/ui add button")}`);
221
+ console.log(` ${chalk2.cyan("npx @frontic/ui add button dialog card")}`);
222
+ console.log(` ${chalk2.cyan("npx @frontic/ui add --all")}`);
223
+ process.exit(1);
224
+ }
225
+ const spinner = ora2("Checking configuration...").start();
226
+ try {
227
+ await ensureFronticRegistry();
228
+ spinner.succeed("Configuration verified");
229
+ } catch {
230
+ spinner.fail("Configuration error");
231
+ console.log();
232
+ console.log(chalk2.yellow("Run `npx @frontic/ui init` first to set up your project."));
233
+ process.exit(1);
234
+ }
235
+ const args = ["add"];
236
+ if (options.all) {
237
+ args.push("--all");
238
+ } else {
239
+ args.push(...components);
240
+ }
241
+ if (options.overwrite) {
242
+ args.push("--overwrite");
243
+ }
244
+ if (options.path) {
245
+ args.push("--path", options.path);
246
+ }
247
+ if (options.yes) {
248
+ args.push("--yes");
249
+ }
250
+ console.log();
251
+ console.log(chalk2.blue("Adding components..."));
252
+ console.log();
253
+ await spawnShadcn(args);
254
+ console.log();
255
+ console.log(chalk2.green("\u2713 Components added successfully!"));
256
+ }
257
+
258
+ // src/commands/mcp.ts
259
+ import chalk3 from "chalk";
260
+ import ora3 from "ora";
261
+ import { writeFile as writeFile2, readFile as readFile2, mkdir } from "fs/promises";
262
+ import { existsSync } from "fs";
263
+ import { join as join2 } from "path";
264
+ import prompts2 from "prompts";
265
+ function registerMcpCommand(program2) {
266
+ const mcp = program2.command("mcp").description("MCP (Model Context Protocol) commands");
267
+ mcp.command("init").description("Set up MCP for AI assistants").option("-c, --client <client>", "Target client (claude, cursor, vscode)").action(async (options) => {
268
+ await initMcp(options);
269
+ });
270
+ }
271
+ async function initMcp(options) {
272
+ console.log();
273
+ console.log(chalk3.bold("Frontic UI - MCP Setup"));
274
+ console.log(chalk3.dim("Configure AI assistant integration"));
275
+ console.log();
276
+ let client = options.client;
277
+ if (!client) {
278
+ const response = await prompts2({
279
+ type: "select",
280
+ name: "client",
281
+ message: "Select your AI client:",
282
+ choices: [
283
+ { title: "Claude Code", value: "claude" },
284
+ { title: "Cursor", value: "cursor" },
285
+ { title: "VS Code", value: "vscode" }
286
+ ]
287
+ });
288
+ client = response.client;
289
+ if (!client) {
290
+ console.log(chalk3.yellow("Setup cancelled."));
291
+ return;
292
+ }
293
+ }
294
+ const spinner = ora3("Creating MCP configuration...").start();
295
+ try {
296
+ await createMcpConfig(client);
297
+ spinner.succeed("MCP configuration created");
298
+ } catch (error) {
299
+ spinner.fail("Failed to create MCP configuration");
300
+ throw error;
301
+ }
302
+ console.log();
303
+ console.log(chalk3.green("\u2713 MCP configured successfully!"));
304
+ console.log();
305
+ console.log("Your AI assistant can now:");
306
+ console.log(chalk3.dim(" \u2022 Browse available Frontic UI components"));
307
+ console.log(chalk3.dim(" \u2022 Add components using natural language"));
308
+ console.log(chalk3.dim(' \u2022 Example: "Add a button component"'));
309
+ console.log();
310
+ }
311
+ async function createMcpConfig(client) {
312
+ const config = getMcpConfig();
313
+ const configPath = getMcpConfigPath(client);
314
+ const configDir = join2(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
315
+ if (!existsSync(configDir)) {
316
+ await mkdir(configDir, { recursive: true });
317
+ }
318
+ const fullPath = join2(process.cwd(), configPath);
319
+ let existingConfig = {};
320
+ try {
321
+ const content = await readFile2(fullPath, "utf-8");
322
+ existingConfig = JSON.parse(content);
323
+ } catch {
324
+ }
325
+ const mergedConfig = {
326
+ ...existingConfig,
327
+ mcpServers: {
328
+ ...existingConfig.mcpServers || {},
329
+ ...config.mcpServers
330
+ }
331
+ };
332
+ await writeFile2(fullPath, JSON.stringify(mergedConfig, null, 2));
333
+ console.log(chalk3.dim(` Config written to: ${configPath}`));
334
+ }
335
+ function getMcpConfigPath(client) {
336
+ switch (client) {
337
+ case "claude":
338
+ return ".mcp.json";
339
+ case "cursor":
340
+ return ".cursor/mcp.json";
341
+ case "vscode":
342
+ return ".vscode/mcp.json";
343
+ }
344
+ }
345
+ function getMcpConfig() {
346
+ return {
347
+ mcpServers: {
348
+ "frontic-ui": {
349
+ command: "npx",
350
+ args: ["shadcn-vue@latest", "mcp"],
351
+ env: {
352
+ SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL
353
+ }
354
+ }
355
+ }
356
+ };
357
+ }
358
+
359
+ // src/index.ts
360
+ var program = new Command();
361
+ program.name("frontic-ui").description("CLI for adding Frontic UI components to your Vue project").version("0.0.1");
362
+ registerInitCommand(program);
363
+ registerAddCommand(program);
364
+ registerMcpCommand(program);
365
+ function run() {
366
+ program.parse();
367
+ }
368
+ export {
369
+ program,
370
+ run
371
+ };
372
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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/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.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 { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists } from \"../utils/config.js\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\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 .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\n await spawnShadcn(args);\n console.log();\n }\n\n // Prompt for theme colors (unless skipped)\n let themeColors = getDefaultThemeColors();\n\n if (!options.yes && !options.defaults) {\n const response = await prompts([\n {\n type: \"confirm\",\n name: \"customizeColors\",\n message: \"Would you like to customize theme colors?\",\n initial: false,\n },\n ]);\n\n if (response.customizeColors) {\n const colorResponse = await prompts([\n {\n type: \"text\",\n name: \"brand\",\n message: \"Brand color (OKLCH)\",\n initial: themeColors.brand,\n },\n {\n type: \"text\",\n name: \"success\",\n message: \"Success color (OKLCH)\",\n initial: themeColors.success,\n },\n {\n type: \"text\",\n name: \"warning\",\n message: \"Warning color (OKLCH)\",\n initial: themeColors.warning,\n },\n {\n type: \"text\",\n name: \"info\",\n message: \"Info color (OKLCH)\",\n initial: themeColors.info,\n },\n ]);\n\n themeColors = {\n brand: colorResponse.brand || themeColors.brand,\n success: colorResponse.success || themeColors.success,\n warning: colorResponse.warning || themeColors.warning,\n info: colorResponse.info || themeColors.info,\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 theme\n const themeSpinner = ora(\"Installing theme...\").start();\n try {\n await spawnShadcn([\"add\", \"theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Theme installed\");\n } catch {\n themeSpinner.warn(\"Theme installation skipped (may already exist)\");\n }\n\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\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\nfunction getDefaultThemeColors() {\n return {\n brand: \"oklch(58% 0.25 265)\",\n success: \"oklch(55% 0.2 145)\",\n warning: \"oklch(75% 0.18 85)\",\n info: \"oklch(60% 0.2 230)\",\n };\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","export const FRONTIC_REGISTRY_URL = \"https://registry.frontic.io/r\";\n\nexport const CONFIG_FILE = \"components.json\";\n\nexport const DEFAULT_THEME_COLORS = {\n brand: \"oklch(58% 0.25 265)\",\n \"brand-foreground\": \"oklch(100% 0 0)\",\n success: \"oklch(55% 0.2 145)\",\n \"success-foreground\": \"oklch(100% 0 0)\",\n warning: \"oklch(75% 0.18 85)\",\n \"warning-foreground\": \"oklch(20% 0 0)\",\n info: \"oklch(60% 0.2 230)\",\n \"info-foreground\": \"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\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 // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...components);\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":["program","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@frontic/ui",
3
+ "version": "0.0.1",
4
+ "description": "CLI for adding Frontic UI components to your Vue project",
5
+ "type": "module",
6
+ "bin": {
7
+ "frontic-ui": "dist/bin/frontic-ui.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "dev": "tsup --watch",
16
+ "build": "tsup",
17
+ "typecheck": "tsc --noEmit",
18
+ "test": "vitest run",
19
+ "test:unit": "vitest run tests/unit",
20
+ "test:integration": "vitest run tests/integration",
21
+ "test:watch": "vitest",
22
+ "clean": "rm -rf dist"
23
+ },
24
+ "dependencies": {
25
+ "chalk": "^5.3.0",
26
+ "commander": "^12.1.0",
27
+ "execa": "^9.5.1",
28
+ "ora": "^8.1.1",
29
+ "prompts": "^2.4.2"
30
+ },
31
+ "devDependencies": {
32
+ "@types/prompts": "^2.4.9",
33
+ "tsup": "^8.3.5",
34
+ "typescript": "^5.7.2",
35
+ "vitest": "^2.1.8"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/frontic/frontic-ui.git",
43
+ "directory": "packages/cli"
44
+ },
45
+ "keywords": [
46
+ "vue",
47
+ "components",
48
+ "ui",
49
+ "shadcn",
50
+ "tailwind",
51
+ "cli"
52
+ ],
53
+ "author": "Frontic",
54
+ "license": "MIT"
55
+ }