@nikkory/vibe-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2371 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_commander7 = require("commander");
28
+
29
+ // src/commands/add.ts
30
+ var fs = __toESM(require("fs/promises"));
31
+ var path = __toESM(require("path"));
32
+ var import_commander = require("commander");
33
+ var import_inquirer = __toESM(require("inquirer"));
34
+
35
+ // src/utils/logger.ts
36
+ var import_boxen = __toESM(require("boxen"));
37
+ var import_chalk = __toESM(require("chalk"));
38
+ var import_ora = __toESM(require("ora"));
39
+ var Logger = class {
40
+ spinner = null;
41
+ /**
42
+ * Success message (green checkmark)
43
+ */
44
+ success(message) {
45
+ console.log(import_chalk.default.green("\u2713"), message);
46
+ }
47
+ /**
48
+ * Error message (red cross)
49
+ */
50
+ error(message) {
51
+ console.log(import_chalk.default.red("\u2717"), message);
52
+ }
53
+ /**
54
+ * Warning message (yellow exclamation)
55
+ */
56
+ warn(message) {
57
+ console.log(import_chalk.default.yellow("\u26A0"), message);
58
+ }
59
+ /**
60
+ * Info message (blue dot)
61
+ */
62
+ info(message) {
63
+ console.log(import_chalk.default.blue("\u2139"), message);
64
+ }
65
+ /**
66
+ * Debug message (gray)
67
+ */
68
+ debug(message) {
69
+ if (process.env["DEBUG"]) {
70
+ console.log(import_chalk.default.gray("\u2022"), import_chalk.default.gray(message));
71
+ }
72
+ }
73
+ /**
74
+ * Start loading spinner
75
+ */
76
+ startSpinner(message) {
77
+ this.spinner = (0, import_ora.default)(message).start();
78
+ }
79
+ /**
80
+ * Update spinner message
81
+ */
82
+ updateSpinner(message) {
83
+ if (this.spinner) {
84
+ this.spinner.text = message;
85
+ }
86
+ }
87
+ /**
88
+ * Stop spinner with success
89
+ */
90
+ stopSpinnerSuccess(message) {
91
+ if (this.spinner) {
92
+ this.spinner.succeed(message);
93
+ this.spinner = null;
94
+ }
95
+ }
96
+ /**
97
+ * Stop spinner with failure
98
+ */
99
+ stopSpinnerFail(message) {
100
+ if (this.spinner) {
101
+ this.spinner.fail(message);
102
+ this.spinner = null;
103
+ }
104
+ }
105
+ /**
106
+ * Stop spinner
107
+ */
108
+ stopSpinner() {
109
+ if (this.spinner) {
110
+ this.spinner.stop();
111
+ this.spinner = null;
112
+ }
113
+ }
114
+ /**
115
+ * Print box message
116
+ */
117
+ box(message, options) {
118
+ console.log(
119
+ (0, import_boxen.default)(message, {
120
+ padding: 1,
121
+ margin: 1,
122
+ borderStyle: "round",
123
+ borderColor: options?.borderColor || "cyan",
124
+ title: options?.title,
125
+ titleAlignment: "center"
126
+ })
127
+ );
128
+ }
129
+ /**
130
+ * Print separator line
131
+ */
132
+ separator() {
133
+ console.log(import_chalk.default.gray("\u2500".repeat(50)));
134
+ }
135
+ /**
136
+ * Print newline
137
+ */
138
+ newline() {
139
+ console.log();
140
+ }
141
+ /**
142
+ * Print header
143
+ */
144
+ header(title) {
145
+ console.log();
146
+ console.log(import_chalk.default.bold.cyan(title));
147
+ this.separator();
148
+ }
149
+ /**
150
+ * Print code block
151
+ */
152
+ code(code) {
153
+ console.log(import_chalk.default.gray(code));
154
+ }
155
+ /**
156
+ * Print table
157
+ */
158
+ table(data) {
159
+ if (data.length === 0) return;
160
+ const firstRow = data[0];
161
+ if (!firstRow) return;
162
+ const headers = Object.keys(firstRow);
163
+ const columnWidths = headers.map((header) => {
164
+ const maxDataWidth = Math.max(...data.map((row) => String(row[header] ?? "").length));
165
+ return Math.max(header.length, maxDataWidth);
166
+ });
167
+ const headerRow = headers.map((header, i) => import_chalk.default.bold(header.padEnd(columnWidths[i] ?? 10))).join(" \u2502 ");
168
+ console.log(headerRow);
169
+ const separator = columnWidths.map((width) => "\u2500".repeat(width)).join("\u2500\u253C\u2500");
170
+ console.log(import_chalk.default.gray(separator));
171
+ data.forEach((row) => {
172
+ const dataRow = headers.map((header, i) => String(row[header] ?? "").padEnd(columnWidths[i] ?? 10)).join(" \u2502 ");
173
+ console.log(dataRow);
174
+ });
175
+ }
176
+ };
177
+ var logger = new Logger();
178
+
179
+ // src/commands/add.ts
180
+ var AVAILABLE_COMPONENTS = [
181
+ "button",
182
+ "input",
183
+ "card",
184
+ "badge",
185
+ "toast",
186
+ "modal",
187
+ "dropdown",
188
+ "tabs",
189
+ "accordion",
190
+ "avatar"
191
+ ];
192
+ var COLORS = [
193
+ "primary",
194
+ "secondary",
195
+ "success",
196
+ "warning",
197
+ "error",
198
+ "info",
199
+ "blue",
200
+ "red",
201
+ "green",
202
+ "yellow",
203
+ "purple",
204
+ "gray",
205
+ "orange",
206
+ "amber",
207
+ "lime",
208
+ "emerald",
209
+ "teal",
210
+ "cyan",
211
+ "sky",
212
+ "indigo",
213
+ "violet",
214
+ "fuchsia",
215
+ "pink",
216
+ "rose",
217
+ "slate",
218
+ "zinc",
219
+ "neutral",
220
+ "stone"
221
+ ];
222
+ var SIZES = ["xs", "sm", "md", "lg", "xl", "2xl"];
223
+ var VARIANTS = {
224
+ button: ["solid", "outline", "ghost", "soft", "link"],
225
+ input: ["outlined", "filled", "underlined", "ghost"],
226
+ card: ["elevated", "outlined", "filled", "ghost"],
227
+ badge: ["solid", "soft", "outline", "dot"],
228
+ toast: ["solid", "soft", "outlined", "minimal"]
229
+ };
230
+ var SHAPES = ["square", "rounded", "pill", "circle"];
231
+ var POSITIONS = [
232
+ "top-left",
233
+ "top-center",
234
+ "top-right",
235
+ "bottom-left",
236
+ "bottom-center",
237
+ "bottom-right",
238
+ "left",
239
+ "center",
240
+ "right"
241
+ ];
242
+ var ANIMATIONS = ["none", "subtle", "standard", "smooth", "bounce", "pulse"];
243
+ var ELEVATIONS = ["none", "xs", "sm", "md", "lg", "xl", "2xl", "glow"];
244
+ var A11Y_LEVELS = ["standard", "enhanced", "maximum"];
245
+ var PRESETS = {
246
+ primary: { color: "blue", variant: "solid", size: "md" },
247
+ secondary: { color: "gray", variant: "outline", size: "md" },
248
+ danger: { color: "red", variant: "solid", size: "md" },
249
+ success: { color: "green", variant: "solid", size: "md" },
250
+ warning: { color: "yellow", variant: "solid", size: "md" },
251
+ ghost: { color: "gray", variant: "ghost", size: "md" },
252
+ pill: { color: "blue", variant: "solid", shape: "pill", size: "md" },
253
+ large: { color: "blue", variant: "solid", size: "lg" },
254
+ small: { color: "blue", variant: "solid", size: "sm" }
255
+ };
256
+ var addCommand = new import_commander.Command("add").description("Add a component with variant configuration").argument("[component]", "Component to add (button, input, card, etc.)").option("-c, --color <color>", "Color theme", "blue").option("-s, --size <size>", "Component size", "md").option("-v, --variant <variant>", "Visual style").option("--shape <shape>", "Border radius style", "rounded").option("-p, --position <position>", "Position (for toast, modal)").option("-a, --animation <animation>", "Animation style", "standard").option("-e, --elevation <elevation>", "Shadow depth", "md").option("--a11y <level>", "Accessibility level", "standard").option("--preset <preset>", "Use a preset configuration").option("-i, --interactive", "Interactive mode").option("-o, --output <path>", "Output directory", "./components").option("--dry-run", "Preview without writing files").action(async (component, options) => {
257
+ try {
258
+ logger.header("\u{1F3A8} Nikkory Vibe - Add Component");
259
+ if (options.interactive || !component) {
260
+ const config = await promptVariantConfig();
261
+ component = config.component;
262
+ Object.assign(options, config);
263
+ }
264
+ if (!component || !AVAILABLE_COMPONENTS.includes(component)) {
265
+ logger.error(`Unknown component: ${component ?? "none"}`);
266
+ logger.info(`Available: ${AVAILABLE_COMPONENTS.join(", ")}`);
267
+ process.exit(1);
268
+ }
269
+ const validatedComponent = component;
270
+ if (options.preset) {
271
+ const preset = PRESETS[options.preset];
272
+ if (!preset) {
273
+ logger.error(`Unknown preset: ${options.preset}`);
274
+ logger.info(`Available: ${Object.keys(PRESETS).join(", ")}`);
275
+ process.exit(1);
276
+ }
277
+ Object.assign(options, preset);
278
+ }
279
+ if (options.color && !COLORS.includes(options.color)) {
280
+ logger.warn(`Unknown color: ${options.color}. Using default.`);
281
+ }
282
+ if (options.size && !SIZES.includes(options.size)) {
283
+ logger.warn(`Unknown size: ${options.size}. Using default.`);
284
+ }
285
+ if (options.position && !POSITIONS.includes(options.position)) {
286
+ logger.warn(`Unknown position: ${options.position}. Using default.`);
287
+ }
288
+ if (options.a11y && !A11Y_LEVELS.includes(options.a11y)) {
289
+ logger.warn(`Unknown accessibility level: ${options.a11y}. Using default.`);
290
+ }
291
+ logger.newline();
292
+ logger.info(`Component: ${validatedComponent}`);
293
+ logger.info(`Color: ${options.color ?? "default"}`);
294
+ logger.info(`Size: ${options.size ?? "default"}`);
295
+ logger.info(`Variant: ${options.variant ?? "default"}`);
296
+ logger.info(`Shape: ${options.shape ?? "default"}`);
297
+ if (options.position) {
298
+ logger.info(`Position: ${options.position}`);
299
+ }
300
+ logger.info(`Animation: ${options.animation ?? "default"}`);
301
+ logger.info(`Elevation: ${options.elevation ?? "default"}`);
302
+ logger.info(`Accessibility: ${options.a11y ?? "default"}`);
303
+ logger.newline();
304
+ logger.startSpinner("Generating component...");
305
+ const variantConfig = {
306
+ color: options.color,
307
+ size: options.size,
308
+ variant: options.variant,
309
+ shape: options.shape,
310
+ position: options.position,
311
+ animation: options.animation,
312
+ elevation: options.elevation,
313
+ a11y: options.a11y
314
+ };
315
+ const code = generateComponentCode(validatedComponent, variantConfig);
316
+ logger.stopSpinnerSuccess("Component generated");
317
+ if (options.dryRun) {
318
+ logger.newline();
319
+ logger.header("Generated Code (Preview)");
320
+ logger.code(code);
321
+ logger.newline();
322
+ logger.info("Dry run mode - No files written");
323
+ return;
324
+ }
325
+ const componentName = capitalize(validatedComponent);
326
+ const outputPath = path.join(process.cwd(), options.output, `${componentName}.tsx`);
327
+ logger.startSpinner(`Writing to ${outputPath}...`);
328
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
329
+ await fs.writeFile(outputPath, code, "utf-8");
330
+ logger.stopSpinnerSuccess(`Created: ${outputPath}`);
331
+ logger.newline();
332
+ logger.box(
333
+ `\u2728 ${componentName} component added!
334
+
335
+ File: ${outputPath}
336
+ Color: ${options.color ?? "default"}
337
+ Size: ${options.size ?? "default"}`,
338
+ { title: "Success", borderColor: "green" }
339
+ );
340
+ logger.newline();
341
+ logger.info("Usage:");
342
+ logger.code(` import { ${componentName} } from './components/${componentName}';`);
343
+ logger.code(
344
+ ` <${componentName} color="${options.color ?? "primary"}" size="${options.size ?? "md"}" />`
345
+ );
346
+ logger.newline();
347
+ } catch (error) {
348
+ logger.stopSpinner();
349
+ logger.error("Failed to add component");
350
+ if (error instanceof Error) {
351
+ logger.debug(error.stack || error.message);
352
+ }
353
+ process.exit(1);
354
+ }
355
+ });
356
+ async function promptVariantConfig() {
357
+ const answers = await import_inquirer.default.prompt([
358
+ {
359
+ type: "list",
360
+ name: "component",
361
+ message: "Select component:",
362
+ choices: AVAILABLE_COMPONENTS.map((c) => ({ name: capitalize(c), value: c }))
363
+ },
364
+ {
365
+ type: "list",
366
+ name: "color",
367
+ message: "Color:",
368
+ choices: [
369
+ new import_inquirer.default.Separator("--- Semantic ---"),
370
+ { name: "Primary (Blue)", value: "primary" },
371
+ { name: "Secondary (Purple)", value: "secondary" },
372
+ { name: "Success (Green)", value: "success" },
373
+ { name: "Warning (Yellow)", value: "warning" },
374
+ { name: "Error (Red)", value: "error" },
375
+ { name: "Info (Cyan)", value: "info" },
376
+ new import_inquirer.default.Separator("--- Palette ---"),
377
+ { name: "Blue", value: "blue" },
378
+ { name: "Red", value: "red" },
379
+ { name: "Green", value: "green" },
380
+ { name: "Yellow", value: "yellow" },
381
+ { name: "Purple", value: "purple" },
382
+ { name: "Gray", value: "gray" },
383
+ { name: "Orange", value: "orange" },
384
+ { name: "Pink", value: "pink" }
385
+ ],
386
+ default: "blue"
387
+ },
388
+ {
389
+ type: "list",
390
+ name: "size",
391
+ message: "Size:",
392
+ choices: [
393
+ { name: "Extra Small (xs)", value: "xs" },
394
+ { name: "Small (sm)", value: "sm" },
395
+ { name: "Medium (md)", value: "md" },
396
+ { name: "Large (lg)", value: "lg" },
397
+ { name: "Extra Large (xl)", value: "xl" },
398
+ { name: "2X Large (2xl)", value: "2xl" }
399
+ ],
400
+ default: "md"
401
+ },
402
+ {
403
+ type: "list",
404
+ name: "variant",
405
+ message: "Variant:",
406
+ choices: (answers2) => {
407
+ const comp = answers2.component;
408
+ return (VARIANTS[comp] || ["solid", "outline", "ghost"]).map((v) => ({
409
+ name: capitalize(v),
410
+ value: v
411
+ }));
412
+ }
413
+ },
414
+ {
415
+ type: "list",
416
+ name: "shape",
417
+ message: "Shape:",
418
+ choices: SHAPES.map((s) => ({ name: capitalize(s), value: s })),
419
+ default: "rounded"
420
+ },
421
+ {
422
+ type: "list",
423
+ name: "animation",
424
+ message: "Animation:",
425
+ choices: ANIMATIONS.map((a) => ({ name: capitalize(a), value: a })),
426
+ default: "standard"
427
+ },
428
+ {
429
+ type: "list",
430
+ name: "elevation",
431
+ message: "Elevation/Shadow:",
432
+ choices: ELEVATIONS.map((e) => ({ name: e === "none" ? "None" : e.toUpperCase(), value: e })),
433
+ default: "md"
434
+ }
435
+ ]);
436
+ return answers;
437
+ }
438
+ function capitalize(str) {
439
+ return str.charAt(0).toUpperCase() + str.slice(1);
440
+ }
441
+ function generateComponentCode(component, config) {
442
+ const name = capitalize(component);
443
+ const propsInterface = `${name}Props`;
444
+ return `/**
445
+ * ${name} Component
446
+ *
447
+ * Generated with Nikkory Vibe CLI
448
+ * Configuration: color=${config.color}, size=${config.size}, variant=${config.variant || "default"}
449
+ */
450
+
451
+ 'use client';
452
+
453
+ import React, { forwardRef } from 'react';
454
+ import { ${name} as Vibe${name} } from '@nikkory/vibe-library/core';
455
+
456
+ export interface ${propsInterface} {
457
+ children?: React.ReactNode;
458
+ className?: string;
459
+ // Override default config
460
+ color?: string;
461
+ size?: string;
462
+ variant?: string;
463
+ shape?: string;
464
+ animation?: string;
465
+ elevation?: string;
466
+ }
467
+
468
+ /**
469
+ * Pre-configured ${name} with:
470
+ * - Color: ${config.color}
471
+ * - Size: ${config.size}
472
+ * - Variant: ${config.variant || "default"}
473
+ * - Shape: ${config.shape}
474
+ * - Animation: ${config.animation}
475
+ * - Elevation: ${config.elevation}
476
+ */
477
+ export const ${name} = forwardRef<HTMLElement, ${propsInterface}>(
478
+ (
479
+ {
480
+ children,
481
+ className = '',
482
+ color = '${config.color}',
483
+ size = '${config.size}',
484
+ variant = '${config.variant || "solid"}',
485
+ shape = '${config.shape}',
486
+ animation = '${config.animation}',
487
+ elevation = '${config.elevation}',
488
+ ...props
489
+ },
490
+ ref
491
+ ) => {
492
+ return (
493
+ <Vibe${name}
494
+ ref={ref}
495
+ color={color}
496
+ size={size}
497
+ variant={variant}
498
+ shape={shape}
499
+ animation={animation}
500
+ elevation={elevation}
501
+ className={className}
502
+ {...props}
503
+ >
504
+ {children}
505
+ </Vibe${name}>
506
+ );
507
+ }
508
+ );
509
+
510
+ ${name}.displayName = '${name}';
511
+
512
+ export default ${name};
513
+ `;
514
+ }
515
+
516
+ // src/commands/copy.ts
517
+ var fsSync = __toESM(require("fs"));
518
+ var fs2 = __toESM(require("fs/promises"));
519
+ var path2 = __toESM(require("path"));
520
+ var import_commander2 = require("commander");
521
+ var DESIGN_SYSTEMS = [
522
+ "material-design",
523
+ "ios-hig",
524
+ "glassmorphism",
525
+ "neumorphism",
526
+ "minimalism",
527
+ "brutalism"
528
+ ];
529
+ var TIERS = ["basic", "standard", "enterprise"];
530
+ var COMPONENTS = [
531
+ // Core
532
+ "button",
533
+ "input",
534
+ "textarea",
535
+ "select",
536
+ "checkbox",
537
+ "radio",
538
+ "switch",
539
+ "slider",
540
+ // Display
541
+ "badge",
542
+ "avatar",
543
+ "card",
544
+ "tooltip",
545
+ "popover",
546
+ // Feedback
547
+ "alert",
548
+ "toast",
549
+ "progress",
550
+ "spinner",
551
+ "skeleton",
552
+ // Navigation
553
+ "tabs",
554
+ "breadcrumb",
555
+ "pagination",
556
+ "stepper",
557
+ "menu",
558
+ // Overlay
559
+ "modal",
560
+ "drawer",
561
+ "dropdown",
562
+ "dialog",
563
+ // Data
564
+ "table",
565
+ "list",
566
+ "tree",
567
+ "timeline",
568
+ // Media
569
+ "image",
570
+ "video",
571
+ "audio",
572
+ "carousel",
573
+ "gallery",
574
+ // Form
575
+ "form",
576
+ "field",
577
+ "label",
578
+ "error-message",
579
+ // Layout
580
+ "container",
581
+ "grid",
582
+ "flex",
583
+ "divider",
584
+ "spacer",
585
+ // Typography
586
+ "heading",
587
+ "text",
588
+ "link",
589
+ "code",
590
+ // Charts
591
+ "chart",
592
+ "sparkline",
593
+ "gauge",
594
+ // Special
595
+ "rating",
596
+ "transfer",
597
+ "color-picker",
598
+ "date-picker",
599
+ "file-upload"
600
+ ];
601
+ var DESIGN_ALIASES = {
602
+ material: "material-design",
603
+ md: "material-design",
604
+ ios: "ios-hig",
605
+ hig: "ios-hig",
606
+ glass: "glassmorphism",
607
+ neu: "neumorphism",
608
+ neomorphism: "neumorphism",
609
+ minimal: "minimalism",
610
+ min: "minimalism",
611
+ brutal: "brutalism"
612
+ };
613
+ var copyCommand = new import_commander2.Command("copy").alias("cp").description("Copy pre-built components from the library (zero-token)").argument(
614
+ "[component]",
615
+ "Component to copy (button, card, etc. or path like button/glassmorphism/enterprise)"
616
+ ).option("-d, --design <design>", "Design system", "material-design").option("-t, --tier <tier>", "Quality tier", "standard").option("-o, --output <path>", "Output directory", "./components").option("--overwrite", "Overwrite existing files").option("--dry-run", "Preview without copying").option("--all", "Copy all components for the design/tier").action(async (component, options) => {
617
+ try {
618
+ logger.header("\u{1F4CB} Nikkory Vibe - Zero-Token Copy");
619
+ if (options.all) {
620
+ await copyAllComponents(options);
621
+ return;
622
+ }
623
+ if (!component) {
624
+ logger.error("Please specify a component to copy");
625
+ logger.newline();
626
+ logger.info("Usage:");
627
+ logger.code(" vibe copy button");
628
+ logger.code(" vibe copy button/glassmorphism");
629
+ logger.code(" vibe copy button/glassmorphism/enterprise");
630
+ logger.code(" vibe copy --all --design=brutalism");
631
+ logger.newline();
632
+ logger.info("Available components:");
633
+ logger.code(` ${COMPONENTS.slice(0, 10).join(", ")}...`);
634
+ logger.info(` Run 'vibe list templates' for full list`);
635
+ process.exit(1);
636
+ }
637
+ const parsed = parseComponentPath(component, options);
638
+ if (!validateComponentPath(parsed)) {
639
+ process.exit(1);
640
+ }
641
+ logger.newline();
642
+ logger.info(`Component: ${capitalize2(parsed.component)}`);
643
+ logger.info(`Design System: ${formatDesignSystem(parsed.designSystem)}`);
644
+ logger.info(`Tier: ${capitalize2(parsed.tier)}`);
645
+ logger.newline();
646
+ await copyComponent(parsed, options);
647
+ } catch (error) {
648
+ logger.stopSpinner();
649
+ logger.error("Copy failed");
650
+ if (error instanceof Error) {
651
+ logger.debug(error.stack || error.message);
652
+ }
653
+ process.exit(1);
654
+ }
655
+ });
656
+ function parseComponentPath(input, options) {
657
+ const parts = input.split("/").filter(Boolean);
658
+ const component = parts[0] ?? "";
659
+ let designSystem = options.design ?? "material-design";
660
+ let tier = options.tier ?? "standard";
661
+ if (parts.length === 2 && parts[1]) {
662
+ designSystem = normalizeDesignSystem(parts[1]);
663
+ } else if (parts.length >= 3 && parts[1] && parts[2]) {
664
+ designSystem = normalizeDesignSystem(parts[1]);
665
+ tier = parts[2];
666
+ }
667
+ designSystem = normalizeDesignSystem(designSystem);
668
+ return { component, designSystem, tier };
669
+ }
670
+ function normalizeDesignSystem(design) {
671
+ const lower = design.toLowerCase();
672
+ return DESIGN_ALIASES[lower] || lower;
673
+ }
674
+ function validateComponentPath(parsed) {
675
+ if (!COMPONENTS.includes(parsed.component)) {
676
+ logger.error(`Unknown component: ${parsed.component}`);
677
+ logger.info(`Available: ${COMPONENTS.slice(0, 8).join(", ")}...`);
678
+ return false;
679
+ }
680
+ if (!DESIGN_SYSTEMS.includes(parsed.designSystem)) {
681
+ logger.error(`Unknown design system: ${parsed.designSystem}`);
682
+ logger.info(`Available: ${DESIGN_SYSTEMS.join(", ")}`);
683
+ return false;
684
+ }
685
+ if (!TIERS.includes(parsed.tier)) {
686
+ logger.error(`Unknown tier: ${parsed.tier}`);
687
+ logger.info(`Available: ${TIERS.join(", ")}`);
688
+ return false;
689
+ }
690
+ return true;
691
+ }
692
+ async function copyComponent(parsed, options) {
693
+ const { component, designSystem, tier } = parsed;
694
+ const libraryRoot = findLibraryRoot();
695
+ const sourcePath = path2.join(
696
+ libraryRoot,
697
+ "src",
698
+ "components",
699
+ component,
700
+ designSystem,
701
+ `${tier}.tsx`
702
+ );
703
+ const sourceExists = await fileExists(sourcePath);
704
+ if (!sourceExists) {
705
+ logger.error(`Component not found: ${sourcePath}`);
706
+ logger.info("This component may not be available yet.");
707
+ logger.info("Run `vibe list templates` to see available components.");
708
+ process.exit(1);
709
+ }
710
+ const outputDir = path2.join(process.cwd(), options.output || "./components");
711
+ const fileName = `${capitalize2(component)}.tsx`;
712
+ const outputPath = path2.join(outputDir, fileName);
713
+ const outputExists = await fileExists(outputPath);
714
+ if (outputExists && !options.overwrite) {
715
+ logger.error(`File already exists: ${outputPath}`);
716
+ logger.info("Use --overwrite to replace it");
717
+ process.exit(1);
718
+ }
719
+ logger.startSpinner(`Reading ${component}...`);
720
+ const sourceCode = await fs2.readFile(sourcePath, "utf-8");
721
+ logger.stopSpinnerSuccess("Source loaded");
722
+ const transformedCode = transformComponent(sourceCode, parsed);
723
+ if (options.dryRun) {
724
+ logger.newline();
725
+ logger.header("Preview (Dry Run)");
726
+ logger.code(`${transformedCode.slice(0, 1e3)}
727
+ ...`);
728
+ logger.newline();
729
+ logger.info(`Would write to: ${outputPath}`);
730
+ logger.info(`Lines: ${transformedCode.split("\n").length}`);
731
+ return;
732
+ }
733
+ logger.startSpinner(`Writing to ${outputPath}...`);
734
+ await fs2.mkdir(outputDir, { recursive: true });
735
+ await fs2.writeFile(outputPath, transformedCode, "utf-8");
736
+ logger.stopSpinnerSuccess("Component copied");
737
+ logger.newline();
738
+ logger.box(
739
+ `\u2728 ${capitalize2(component)} copied successfully!
740
+
741
+ File: ${outputPath}
742
+ Design: ${formatDesignSystem(designSystem)}
743
+ Tier: ${capitalize2(tier)}
744
+ Lines: ${transformedCode.split("\n").length}`,
745
+ { title: "Success", borderColor: "green" }
746
+ );
747
+ logger.newline();
748
+ logger.info("Usage:");
749
+ logger.code(
750
+ ` import { ${capitalize2(component)} } from './components/${capitalize2(component)}';`
751
+ );
752
+ logger.newline();
753
+ }
754
+ async function copyAllComponents(options) {
755
+ const designSystem = normalizeDesignSystem(options.design || "material-design");
756
+ const tier = options.tier || "standard";
757
+ logger.newline();
758
+ logger.info(`Copying all components...`);
759
+ logger.info(`Design System: ${formatDesignSystem(designSystem)}`);
760
+ logger.info(`Tier: ${capitalize2(tier)}`);
761
+ logger.newline();
762
+ const libraryRoot = findLibraryRoot();
763
+ let copied = 0;
764
+ let skipped = 0;
765
+ const errors = [];
766
+ for (const component of COMPONENTS) {
767
+ const sourcePath = path2.join(
768
+ libraryRoot,
769
+ "src",
770
+ "components",
771
+ component,
772
+ designSystem,
773
+ `${tier}.tsx`
774
+ );
775
+ const exists = await fileExists(sourcePath);
776
+ if (!exists) {
777
+ skipped++;
778
+ continue;
779
+ }
780
+ try {
781
+ await copyComponent({ component, designSystem, tier }, { ...options, all: false });
782
+ copied++;
783
+ } catch (error) {
784
+ errors.push(component);
785
+ }
786
+ }
787
+ logger.newline();
788
+ logger.box(
789
+ `\u{1F4E6} Bulk Copy Complete
790
+
791
+ Copied: ${copied} components
792
+ Skipped: ${skipped} (not available)
793
+ Errors: ${errors.length}`,
794
+ { title: "Summary", borderColor: copied > 0 ? "green" : "yellow" }
795
+ );
796
+ if (errors.length > 0) {
797
+ logger.warn(`Failed: ${errors.join(", ")}`);
798
+ }
799
+ }
800
+ function transformComponent(code, parsed) {
801
+ const { component, designSystem, tier } = parsed;
802
+ const header = `/**
803
+ * ${capitalize2(component)} Component
804
+ *
805
+ * Copied from @nikkory/vibe-library
806
+ * Design System: ${formatDesignSystem(designSystem)}
807
+ * Tier: ${capitalize2(tier)}
808
+ *
809
+ * Zero-token generation - No AI needed
810
+ * Just copy, paste, and customize!
811
+ */
812
+
813
+ `;
814
+ let transformed = code;
815
+ transformed = transformed.replace(/from ['"]@nikkory\/vibe-library\/core['"]/g, "from './core'");
816
+ transformed = transformed.replace(/from ['"]@nikkory\/vibe-library['"]/g, "from './index'");
817
+ if (!transformed.includes("'use client'")) {
818
+ transformed = `'use client';
819
+
820
+ ${transformed}`;
821
+ }
822
+ return `${header}${transformed}`;
823
+ }
824
+ function findLibraryRoot() {
825
+ const possiblePaths = [
826
+ path2.join(process.cwd(), "node_modules", "@nikkory", "vibe-library"),
827
+ path2.join(process.cwd(), "..", "..", "packages", "library"),
828
+ path2.join(__dirname, "..", "..", "..", "library"),
829
+ // Development path
830
+ "m:/AI Workspace/nikkory-vibe/packages/library"
831
+ ];
832
+ for (const p of possiblePaths) {
833
+ try {
834
+ fsSync.accessSync(p);
835
+ return p;
836
+ } catch {
837
+ }
838
+ }
839
+ return possiblePaths[possiblePaths.length - 1] ?? "m:/AI Workspace/nikkory-vibe/packages/library";
840
+ }
841
+ async function fileExists(filePath) {
842
+ try {
843
+ await fs2.access(filePath);
844
+ return true;
845
+ } catch {
846
+ return false;
847
+ }
848
+ }
849
+ function capitalize2(str) {
850
+ return str.charAt(0).toUpperCase() + str.slice(1);
851
+ }
852
+ function formatDesignSystem(design) {
853
+ const names = {
854
+ "material-design": "Material Design",
855
+ "ios-hig": "iOS HIG",
856
+ glassmorphism: "Glassmorphism",
857
+ neumorphism: "Neumorphism",
858
+ minimalism: "Minimalism",
859
+ brutalism: "Brutalism"
860
+ };
861
+ return names[design] || capitalize2(design);
862
+ }
863
+
864
+ // src/commands/generate.ts
865
+ var fs3 = __toESM(require("fs/promises"));
866
+ var path3 = __toESM(require("path"));
867
+ var import_vibe_core = require("@nikkory/vibe-core");
868
+ var import_commander3 = require("commander");
869
+
870
+ // src/utils/prompts.ts
871
+ var import_inquirer2 = __toESM(require("inquirer"));
872
+ async function promptComponentConfig() {
873
+ const answers = await import_inquirer2.default.prompt([
874
+ {
875
+ type: "input",
876
+ name: "name",
877
+ message: "Component name (PascalCase):",
878
+ validate: (input) => {
879
+ if (!input) return "Component name is required";
880
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(input)) {
881
+ return "Component name must be PascalCase (e.g., MyButton)";
882
+ }
883
+ return true;
884
+ }
885
+ },
886
+ {
887
+ type: "list",
888
+ name: "template",
889
+ message: "Template type:",
890
+ choices: [
891
+ { name: "Button", value: "button" },
892
+ { name: "Card", value: "card" },
893
+ { name: "Input", value: "input" },
894
+ { name: "Modal", value: "modal" },
895
+ { name: "Table", value: "table" }
896
+ ]
897
+ },
898
+ {
899
+ type: "list",
900
+ name: "designSystem",
901
+ message: "Design system:",
902
+ choices: [
903
+ { name: "Material Design 3", value: "material-design" },
904
+ { name: "iOS Human Interface Guidelines", value: "ios-hig" },
905
+ { name: "Glassmorphism", value: "glassmorphism" },
906
+ { name: "Neumorphism", value: "neumorphism" },
907
+ { name: "Minimalism", value: "minimalism" }
908
+ ]
909
+ },
910
+ {
911
+ type: "list",
912
+ name: "tier",
913
+ message: "Quality tier:",
914
+ choices: [
915
+ { name: "Basic (Prototype)", value: "basic" },
916
+ { name: "Standard (Production)", value: "standard" },
917
+ { name: "Enterprise (Mission-critical)", value: "enterprise" }
918
+ ],
919
+ default: "standard"
920
+ },
921
+ {
922
+ type: "list",
923
+ name: "framework",
924
+ message: "Framework:",
925
+ choices: [
926
+ { name: "React", value: "react" },
927
+ { name: "Vue", value: "vue" },
928
+ { name: "Angular", value: "angular" },
929
+ { name: "Svelte", value: "svelte" },
930
+ { name: "Solid", value: "solid" }
931
+ ],
932
+ default: "react"
933
+ }
934
+ ]);
935
+ return answers;
936
+ }
937
+ async function promptProjectInit() {
938
+ const answers = await import_inquirer2.default.prompt([
939
+ {
940
+ type: "input",
941
+ name: "projectName",
942
+ message: "Project name:",
943
+ validate: (input) => {
944
+ if (!input) return "Project name is required";
945
+ if (!/^[a-z][a-z0-9-]*$/.test(input)) {
946
+ return "Project name must be lowercase kebab-case (e.g., my-app)";
947
+ }
948
+ return true;
949
+ }
950
+ },
951
+ {
952
+ type: "list",
953
+ name: "framework",
954
+ message: "Frontend framework:",
955
+ choices: [
956
+ { name: "React (Next.js)", value: "react" },
957
+ { name: "Vue (Nuxt)", value: "vue" },
958
+ { name: "Angular", value: "angular" },
959
+ { name: "Svelte (SvelteKit)", value: "svelte" },
960
+ { name: "Solid (SolidStart)", value: "solid" }
961
+ ],
962
+ default: "react"
963
+ },
964
+ {
965
+ type: "list",
966
+ name: "designSystem",
967
+ message: "Default design system:",
968
+ choices: [
969
+ { name: "Material Design 3", value: "material-design" },
970
+ { name: "iOS HIG", value: "ios-hig" },
971
+ { name: "Glassmorphism", value: "glassmorphism" },
972
+ { name: "Custom", value: "custom" }
973
+ ],
974
+ default: "material-design"
975
+ },
976
+ {
977
+ type: "confirm",
978
+ name: "includeBackend",
979
+ message: "Include backend (NestJS)?",
980
+ default: false
981
+ }
982
+ ]);
983
+ return answers;
984
+ }
985
+ async function promptSectionConfig() {
986
+ const answers = await import_inquirer2.default.prompt([
987
+ {
988
+ type: "input",
989
+ name: "name",
990
+ message: "Section name (PascalCase):",
991
+ validate: (input) => {
992
+ if (!input) return "Section name is required";
993
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(input)) {
994
+ return "Section name must be PascalCase (e.g., HeroSection)";
995
+ }
996
+ return true;
997
+ }
998
+ },
999
+ {
1000
+ type: "list",
1001
+ name: "template",
1002
+ message: "Section template:",
1003
+ choices: [
1004
+ // Hero sections
1005
+ { name: "Hero - Centered", value: "hero-centered" },
1006
+ { name: "Hero - Split (Image + Text)", value: "hero-split" },
1007
+ { name: "Hero - Background Image", value: "hero-background" },
1008
+ { name: "Hero - Video Background", value: "hero-video" },
1009
+ // Features sections
1010
+ { name: "Features - Grid", value: "features-grid" },
1011
+ { name: "Features - List", value: "features-list" },
1012
+ { name: "Features - Alternating", value: "features-alternating" },
1013
+ // CTA sections
1014
+ { name: "CTA - Banner", value: "cta-banner" },
1015
+ { name: "CTA - Centered", value: "cta-centered" },
1016
+ { name: "CTA - Split", value: "cta-split" },
1017
+ // Pricing sections
1018
+ { name: "Pricing - Cards", value: "pricing-cards" },
1019
+ { name: "Pricing - Table", value: "pricing-table" },
1020
+ // Testimonial sections
1021
+ { name: "Testimonials - Grid", value: "testimonials-grid" },
1022
+ { name: "Testimonials - Carousel", value: "testimonials-carousel" },
1023
+ // Other sections
1024
+ { name: "FAQ - Accordion", value: "faq-accordion" },
1025
+ { name: "Team - Grid", value: "team-grid" },
1026
+ { name: "Stats - Grid", value: "stats-grid" },
1027
+ { name: "Logo Cloud", value: "logo-cloud" },
1028
+ { name: "Newsletter", value: "newsletter" },
1029
+ { name: "Contact Form", value: "contact-form" }
1030
+ ]
1031
+ },
1032
+ {
1033
+ type: "list",
1034
+ name: "designSystem",
1035
+ message: "Design system:",
1036
+ choices: [
1037
+ { name: "Material Design 3", value: "material-design" },
1038
+ { name: "iOS Human Interface Guidelines", value: "ios-hig" },
1039
+ { name: "Glassmorphism", value: "glassmorphism" },
1040
+ { name: "Neumorphism", value: "neumorphism" },
1041
+ { name: "Brutalism", value: "brutalism" },
1042
+ { name: "Minimalism", value: "minimalism" }
1043
+ ]
1044
+ },
1045
+ {
1046
+ type: "list",
1047
+ name: "tier",
1048
+ message: "Quality tier:",
1049
+ choices: [
1050
+ { name: "Basic (Prototype)", value: "basic" },
1051
+ { name: "Standard (Production)", value: "standard" },
1052
+ { name: "Enterprise (Mission-critical)", value: "enterprise" }
1053
+ ],
1054
+ default: "standard"
1055
+ },
1056
+ {
1057
+ type: "list",
1058
+ name: "framework",
1059
+ message: "Framework:",
1060
+ choices: [
1061
+ { name: "React", value: "react" },
1062
+ { name: "Vue", value: "vue" },
1063
+ { name: "Angular", value: "angular" },
1064
+ { name: "Svelte", value: "svelte" },
1065
+ { name: "Solid", value: "solid" }
1066
+ ],
1067
+ default: "react"
1068
+ },
1069
+ {
1070
+ type: "input",
1071
+ name: "heading",
1072
+ message: "Section heading:",
1073
+ default: "Welcome to Your App"
1074
+ },
1075
+ {
1076
+ type: "input",
1077
+ name: "subheading",
1078
+ message: "Section subheading (optional):",
1079
+ default: ""
1080
+ },
1081
+ {
1082
+ type: "input",
1083
+ name: "description",
1084
+ message: "Section description (optional):",
1085
+ default: ""
1086
+ },
1087
+ {
1088
+ type: "input",
1089
+ name: "ctaText",
1090
+ message: "Call-to-action button text:",
1091
+ default: "Get Started"
1092
+ },
1093
+ {
1094
+ type: "input",
1095
+ name: "ctaHref",
1096
+ message: "Call-to-action button link:",
1097
+ default: "#"
1098
+ }
1099
+ ]);
1100
+ return answers;
1101
+ }
1102
+ async function promptGenerationType() {
1103
+ const answer = await import_inquirer2.default.prompt([
1104
+ {
1105
+ type: "list",
1106
+ name: "type",
1107
+ message: "What do you want to generate?",
1108
+ choices: [
1109
+ { name: "Component (Button, Card, Input, etc.)", value: "component" },
1110
+ { name: "Section (Hero, Features, CTA, etc.)", value: "section" },
1111
+ { name: "Page (Landing, Dashboard, Auth, etc.)", value: "page" }
1112
+ ]
1113
+ }
1114
+ ]);
1115
+ return answer.type;
1116
+ }
1117
+ async function promptPageConfig() {
1118
+ const answers = await import_inquirer2.default.prompt([
1119
+ {
1120
+ type: "input",
1121
+ name: "name",
1122
+ message: "Page name (PascalCase):",
1123
+ validate: (input) => {
1124
+ if (!input) return "Page name is required";
1125
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(input)) {
1126
+ return "Page name must be PascalCase (e.g., HomePage)";
1127
+ }
1128
+ return true;
1129
+ }
1130
+ },
1131
+ {
1132
+ type: "list",
1133
+ name: "template",
1134
+ message: "Page template:",
1135
+ choices: [
1136
+ // Landing pages
1137
+ { name: "Landing - SaaS Product", value: "landing-saas" },
1138
+ { name: "Landing - Product Showcase", value: "landing-product" },
1139
+ { name: "Landing - Agency", value: "landing-agency" },
1140
+ { name: "Landing - Startup", value: "landing-startup" },
1141
+ { name: "Landing - Mobile App", value: "landing-app" },
1142
+ // Marketing pages
1143
+ { name: "Marketing - Simple", value: "marketing-simple" },
1144
+ { name: "Marketing - Feature", value: "marketing-feature" },
1145
+ { name: "Marketing - Pricing", value: "marketing-pricing" },
1146
+ // Dashboard pages
1147
+ { name: "Dashboard - Overview", value: "dashboard-overview" },
1148
+ { name: "Dashboard - Analytics", value: "dashboard-analytics" },
1149
+ { name: "Dashboard - Settings", value: "dashboard-settings" },
1150
+ // Auth pages
1151
+ { name: "Auth - Login", value: "auth-login" },
1152
+ { name: "Auth - Register", value: "auth-register" },
1153
+ { name: "Auth - Forgot Password", value: "auth-forgot-password" },
1154
+ // E-commerce pages
1155
+ { name: "E-commerce - Home", value: "ecommerce-home" },
1156
+ { name: "E-commerce - Product", value: "ecommerce-product" },
1157
+ { name: "E-commerce - Cart", value: "ecommerce-cart" },
1158
+ // Error pages
1159
+ { name: "Error - 404 Not Found", value: "error-404" },
1160
+ { name: "Error - 500 Server Error", value: "error-500" },
1161
+ { name: "Error - Maintenance", value: "error-maintenance" },
1162
+ // Content pages
1163
+ { name: "Content - Blog List", value: "content-blog-list" },
1164
+ { name: "Content - Blog Post", value: "content-blog-post" },
1165
+ { name: "Content - About", value: "content-about" },
1166
+ { name: "Content - Contact", value: "content-contact" }
1167
+ ]
1168
+ },
1169
+ {
1170
+ type: "list",
1171
+ name: "designSystem",
1172
+ message: "Design system:",
1173
+ choices: [
1174
+ { name: "Material Design 3", value: "material-design" },
1175
+ { name: "iOS Human Interface Guidelines", value: "ios-hig" },
1176
+ { name: "Glassmorphism", value: "glassmorphism" },
1177
+ { name: "Neumorphism", value: "neumorphism" },
1178
+ { name: "Brutalism", value: "brutalism" },
1179
+ { name: "Minimalism", value: "minimalism" }
1180
+ ]
1181
+ },
1182
+ {
1183
+ type: "list",
1184
+ name: "tier",
1185
+ message: "Quality tier:",
1186
+ choices: [
1187
+ { name: "Basic (Prototype)", value: "basic" },
1188
+ { name: "Standard (Production)", value: "standard" },
1189
+ { name: "Enterprise (Mission-critical)", value: "enterprise" }
1190
+ ],
1191
+ default: "standard"
1192
+ },
1193
+ {
1194
+ type: "list",
1195
+ name: "framework",
1196
+ message: "Framework:",
1197
+ choices: [
1198
+ { name: "React", value: "react" },
1199
+ { name: "Next.js", value: "nextjs" },
1200
+ { name: "Remix", value: "remix" },
1201
+ { name: "Astro", value: "astro" }
1202
+ ],
1203
+ default: "react"
1204
+ },
1205
+ {
1206
+ type: "input",
1207
+ name: "title",
1208
+ message: "Page title (for SEO):",
1209
+ default: "My Page"
1210
+ },
1211
+ {
1212
+ type: "input",
1213
+ name: "description",
1214
+ message: "Page description (for SEO):",
1215
+ default: "A great page built with Nikkory Vibe"
1216
+ }
1217
+ ]);
1218
+ return answers;
1219
+ }
1220
+
1221
+ // src/commands/generate.ts
1222
+ var generateCommand = new import_commander3.Command("generate").alias("g").description("Generate components, sections, or pages from templates").argument("[type]", "Type to generate (component, section, page)").option("-n, --name <name>", "Name (PascalCase)").option("-t, --template <template>", "Template type").option("-d, --design <system>", "Design system", "material-design").option("--tier <tier>", "Quality tier (basic, standard, enterprise)", "standard").option("-f, --framework <framework>", "Framework (react, vue, etc.)", "react").option("-o, --output <path>", "Output file path").option("--dry-run", "Preview generated code without writing").option("--interactive", "Interactive mode with prompts").option("--heading <text>", "Section heading (for sections)").option("--subheading <text>", "Section subheading (for sections)").option("--description <text>", "Section description (for sections)").option("--cta-text <text>", "CTA button text (for sections)").option("--cta-href <url>", "CTA button link (for sections)").option("--title <text>", "Page title for SEO (for pages)").action(async (type, options) => {
1223
+ try {
1224
+ logger.header("\u{1F3A8} Nikkory Vibe - Code Generator");
1225
+ let generationType = type;
1226
+ if (!generationType || options.interactive) {
1227
+ generationType = await promptGenerationType();
1228
+ }
1229
+ switch (generationType) {
1230
+ case "component":
1231
+ await generateComponent(options);
1232
+ break;
1233
+ case "section":
1234
+ await generateSection(options);
1235
+ break;
1236
+ case "page":
1237
+ await generatePage(options);
1238
+ break;
1239
+ default:
1240
+ await generateComponent(options);
1241
+ }
1242
+ } catch (error) {
1243
+ logger.stopSpinner();
1244
+ logger.error("Unexpected error occurred");
1245
+ if (error instanceof Error) {
1246
+ logger.debug(error.stack || error.message);
1247
+ }
1248
+ process.exit(1);
1249
+ }
1250
+ });
1251
+ async function generateComponent(options) {
1252
+ let config;
1253
+ if (options.interactive ?? !options.name) {
1254
+ config = await promptComponentConfig();
1255
+ } else {
1256
+ config = {
1257
+ name: options.name ?? "",
1258
+ template: options.template ?? "button",
1259
+ framework: options.framework ?? "react",
1260
+ designSystem: options.design ?? "material-design",
1261
+ tier: options.tier ?? "standard"
1262
+ };
1263
+ }
1264
+ if (!config.name) {
1265
+ logger.error("Component name is required");
1266
+ process.exit(1);
1267
+ }
1268
+ logger.newline();
1269
+ logger.info(`Generating ${config.tier} ${config.template} component...`);
1270
+ logger.info(`Design System: ${config.designSystem}`);
1271
+ logger.info(`Framework: ${config.framework}`);
1272
+ logger.newline();
1273
+ logger.startSpinner("Loading template...");
1274
+ const generator = new import_vibe_core.ComponentGenerator();
1275
+ const result = await generator.generate({
1276
+ name: config.name,
1277
+ template: config.template,
1278
+ designSystem: config.designSystem,
1279
+ tier: config.tier,
1280
+ framework: config.framework,
1281
+ outputPath: options.output
1282
+ });
1283
+ if (result.isFailure()) {
1284
+ logger.stopSpinnerFail("Generation failed");
1285
+ logger.error(result.getError().message);
1286
+ process.exit(1);
1287
+ }
1288
+ logger.stopSpinnerSuccess("Template loaded");
1289
+ const code = result.getValue();
1290
+ if (options.dryRun) {
1291
+ logger.newline();
1292
+ logger.header("Generated Code (Preview)");
1293
+ logger.code(code);
1294
+ logger.newline();
1295
+ logger.info("Dry run mode - No files written");
1296
+ return;
1297
+ }
1298
+ const outputPath = options.output ?? generateComponentPath(config);
1299
+ logger.startSpinner(`Writing to ${outputPath}...`);
1300
+ await fs3.mkdir(path3.dirname(outputPath), { recursive: true });
1301
+ await fs3.writeFile(outputPath, code, "utf-8");
1302
+ logger.stopSpinnerSuccess(`Component created: ${outputPath}`);
1303
+ logger.newline();
1304
+ logger.box(
1305
+ `\u2728 ${config.name} component generated successfully!
1306
+
1307
+ File: ${outputPath}
1308
+ Lines: ${code.split("\n").length}
1309
+ Design: ${config.designSystem}
1310
+ Tier: ${config.tier}`,
1311
+ { title: "Success", borderColor: "green" }
1312
+ );
1313
+ printNextSteps("component");
1314
+ }
1315
+ async function generateSection(options) {
1316
+ let config;
1317
+ if (options.interactive ?? !options.name) {
1318
+ config = await promptSectionConfig();
1319
+ } else {
1320
+ config = {
1321
+ name: options.name ?? "",
1322
+ template: options.template ?? "hero-centered",
1323
+ framework: options.framework ?? "react",
1324
+ designSystem: options.design ?? "material-design",
1325
+ tier: options.tier ?? "standard",
1326
+ heading: options.heading ?? "Welcome to Your App",
1327
+ subheading: options.subheading ?? "",
1328
+ description: options.description ?? "",
1329
+ ctaText: options.ctaText ?? "Get Started",
1330
+ ctaHref: options.ctaHref ?? "#"
1331
+ };
1332
+ }
1333
+ if (!config.name) {
1334
+ logger.error("Section name is required");
1335
+ process.exit(1);
1336
+ }
1337
+ logger.newline();
1338
+ logger.info(`Generating ${config.tier} ${config.template} section...`);
1339
+ logger.info(`Design System: ${config.designSystem}`);
1340
+ logger.info(`Framework: ${config.framework}`);
1341
+ logger.newline();
1342
+ const sectionConfig = {
1343
+ name: config.name,
1344
+ template: config.template,
1345
+ designSystem: config.designSystem,
1346
+ tier: config.tier,
1347
+ framework: config.framework,
1348
+ outputPath: options.output,
1349
+ content: {
1350
+ heading: config.heading,
1351
+ subheading: config.subheading || void 0,
1352
+ description: config.description || void 0,
1353
+ cta: config.ctaText ? {
1354
+ text: config.ctaText,
1355
+ href: config.ctaHref || "#"
1356
+ } : void 0
1357
+ }
1358
+ };
1359
+ logger.startSpinner("Generating section...");
1360
+ const generator = new import_vibe_core.SectionGenerator();
1361
+ const result = await generator.generateSection(sectionConfig);
1362
+ if (result.isFailure()) {
1363
+ logger.stopSpinnerFail("Generation failed");
1364
+ logger.error(result.getError().message);
1365
+ process.exit(1);
1366
+ }
1367
+ logger.stopSpinnerSuccess("Section generated");
1368
+ const sectionResult = result.getValue();
1369
+ if (options.dryRun) {
1370
+ logger.newline();
1371
+ logger.header("Generated Code (Preview)");
1372
+ logger.code(sectionResult.code);
1373
+ logger.newline();
1374
+ logger.info("Dry run mode - No files written");
1375
+ logger.newline();
1376
+ logger.info("Metadata:");
1377
+ logger.info(` Template: ${sectionResult.metadata.template}`);
1378
+ logger.info(` Lines of code: ${sectionResult.metadata.linesOfCode}`);
1379
+ logger.info(` Child components: ${sectionResult.metadata.childComponentCount}`);
1380
+ return;
1381
+ }
1382
+ const outputPath = options.output ?? generateSectionPath(config);
1383
+ logger.startSpinner(`Writing to ${outputPath}...`);
1384
+ await fs3.mkdir(path3.dirname(outputPath), { recursive: true });
1385
+ await fs3.writeFile(outputPath, sectionResult.code, "utf-8");
1386
+ logger.stopSpinnerSuccess(`Section created: ${outputPath}`);
1387
+ logger.newline();
1388
+ logger.box(
1389
+ `\u2728 ${config.name} section generated successfully!
1390
+
1391
+ File: ${outputPath}
1392
+ Template: ${config.template}
1393
+ Lines: ${sectionResult.metadata.linesOfCode}
1394
+ Design: ${config.designSystem}
1395
+ Tier: ${config.tier}`,
1396
+ { title: "Success", borderColor: "green" }
1397
+ );
1398
+ printNextSteps("section");
1399
+ }
1400
+ async function generatePage(options) {
1401
+ let config;
1402
+ if (options.interactive ?? !options.name) {
1403
+ config = await promptPageConfig();
1404
+ } else {
1405
+ config = {
1406
+ name: options.name ?? "",
1407
+ template: options.template ?? "landing-saas",
1408
+ framework: options.framework ?? "react",
1409
+ designSystem: options.design ?? "material-design",
1410
+ tier: options.tier ?? "standard",
1411
+ title: options.title ?? "My Page",
1412
+ description: options.description ?? ""
1413
+ };
1414
+ }
1415
+ if (!config.name) {
1416
+ logger.error("Page name is required");
1417
+ process.exit(1);
1418
+ }
1419
+ logger.newline();
1420
+ logger.info(`Generating ${config.tier} ${config.template} page...`);
1421
+ logger.info(`Design System: ${config.designSystem}`);
1422
+ logger.info(`Framework: ${config.framework}`);
1423
+ logger.newline();
1424
+ const pageConfig = {
1425
+ name: config.name,
1426
+ template: config.template,
1427
+ designSystem: config.designSystem,
1428
+ tier: config.tier,
1429
+ framework: config.framework,
1430
+ outputPath: options.output,
1431
+ meta: {
1432
+ title: config.title,
1433
+ description: config.description || void 0
1434
+ }
1435
+ };
1436
+ logger.startSpinner("Generating page...");
1437
+ const generator = new import_vibe_core.PageGenerator();
1438
+ const result = await generator.generatePage(pageConfig);
1439
+ if (result.isFailure()) {
1440
+ logger.stopSpinnerFail("Generation failed");
1441
+ logger.error(result.getError().message);
1442
+ process.exit(1);
1443
+ }
1444
+ logger.stopSpinnerSuccess("Page generated");
1445
+ const pageResult = result.getValue();
1446
+ if (options.dryRun) {
1447
+ logger.newline();
1448
+ logger.header("Generated Code (Preview)");
1449
+ logger.code(pageResult.code);
1450
+ logger.newline();
1451
+ logger.info("Dry run mode - No files written");
1452
+ logger.newline();
1453
+ logger.info("Metadata:");
1454
+ logger.info(` Template: ${pageResult.metadata.template}`);
1455
+ logger.info(` Framework: ${pageResult.metadata.framework}`);
1456
+ logger.info(` Lines of code: ${pageResult.metadata.linesOfCode}`);
1457
+ logger.info(` Sections: ${pageResult.metadata.sectionCount}`);
1458
+ return;
1459
+ }
1460
+ const outputPath = options.output ?? generatePagePath(config);
1461
+ logger.startSpinner(`Writing to ${outputPath}...`);
1462
+ await fs3.mkdir(path3.dirname(outputPath), { recursive: true });
1463
+ await fs3.writeFile(outputPath, pageResult.code, "utf-8");
1464
+ logger.stopSpinnerSuccess(`Page created: ${outputPath}`);
1465
+ logger.newline();
1466
+ logger.box(
1467
+ `\u2728 ${config.name} page generated successfully!
1468
+
1469
+ File: ${outputPath}
1470
+ Template: ${config.template}
1471
+ Lines: ${pageResult.metadata.linesOfCode}
1472
+ Framework: ${config.framework}
1473
+ Design: ${config.designSystem}
1474
+ Tier: ${config.tier}`,
1475
+ { title: "Success", borderColor: "green" }
1476
+ );
1477
+ printNextSteps("page");
1478
+ }
1479
+ function generateComponentPath(config) {
1480
+ const ext = getFileExtension(config.framework);
1481
+ const fileName = `${config.name}.${ext}`;
1482
+ return path3.join(process.cwd(), "src", "components", fileName);
1483
+ }
1484
+ function generateSectionPath(config) {
1485
+ const ext = getFileExtension(config.framework);
1486
+ const fileName = `${config.name}.${ext}`;
1487
+ return path3.join(process.cwd(), "src", "sections", fileName);
1488
+ }
1489
+ function generatePagePath(config) {
1490
+ const ext = getFileExtension(config.framework);
1491
+ const fileName = `${config.name}.${ext}`;
1492
+ const pageDir = config.framework === "nextjs" ? "app" : "pages";
1493
+ return path3.join(process.cwd(), "src", pageDir, fileName);
1494
+ }
1495
+ function getFileExtension(framework) {
1496
+ const extensions = {
1497
+ react: "tsx",
1498
+ vue: "vue",
1499
+ angular: "component.ts",
1500
+ svelte: "svelte",
1501
+ solid: "tsx"
1502
+ };
1503
+ return extensions[framework] || "tsx";
1504
+ }
1505
+ function printNextSteps(type) {
1506
+ logger.newline();
1507
+ logger.info("Next steps:");
1508
+ if (type === "component") {
1509
+ logger.code(" 1. Import the component in your app");
1510
+ logger.code(" 2. Review and customize as needed");
1511
+ logger.code(" 3. Run your dev server to test");
1512
+ } else if (type === "section") {
1513
+ logger.code(" 1. Import the section in your page");
1514
+ logger.code(" 2. Customize content props (heading, description, etc.)");
1515
+ logger.code(" 3. Add your own images and assets");
1516
+ logger.code(" 4. Run your dev server to preview");
1517
+ } else {
1518
+ logger.code(" 1. Set up routing for your page");
1519
+ logger.code(" 2. Customize page content and sections");
1520
+ logger.code(" 3. Add SEO meta tags if needed");
1521
+ logger.code(" 4. Run your dev server to preview");
1522
+ }
1523
+ logger.newline();
1524
+ }
1525
+
1526
+ // src/commands/init.ts
1527
+ var fs4 = __toESM(require("fs/promises"));
1528
+ var path4 = __toESM(require("path"));
1529
+ var import_commander4 = require("commander");
1530
+ function generateClaudeMd(config) {
1531
+ const tier = config.tier || "standard";
1532
+ return `# Claude Code Instructions - ${config.projectName}
1533
+
1534
+ > Auto-generated by Nikkory Vibe. AI Agent will automatically follow these quality rules.
1535
+
1536
+ ## Project Overview
1537
+
1538
+ - **Framework**: ${config.framework}
1539
+ - **Design System**: ${config.designSystem}
1540
+ - **Styling**: TailwindCSS
1541
+ - **Quality Tier**: ${tier}
1542
+
1543
+ ---
1544
+
1545
+ # \u{1F534} AI AGENT INSPECTOR - MANDATORY QUALITY RULES
1546
+
1547
+ **CRITICAL**: These rules are AUTOMATICALLY ENFORCED. AI Agent MUST follow ALL rules below for EVERY code change. No exceptions. No simplification.
1548
+
1549
+ ## ESLint Zero-Error Rules (MANDATORY)
1550
+
1551
+ ### Import Order (ALWAYS enforce)
1552
+
1553
+ \`\`\`typescript
1554
+ // \u2705 CORRECT - React first, blank line between groups
1555
+ import React, { useState, useCallback, memo, forwardRef } from 'react';
1556
+
1557
+ import { cn } from '@/lib/utils';
1558
+ import { Button } from '@/components';
1559
+
1560
+ // \u274C WRONG - No blank lines, wrong order
1561
+ import { Button } from '@/components';
1562
+ import React from 'react';
1563
+ import { cn } from '@/lib/utils';
1564
+ \`\`\`
1565
+
1566
+ ### Explicit Return Types (ALWAYS add)
1567
+
1568
+ \`\`\`typescript
1569
+ // \u2705 CORRECT
1570
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>): void => {
1571
+ console.log(e);
1572
+ };
1573
+
1574
+ // \u274C WRONG - Missing return type
1575
+ const handleClick = (e) => {
1576
+ console.log(e);
1577
+ };
1578
+ \`\`\`
1579
+
1580
+ ### No Unused Variables (ALWAYS prefix with _)
1581
+
1582
+ \`\`\`typescript
1583
+ // \u2705 CORRECT
1584
+ const { name, age: _age, email } = user; // _age unused but valid
1585
+
1586
+ // \u274C WRONG
1587
+ const { name, age, email } = user; // age unused = ERROR
1588
+ \`\`\`
1589
+
1590
+ ### No \`any\` Type (ALWAYS use \`unknown\`)
1591
+
1592
+ \`\`\`typescript
1593
+ // \u2705 CORRECT
1594
+ const handleData = (data: unknown): void => {};
1595
+
1596
+ // \u274C WRONG
1597
+ const handleData = (data: any): void => {};
1598
+ \`\`\`
1599
+
1600
+ ### No Non-Null Assertion (ALWAYS use optional chaining)
1601
+
1602
+ \`\`\`typescript
1603
+ // \u2705 CORRECT
1604
+ ref.current?.focus();
1605
+
1606
+ // \u274C WRONG
1607
+ ref.current!.focus();
1608
+ \`\`\`
1609
+
1610
+ ## TypeScript Strict Mode (MANDATORY)
1611
+
1612
+ | Pattern | Required | Example |
1613
+ |---------|----------|---------|
1614
+ | Explicit return types | YES | \`(): void\`, \`(): string\` |
1615
+ | No implicit any | YES | Always type parameters |
1616
+ | Strict null checks | YES | Use \`?.\` and \`??\` |
1617
+ | Interface over type | YES | For object shapes |
1618
+
1619
+ ## React Component Patterns
1620
+
1621
+ ### Basic Tier
1622
+
1623
+ \`\`\`typescript
1624
+ import React from 'react';
1625
+
1626
+ interface ComponentProps {
1627
+ children?: React.ReactNode;
1628
+ className?: string;
1629
+ }
1630
+
1631
+ export const Component: React.FC<ComponentProps> = ({
1632
+ children,
1633
+ className,
1634
+ }) => {
1635
+ return <div className={className}>{children}</div>;
1636
+ };
1637
+ \`\`\`
1638
+
1639
+ ### Standard Tier (forwardRef + displayName)
1640
+
1641
+ \`\`\`typescript
1642
+ import React, { forwardRef } from 'react';
1643
+
1644
+ interface ComponentProps {
1645
+ children?: React.ReactNode;
1646
+ variant?: 'primary' | 'secondary';
1647
+ }
1648
+
1649
+ export const Component = forwardRef<HTMLDivElement, ComponentProps>(
1650
+ ({ children, variant = 'primary', ...props }, ref) => {
1651
+ return <div ref={ref} {...props}>{children}</div>;
1652
+ }
1653
+ );
1654
+
1655
+ Component.displayName = 'Component'; // REQUIRED!
1656
+ \`\`\`
1657
+
1658
+ ### Enterprise Tier (memo + forwardRef + displayName)
1659
+
1660
+ \`\`\`typescript
1661
+ import React, { memo, forwardRef, useCallback } from 'react';
1662
+
1663
+ interface ComponentProps {
1664
+ children?: React.ReactNode;
1665
+ analyticsEvent?: string;
1666
+ onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
1667
+ }
1668
+
1669
+ export const Component = memo(
1670
+ forwardRef<HTMLDivElement, ComponentProps>(
1671
+ ({ children, analyticsEvent, onClick, ...props }, ref) => {
1672
+ const handleClick = useCallback(
1673
+ (e: React.MouseEvent<HTMLDivElement>): void => {
1674
+ if (analyticsEvent && typeof window !== 'undefined') {
1675
+ (window as unknown as { dataLayer?: unknown[] }).dataLayer?.push({
1676
+ event: analyticsEvent,
1677
+ });
1678
+ }
1679
+ onClick?.(e);
1680
+ },
1681
+ [analyticsEvent, onClick]
1682
+ );
1683
+
1684
+ return <div ref={ref} onClick={handleClick} {...props}>{children}</div>;
1685
+ }
1686
+ )
1687
+ );
1688
+
1689
+ Component.displayName = 'Component'; // REQUIRED!
1690
+ \`\`\`
1691
+
1692
+ ## Debugging Rules (NEVER SKIP)
1693
+
1694
+ When debugging or fixing issues:
1695
+
1696
+ 1. **NEVER simplify code** - Fix the actual issue, don't remove features
1697
+ 2. **NEVER remove types** - Keep all TypeScript annotations
1698
+ 3. **NEVER use \`any\`** - Use \`unknown\` if type is unclear
1699
+ 4. **ALWAYS preserve patterns** - forwardRef, memo, displayName
1700
+ 5. **ALWAYS run lint check** - \`pnpm lint\` before considering done
1701
+ 6. **ALWAYS check types** - \`pnpm type-check\` before considering done
1702
+
1703
+ ## Pre-Commit Checklist (AUTO-ENFORCE)
1704
+
1705
+ Before ANY commit, AI Agent MUST verify:
1706
+
1707
+ - [ ] All imports have correct order with blank lines
1708
+ - [ ] All functions have explicit return types
1709
+ - [ ] No unused variables (prefix with _ if intentionally unused)
1710
+ - [ ] No \`any\` types (use \`unknown\` instead)
1711
+ - [ ] No non-null assertions (use \`?.\` instead)
1712
+ - [ ] forwardRef components have displayName
1713
+ - [ ] Enterprise components use memo()
1714
+ - [ ] useEffect cleanup has \`: void\` return type
1715
+ - [ ] Event handlers have proper React event types
1716
+
1717
+ ## Quick Fix Reference
1718
+
1719
+ | Error | Quick Fix |
1720
+ |-------|-----------|
1721
+ | \`import/order\` | Add blank line between import groups |
1722
+ | \`explicit-function-return-type\` | Add \`: void\`, \`: string\`, etc. |
1723
+ | \`no-unused-vars\` | Prefix with \`_\` |
1724
+ | \`no-explicit-any\` | Use \`unknown\` |
1725
+ | \`no-non-null-assertion\` | Use \`?.\` optional chaining |
1726
+ | \`TS2304: Cannot find name\` | Add missing import |
1727
+ | \`TS2322: Type not assignable\` | Fix type or cast properly |
1728
+ | \`TS6133: Unused declaration\` | Remove or prefix with \`_\` |
1729
+
1730
+ ---
1731
+
1732
+ **Powered by Nikkory Vibe**
1733
+ `;
1734
+ }
1735
+ var initCommand = new import_commander4.Command("init").description("Initialize a new Nikkory Vibe project with AI Agent Inspector").argument("[project-name]", "Project name (kebab-case)").option("-f, --framework <framework>", "Frontend framework", "react").option("-d, --design <system>", "Default design system", "material-design").option("-t, --tier <tier>", "Quality tier (basic, standard, enterprise)", "standard").option("--backend", "Include backend (NestJS)").option("--no-install", "Skip dependency installation").option("--no-claude", "Skip CLAUDE.md generation").action(
1736
+ async (projectName, options) => {
1737
+ try {
1738
+ logger.header("\u{1F3A8} Nikkory Vibe - Project Initialization");
1739
+ let config;
1740
+ if (!projectName) {
1741
+ const promptConfig = await promptProjectInit();
1742
+ projectName = promptConfig.projectName;
1743
+ config = {
1744
+ ...promptConfig,
1745
+ tier: options.tier ?? "standard"
1746
+ };
1747
+ } else {
1748
+ config = {
1749
+ projectName,
1750
+ framework: options.framework ?? "react",
1751
+ designSystem: options.design ?? "material-design",
1752
+ tier: options.tier ?? "standard",
1753
+ includeBackend: options.backend ?? false
1754
+ };
1755
+ }
1756
+ const projectPath = path4.join(process.cwd(), projectName);
1757
+ try {
1758
+ await fs4.access(projectPath);
1759
+ logger.error(`Directory "${projectName}" already exists`);
1760
+ process.exit(1);
1761
+ } catch {
1762
+ }
1763
+ logger.newline();
1764
+ logger.info(`Creating project: ${projectName}`);
1765
+ logger.info(`Framework: ${config.framework}`);
1766
+ logger.info(`Design System: ${config.designSystem}`);
1767
+ logger.info(`Quality Tier: ${config.tier}`);
1768
+ if (config.includeBackend) {
1769
+ logger.info(`Backend: NestJS`);
1770
+ }
1771
+ logger.newline();
1772
+ logger.startSpinner("Creating project structure...");
1773
+ await fs4.mkdir(projectPath, { recursive: true });
1774
+ await createProjectStructure(projectPath, config);
1775
+ logger.stopSpinnerSuccess("Project structure created");
1776
+ logger.startSpinner("Creating package.json...");
1777
+ await createPackageJson(projectPath, config);
1778
+ logger.stopSpinnerSuccess("package.json created");
1779
+ logger.startSpinner("Creating configuration files...");
1780
+ await createConfigFiles(projectPath, config);
1781
+ logger.stopSpinnerSuccess("Configuration files created");
1782
+ if (options.claude !== false) {
1783
+ logger.startSpinner("Creating CLAUDE.md (AI Agent Inspector)...");
1784
+ await createClaudeMd(projectPath, config);
1785
+ logger.stopSpinnerSuccess("CLAUDE.md created - AI Agent Inspector enabled");
1786
+ }
1787
+ logger.startSpinner("Creating README.md...");
1788
+ await createReadme(projectPath, config);
1789
+ logger.stopSpinnerSuccess("README.md created");
1790
+ logger.newline();
1791
+ logger.box(
1792
+ `\u2728 Project "${projectName}" created successfully!
1793
+
1794
+ Location: ${projectPath}
1795
+ Framework: ${config.framework}
1796
+ Design: ${config.designSystem}
1797
+ Tier: ${config.tier}
1798
+ AI Inspector: ${options.claude !== false ? "Enabled" : "Disabled"}`,
1799
+ { title: "Success", borderColor: "green" }
1800
+ );
1801
+ if (options.claude !== false) {
1802
+ logger.newline();
1803
+ logger.info("\u{1F534} AI Agent Inspector is enabled!");
1804
+ logger.info(" Claude Code will automatically enforce quality rules.");
1805
+ logger.info(" No manual commands needed - just code!");
1806
+ }
1807
+ logger.newline();
1808
+ logger.info("Next steps:");
1809
+ logger.code(` cd ${projectName}`);
1810
+ if (options.install ?? true) {
1811
+ logger.code(` pnpm install`);
1812
+ }
1813
+ logger.code(` pnpm dev`);
1814
+ logger.newline();
1815
+ logger.info("Generate your first component:");
1816
+ logger.code(` vibe smart button --style glassmorphism --tier ${config.tier}`);
1817
+ logger.newline();
1818
+ } catch (error) {
1819
+ logger.stopSpinner();
1820
+ logger.error("Project initialization failed");
1821
+ if (error instanceof Error) {
1822
+ logger.debug(error.stack || error.message);
1823
+ }
1824
+ process.exit(1);
1825
+ }
1826
+ }
1827
+ );
1828
+ async function createProjectStructure(projectPath, config) {
1829
+ const dirs = ["src/components", "src/pages", "src/styles", "src/utils", "public", ".claude"];
1830
+ if (config.includeBackend) {
1831
+ dirs.push("api/src/modules", "api/src/common", "api/prisma");
1832
+ }
1833
+ for (const dir of dirs) {
1834
+ await fs4.mkdir(path4.join(projectPath, dir), { recursive: true });
1835
+ }
1836
+ }
1837
+ async function createClaudeMd(projectPath, config) {
1838
+ const content = generateClaudeMd(config);
1839
+ await fs4.writeFile(path4.join(projectPath, "CLAUDE.md"), content, "utf-8");
1840
+ }
1841
+ async function createPackageJson(projectPath, config) {
1842
+ const packageJson = {
1843
+ name: config.projectName,
1844
+ version: "0.1.0",
1845
+ private: true,
1846
+ scripts: {
1847
+ dev: config.framework === "react" ? "next dev" : "vite dev",
1848
+ build: config.framework === "react" ? "next build" : "vite build",
1849
+ start: config.framework === "react" ? "next start" : "vite preview",
1850
+ lint: "eslint . --ext .ts,.tsx",
1851
+ "type-check": "tsc --noEmit"
1852
+ },
1853
+ dependencies: getFrameworkDependencies(config.framework),
1854
+ devDependencies: {
1855
+ "@types/node": "^20.0.0",
1856
+ "@types/react": "^18.0.0",
1857
+ "@types/react-dom": "^18.0.0",
1858
+ typescript: "^5.0.0",
1859
+ eslint: "^8.0.0",
1860
+ "@nikkory/vibe-cli": "^1.0.0"
1861
+ }
1862
+ };
1863
+ await fs4.writeFile(
1864
+ path4.join(projectPath, "package.json"),
1865
+ JSON.stringify(packageJson, null, 2),
1866
+ "utf-8"
1867
+ );
1868
+ }
1869
+ function getFrameworkDependencies(framework) {
1870
+ const deps = {
1871
+ react: {
1872
+ react: "^18.2.0",
1873
+ "react-dom": "^18.2.0",
1874
+ next: "^14.0.0",
1875
+ tailwindcss: "^3.4.0"
1876
+ },
1877
+ vue: {
1878
+ vue: "^3.3.0",
1879
+ nuxt: "^3.8.0",
1880
+ tailwindcss: "^3.4.0"
1881
+ },
1882
+ angular: {
1883
+ "@angular/core": "^17.0.0",
1884
+ "@angular/common": "^17.0.0",
1885
+ "@angular/platform-browser": "^17.0.0"
1886
+ },
1887
+ svelte: {
1888
+ svelte: "^4.0.0",
1889
+ "@sveltejs/kit": "^2.0.0",
1890
+ tailwindcss: "^3.4.0"
1891
+ },
1892
+ solid: {
1893
+ "solid-js": "^1.8.0",
1894
+ "solid-start": "^0.4.0",
1895
+ tailwindcss: "^3.4.0"
1896
+ }
1897
+ };
1898
+ return deps[framework] ?? deps["react"] ?? {};
1899
+ }
1900
+ async function createConfigFiles(projectPath, _config) {
1901
+ const tsConfig = {
1902
+ compilerOptions: {
1903
+ target: "ES2020",
1904
+ lib: ["ES2020", "DOM", "DOM.Iterable"],
1905
+ jsx: "preserve",
1906
+ module: "ESNext",
1907
+ moduleResolution: "bundler",
1908
+ resolveJsonModule: true,
1909
+ allowJs: true,
1910
+ strict: true,
1911
+ noImplicitAny: true,
1912
+ strictNullChecks: true,
1913
+ esModuleInterop: true,
1914
+ skipLibCheck: true,
1915
+ forceConsistentCasingInFileNames: true,
1916
+ incremental: true,
1917
+ paths: {
1918
+ "@/*": ["./src/*"]
1919
+ }
1920
+ },
1921
+ include: ["src/**/*"],
1922
+ exclude: ["node_modules"]
1923
+ };
1924
+ await fs4.writeFile(
1925
+ path4.join(projectPath, "tsconfig.json"),
1926
+ JSON.stringify(tsConfig, null, 2),
1927
+ "utf-8"
1928
+ );
1929
+ const gitignore = `# Dependencies
1930
+ node_modules
1931
+ .pnpm-store
1932
+
1933
+ # Build output
1934
+ dist
1935
+ .next
1936
+ out
1937
+ build
1938
+
1939
+ # Environment
1940
+ .env
1941
+ .env.local
1942
+ .env.*.local
1943
+
1944
+ # IDE
1945
+ .vscode
1946
+ .idea
1947
+ *.swp
1948
+ *.swo
1949
+
1950
+ # OS
1951
+ .DS_Store
1952
+ Thumbs.db
1953
+
1954
+ # Logs
1955
+ *.log
1956
+ npm-debug.log*
1957
+ yarn-debug.log*
1958
+ yarn-error.log*
1959
+ `;
1960
+ await fs4.writeFile(path4.join(projectPath, ".gitignore"), gitignore, "utf-8");
1961
+ }
1962
+ async function createReadme(projectPath, config) {
1963
+ const readme = `# ${config.projectName}
1964
+
1965
+ Generated with **Nikkory Vibe** \u2728
1966
+
1967
+ ## Tech Stack
1968
+
1969
+ - **Framework**: ${config.framework}
1970
+ - **Design System**: ${config.designSystem}
1971
+ - **Quality Tier**: ${config.tier}
1972
+ - **Styling**: TailwindCSS
1973
+ - **TypeScript**: 5.0+
1974
+
1975
+ ## AI Agent Inspector
1976
+
1977
+ This project includes **AI Agent Inspector** via \`CLAUDE.md\`.
1978
+ When using Claude Code, AI will automatically:
1979
+
1980
+ - \u2705 Follow ESLint zero-error rules
1981
+ - \u2705 Use TypeScript strict mode patterns
1982
+ - \u2705 Apply correct React component patterns for ${config.tier} tier
1983
+ - \u2705 Never simplify code when debugging
1984
+ - \u2705 Run lint/type checks before completing tasks
1985
+
1986
+ **No manual commands needed - just code!**
1987
+
1988
+ ## Getting Started
1989
+
1990
+ \`\`\`bash
1991
+ # Install dependencies
1992
+ pnpm install
1993
+
1994
+ # Run development server
1995
+ pnpm dev
1996
+
1997
+ # Build for production
1998
+ pnpm build
1999
+ \`\`\`
2000
+
2001
+ ## Generate Components
2002
+
2003
+ \`\`\`bash
2004
+ # Generate a component with Smart Generator
2005
+ vibe smart button --style glassmorphism --tier ${config.tier}
2006
+
2007
+ # List all 50 design styles
2008
+ vibe smart --list-styles
2009
+
2010
+ # Generate all 3 tiers at once
2011
+ vibe smart card --style brutalism --all-tiers
2012
+
2013
+ # Preview without writing
2014
+ vibe smart input --style neumorphism --dry-run
2015
+ \`\`\`
2016
+
2017
+ ## Code Quality
2018
+
2019
+ \`\`\`bash
2020
+ # Run ESLint
2021
+ pnpm lint
2022
+
2023
+ # Run TypeScript check
2024
+ pnpm type-check
2025
+
2026
+ # Run Code Doctor
2027
+ vibe doctor scan ./src
2028
+ \`\`\`
2029
+
2030
+ ## Project Structure
2031
+
2032
+ \`\`\`
2033
+ ${config.projectName}/
2034
+ \u251C\u2500\u2500 src/
2035
+ \u2502 \u251C\u2500\u2500 components/ # React components
2036
+ \u2502 \u251C\u2500\u2500 pages/ # Page components
2037
+ \u2502 \u251C\u2500\u2500 styles/ # Global styles
2038
+ \u2502 \u2514\u2500\u2500 utils/ # Utilities
2039
+ \u251C\u2500\u2500 public/ # Static assets
2040
+ \u251C\u2500\u2500 CLAUDE.md # AI Agent Inspector rules
2041
+ \u2514\u2500\u2500 package.json
2042
+ \`\`\`
2043
+
2044
+ ## Learn More
2045
+
2046
+ - [Nikkory Vibe Documentation](https://vibe.nikkory.com/docs)
2047
+ - [Design Systems](https://vibe.nikkory.com/docs/design-systems)
2048
+ - [CLI Reference](https://vibe.nikkory.com/docs/cli)
2049
+
2050
+ ---
2051
+
2052
+ Powered by Nikkory
2053
+ `;
2054
+ await fs4.writeFile(path4.join(projectPath, "README.md"), readme, "utf-8");
2055
+ }
2056
+
2057
+ // src/commands/list.ts
2058
+ var import_commander5 = require("commander");
2059
+ var listCommand = new import_commander5.Command("list").alias("ls").description("List available templates and design systems").argument("[category]", "Category to list (templates, designs, tiers)", "all").option("--json", "Output as JSON").action((category, options) => {
2060
+ try {
2061
+ if (options.json) {
2062
+ const data = getAllData();
2063
+ console.log(JSON.stringify(data, null, 2));
2064
+ return;
2065
+ }
2066
+ logger.header("\u{1F3A8} Nikkory Vibe - Available Options");
2067
+ switch (category) {
2068
+ case "templates":
2069
+ listTemplates();
2070
+ break;
2071
+ case "designs":
2072
+ case "design-systems":
2073
+ listDesignSystems();
2074
+ break;
2075
+ case "tiers":
2076
+ listTiers();
2077
+ break;
2078
+ case "frameworks":
2079
+ listFrameworks();
2080
+ break;
2081
+ case "all":
2082
+ default:
2083
+ listTemplates();
2084
+ logger.newline();
2085
+ listDesignSystems();
2086
+ logger.newline();
2087
+ listTiers();
2088
+ logger.newline();
2089
+ listFrameworks();
2090
+ break;
2091
+ }
2092
+ logger.newline();
2093
+ logger.info("Generate a component:");
2094
+ logger.code(" vibe generate component MyButton --design material-design");
2095
+ logger.newline();
2096
+ } catch (error) {
2097
+ logger.error("Failed to list options");
2098
+ if (error instanceof Error) {
2099
+ logger.debug(error.stack || error.message);
2100
+ }
2101
+ process.exit(1);
2102
+ }
2103
+ });
2104
+ function listTemplates() {
2105
+ logger.newline();
2106
+ logger.info("\u{1F4E6} Available Templates:");
2107
+ logger.separator();
2108
+ const templates = [
2109
+ { name: "Button", value: "button", description: "Interactive button components" },
2110
+ { name: "Card", value: "card", description: "Content container cards" },
2111
+ { name: "Input", value: "input", description: "Form input fields" },
2112
+ { name: "Modal", value: "modal", description: "Dialog/modal overlays" },
2113
+ { name: "Table", value: "table", description: "Data tables" },
2114
+ { name: "Form", value: "form", description: "Form layouts" },
2115
+ { name: "Navigation", value: "navigation", description: "Nav bars and menus" },
2116
+ { name: "Hero", value: "hero", description: "Hero sections" },
2117
+ { name: "Feature", value: "feature", description: "Feature showcases" },
2118
+ { name: "Pricing", value: "pricing", description: "Pricing tables" }
2119
+ ];
2120
+ logger.table(
2121
+ templates.map((t) => ({
2122
+ Template: t.name,
2123
+ ID: t.value,
2124
+ Description: t.description
2125
+ }))
2126
+ );
2127
+ }
2128
+ function listDesignSystems() {
2129
+ logger.newline();
2130
+ logger.info("\u{1F3A8} Available Design Systems:");
2131
+ logger.separator();
2132
+ const designs = [
2133
+ {
2134
+ name: "Material Design 3",
2135
+ value: "material-design",
2136
+ category: "Modern"
2137
+ },
2138
+ {
2139
+ name: "iOS Human Interface Guidelines",
2140
+ value: "ios-hig",
2141
+ category: "Mobile"
2142
+ },
2143
+ {
2144
+ name: "Glassmorphism",
2145
+ value: "glassmorphism",
2146
+ category: "Modern"
2147
+ },
2148
+ {
2149
+ name: "Neumorphism",
2150
+ value: "neumorphism",
2151
+ category: "Modern"
2152
+ },
2153
+ {
2154
+ name: "Minimalism",
2155
+ value: "minimalism",
2156
+ category: "Clean"
2157
+ },
2158
+ {
2159
+ name: "Brutalism",
2160
+ value: "brutalism",
2161
+ category: "Bold"
2162
+ },
2163
+ {
2164
+ name: "Cyberpunk",
2165
+ value: "cyberpunk",
2166
+ category: "Futuristic"
2167
+ },
2168
+ {
2169
+ name: "Retro",
2170
+ value: "retro",
2171
+ category: "Vintage"
2172
+ }
2173
+ ];
2174
+ logger.table(
2175
+ designs.map((d) => ({
2176
+ "Design System": d.name,
2177
+ ID: d.value,
2178
+ Category: d.category
2179
+ }))
2180
+ );
2181
+ }
2182
+ function listTiers() {
2183
+ logger.newline();
2184
+ logger.info("\u2B50 Quality Tiers:");
2185
+ logger.separator();
2186
+ const tiers = [
2187
+ {
2188
+ tier: "Basic",
2189
+ id: "basic",
2190
+ description: "Prototype/demo quality",
2191
+ features: "2-3 variants, basic styling",
2192
+ loc: "~60 LOC"
2193
+ },
2194
+ {
2195
+ tier: "Standard",
2196
+ id: "standard",
2197
+ description: "Production-ready",
2198
+ features: "5+ variants, accessibility, dark mode",
2199
+ loc: "~200 LOC"
2200
+ },
2201
+ {
2202
+ tier: "Enterprise",
2203
+ id: "enterprise",
2204
+ description: "Mission-critical",
2205
+ features: "All features + analytics + advanced animations",
2206
+ loc: "~350 LOC"
2207
+ }
2208
+ ];
2209
+ logger.table(
2210
+ tiers.map((t) => ({
2211
+ Tier: t.tier,
2212
+ ID: t.id,
2213
+ Description: t.description,
2214
+ Features: t.features,
2215
+ Size: t.loc
2216
+ }))
2217
+ );
2218
+ }
2219
+ function listFrameworks() {
2220
+ logger.newline();
2221
+ logger.info("\u{1F680} Supported Frameworks:");
2222
+ logger.separator();
2223
+ const frameworks = [
2224
+ { name: "React", value: "react", extension: ".tsx" },
2225
+ { name: "Vue", value: "vue", extension: ".vue" },
2226
+ { name: "Angular", value: "angular", extension: ".component.ts" },
2227
+ { name: "Svelte", value: "svelte", extension: ".svelte" },
2228
+ { name: "Solid", value: "solid", extension: ".tsx" }
2229
+ ];
2230
+ logger.table(
2231
+ frameworks.map((f) => ({
2232
+ Framework: f.name,
2233
+ ID: f.value,
2234
+ Extension: f.extension
2235
+ }))
2236
+ );
2237
+ }
2238
+ function getAllData() {
2239
+ return {
2240
+ templates: [
2241
+ "button",
2242
+ "card",
2243
+ "input",
2244
+ "modal",
2245
+ "table",
2246
+ "form",
2247
+ "navigation",
2248
+ "hero",
2249
+ "feature",
2250
+ "pricing"
2251
+ ],
2252
+ designSystems: [
2253
+ "material-design",
2254
+ "ios-hig",
2255
+ "glassmorphism",
2256
+ "neumorphism",
2257
+ "minimalism",
2258
+ "brutalism",
2259
+ "cyberpunk",
2260
+ "retro"
2261
+ ],
2262
+ tiers: ["basic", "standard", "enterprise"],
2263
+ frameworks: ["react", "vue", "angular", "svelte", "solid"]
2264
+ };
2265
+ }
2266
+
2267
+ // src/commands/matrix-generate.ts
2268
+ var import_commander6 = require("commander");
2269
+ var import_chalk2 = __toESM(require("chalk"));
2270
+ var import_ora2 = __toESM(require("ora"));
2271
+ var import_vibe_engine = require("@nikkory/vibe-engine");
2272
+
2273
+ // src/generators/component-generator.ts
2274
+ var import_promises = require("fs/promises");
2275
+ var import_path = require("path");
2276
+ var ComponentGenerator2 = class {
2277
+ /**
2278
+ * Write generated code to file
2279
+ *
2280
+ * @param filePath - Absolute file path
2281
+ * @param code - Generated code content
2282
+ * @returns Promise<void>
2283
+ */
2284
+ async writeToFile(filePath, code) {
2285
+ await (0, import_promises.mkdir)((0, import_path.dirname)(filePath), { recursive: true });
2286
+ await (0, import_promises.writeFile)(filePath, code, "utf-8");
2287
+ }
2288
+ /**
2289
+ * Format code with syntax highlighting (for terminal output)
2290
+ *
2291
+ * @param code - Code to format
2292
+ * @returns Formatted code string
2293
+ *
2294
+ * Note: Simple pass-through for now. Could use chalk for syntax highlighting.
2295
+ */
2296
+ formatCode(code) {
2297
+ return code;
2298
+ }
2299
+ };
2300
+
2301
+ // src/commands/matrix-generate.ts
2302
+ var matrixGenerateCommand = new import_commander6.Command("matrix-generate").description("Generate UI component using Matrix Multiplication (24-Factor System)").argument("<component>", "Component ID (e.g., button, input, card)").option(
2303
+ "-d, --design-system <system>",
2304
+ "Design system (material-design, ios-hig, glassmorphism, neumorphism, brutalism, minimalism, fluent, carbon, ant-design, chakra, atlassian, blueprint)",
2305
+ "material-design"
2306
+ ).option(
2307
+ "-t, --tier <tier>",
2308
+ "Quality tier (basic, standard, enterprise)",
2309
+ "standard"
2310
+ ).option(
2311
+ "-f, --factor-overrides <json>",
2312
+ `Factor overrides as JSON (e.g., '{"4":"xl","17":"lg"}')`
2313
+ ).option(
2314
+ "-o, --output <path>",
2315
+ "Output file path"
2316
+ ).action(async (componentId, options) => {
2317
+ const spinner = (0, import_ora2.default)("Generating component...").start();
2318
+ try {
2319
+ const resolver = new import_vibe_engine.MatrixResolver();
2320
+ const templateEngine = new import_vibe_engine.TemplateEngine();
2321
+ let factor24Config;
2322
+ if (options.factorOverrides) {
2323
+ try {
2324
+ factor24Config = JSON.parse(options.factorOverrides);
2325
+ } catch (parseError) {
2326
+ spinner.fail(import_chalk2.default.red("Invalid JSON in --factor-overrides"));
2327
+ if (parseError instanceof Error) {
2328
+ console.error(import_chalk2.default.gray(parseError.message));
2329
+ }
2330
+ process.exit(1);
2331
+ }
2332
+ }
2333
+ const input = {
2334
+ componentId,
2335
+ designSystem: options.designSystem,
2336
+ tier: options.tier,
2337
+ factor24Config
2338
+ };
2339
+ const config = resolver.resolve(input);
2340
+ const code = templateEngine.generate(config);
2341
+ const generator = new ComponentGenerator2();
2342
+ if (options.output) {
2343
+ await generator.writeToFile(options.output, code);
2344
+ spinner.succeed(import_chalk2.default.green(`Generated ${config.componentName} \u2192 ${options.output}`));
2345
+ } else {
2346
+ spinner.succeed(import_chalk2.default.green(`Generated ${config.componentName}`));
2347
+ console.log(code);
2348
+ }
2349
+ console.log(import_chalk2.default.cyan("\nComponent Info:"));
2350
+ console.log(` ${import_chalk2.default.gray("Name:")} ${config.componentName}`);
2351
+ console.log(` ${import_chalk2.default.gray("Tier:")} ${config.tier}`);
2352
+ console.log(` ${import_chalk2.default.gray("Design System:")} ${config.designSystem}`);
2353
+ console.log(` ${import_chalk2.default.gray("HTML Element:")} <${config.elementType}>`);
2354
+ console.log(` ${import_chalk2.default.gray("Class Names:")} ${config.classNames.join(" ")}`);
2355
+ console.log("");
2356
+ } catch (error) {
2357
+ spinner.fail(import_chalk2.default.red(`Error: ${error.message}`));
2358
+ process.exit(1);
2359
+ }
2360
+ });
2361
+
2362
+ // src/index.ts
2363
+ var program = new import_commander7.Command();
2364
+ program.name("vibe").description("Nikkory Vibe - Production-ready code in seconds").version("1.0.0");
2365
+ program.addCommand(generateCommand);
2366
+ program.addCommand(matrixGenerateCommand);
2367
+ program.addCommand(initCommand);
2368
+ program.addCommand(listCommand);
2369
+ program.addCommand(addCommand);
2370
+ program.addCommand(copyCommand);
2371
+ program.parse(process.argv);