@nikkory/vibe-cli 2.1.0 → 2.2.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/cli.js DELETED
@@ -1,4106 +0,0 @@
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/cli.ts
27
- var import_chalk14 = __toESM(require("chalk"));
28
- var import_commander12 = require("commander");
29
-
30
- // src/commands/add.ts
31
- var fs = __toESM(require("fs/promises"));
32
- var path = __toESM(require("path"));
33
- var import_commander = require("commander");
34
- var import_inquirer = __toESM(require("inquirer"));
35
-
36
- // src/utils/logger.ts
37
- var import_boxen = __toESM(require("boxen"));
38
- var import_chalk = __toESM(require("chalk"));
39
- var import_ora = __toESM(require("ora"));
40
- var Logger = class {
41
- spinner = null;
42
- /**
43
- * Success message (green checkmark)
44
- */
45
- success(message) {
46
- console.log(import_chalk.default.green("\u2713"), message);
47
- }
48
- /**
49
- * Error message (red cross)
50
- */
51
- error(message) {
52
- console.log(import_chalk.default.red("\u2717"), message);
53
- }
54
- /**
55
- * Warning message (yellow exclamation)
56
- */
57
- warn(message) {
58
- console.log(import_chalk.default.yellow("\u26A0"), message);
59
- }
60
- /**
61
- * Info message (blue dot)
62
- */
63
- info(message) {
64
- console.log(import_chalk.default.blue("\u2139"), message);
65
- }
66
- /**
67
- * Debug message (gray)
68
- */
69
- debug(message) {
70
- if (process.env["DEBUG"]) {
71
- console.log(import_chalk.default.gray("\u2022"), import_chalk.default.gray(message));
72
- }
73
- }
74
- /**
75
- * Start loading spinner
76
- */
77
- startSpinner(message) {
78
- this.spinner = (0, import_ora.default)(message).start();
79
- }
80
- /**
81
- * Update spinner message
82
- */
83
- updateSpinner(message) {
84
- if (this.spinner) {
85
- this.spinner.text = message;
86
- }
87
- }
88
- /**
89
- * Stop spinner with success
90
- */
91
- stopSpinnerSuccess(message) {
92
- if (this.spinner) {
93
- this.spinner.succeed(message);
94
- this.spinner = null;
95
- }
96
- }
97
- /**
98
- * Stop spinner with failure
99
- */
100
- stopSpinnerFail(message) {
101
- if (this.spinner) {
102
- this.spinner.fail(message);
103
- this.spinner = null;
104
- }
105
- }
106
- /**
107
- * Stop spinner
108
- */
109
- stopSpinner() {
110
- if (this.spinner) {
111
- this.spinner.stop();
112
- this.spinner = null;
113
- }
114
- }
115
- /**
116
- * Print box message
117
- */
118
- box(message, options) {
119
- console.log(
120
- (0, import_boxen.default)(message, {
121
- padding: 1,
122
- margin: 1,
123
- borderStyle: "round",
124
- borderColor: options?.borderColor || "cyan",
125
- title: options?.title,
126
- titleAlignment: "center"
127
- })
128
- );
129
- }
130
- /**
131
- * Print separator line
132
- */
133
- separator() {
134
- console.log(import_chalk.default.gray("\u2500".repeat(50)));
135
- }
136
- /**
137
- * Print newline
138
- */
139
- newline() {
140
- console.log();
141
- }
142
- /**
143
- * Print header
144
- */
145
- header(title) {
146
- console.log();
147
- console.log(import_chalk.default.bold.cyan(title));
148
- this.separator();
149
- }
150
- /**
151
- * Print code block
152
- */
153
- code(code) {
154
- console.log(import_chalk.default.gray(code));
155
- }
156
- /**
157
- * Print table
158
- */
159
- table(data) {
160
- if (data.length === 0) return;
161
- const firstRow = data[0];
162
- if (!firstRow) return;
163
- const headers = Object.keys(firstRow);
164
- const columnWidths = headers.map((header) => {
165
- const maxDataWidth = Math.max(...data.map((row) => String(row[header] ?? "").length));
166
- return Math.max(header.length, maxDataWidth);
167
- });
168
- const headerRow = headers.map((header, i) => import_chalk.default.bold(header.padEnd(columnWidths[i] ?? 10))).join(" \u2502 ");
169
- console.log(headerRow);
170
- const separator = columnWidths.map((width) => "\u2500".repeat(width)).join("\u2500\u253C\u2500");
171
- console.log(import_chalk.default.gray(separator));
172
- data.forEach((row) => {
173
- const dataRow = headers.map((header, i) => String(row[header] ?? "").padEnd(columnWidths[i] ?? 10)).join(" \u2502 ");
174
- console.log(dataRow);
175
- });
176
- }
177
- };
178
- var logger = new Logger();
179
-
180
- // src/commands/add.ts
181
- var AVAILABLE_COMPONENTS = [
182
- "button",
183
- "input",
184
- "card",
185
- "badge",
186
- "toast",
187
- "modal",
188
- "dropdown",
189
- "tabs",
190
- "accordion",
191
- "avatar"
192
- ];
193
- var COLORS = [
194
- "primary",
195
- "secondary",
196
- "success",
197
- "warning",
198
- "error",
199
- "info",
200
- "blue",
201
- "red",
202
- "green",
203
- "yellow",
204
- "purple",
205
- "gray",
206
- "orange",
207
- "amber",
208
- "lime",
209
- "emerald",
210
- "teal",
211
- "cyan",
212
- "sky",
213
- "indigo",
214
- "violet",
215
- "fuchsia",
216
- "pink",
217
- "rose",
218
- "slate",
219
- "zinc",
220
- "neutral",
221
- "stone"
222
- ];
223
- var SIZES = ["xs", "sm", "md", "lg", "xl", "2xl"];
224
- var VARIANTS = {
225
- button: ["solid", "outline", "ghost", "soft", "link"],
226
- input: ["outlined", "filled", "underlined", "ghost"],
227
- card: ["elevated", "outlined", "filled", "ghost"],
228
- badge: ["solid", "soft", "outline", "dot"],
229
- toast: ["solid", "soft", "outlined", "minimal"]
230
- };
231
- var SHAPES = ["square", "rounded", "pill", "circle"];
232
- var POSITIONS = [
233
- "top-left",
234
- "top-center",
235
- "top-right",
236
- "bottom-left",
237
- "bottom-center",
238
- "bottom-right",
239
- "left",
240
- "center",
241
- "right"
242
- ];
243
- var ANIMATIONS = ["none", "subtle", "standard", "smooth", "bounce", "pulse"];
244
- var ELEVATIONS = ["none", "xs", "sm", "md", "lg", "xl", "2xl", "glow"];
245
- var A11Y_LEVELS = ["standard", "enhanced", "maximum"];
246
- var PRESETS = {
247
- primary: { color: "blue", variant: "solid", size: "md" },
248
- secondary: { color: "gray", variant: "outline", size: "md" },
249
- danger: { color: "red", variant: "solid", size: "md" },
250
- success: { color: "green", variant: "solid", size: "md" },
251
- warning: { color: "yellow", variant: "solid", size: "md" },
252
- ghost: { color: "gray", variant: "ghost", size: "md" },
253
- pill: { color: "blue", variant: "solid", shape: "pill", size: "md" },
254
- large: { color: "blue", variant: "solid", size: "lg" },
255
- small: { color: "blue", variant: "solid", size: "sm" }
256
- };
257
- 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) => {
258
- try {
259
- logger.header("\u{1F3A8} Nikkory Vibe - Add Component");
260
- if (options.interactive || !component) {
261
- const config = await promptVariantConfig();
262
- component = config.component;
263
- Object.assign(options, config);
264
- }
265
- if (!component || !AVAILABLE_COMPONENTS.includes(component)) {
266
- logger.error(`Unknown component: ${component ?? "none"}`);
267
- logger.info(`Available: ${AVAILABLE_COMPONENTS.join(", ")}`);
268
- process.exit(1);
269
- }
270
- const validatedComponent = component;
271
- if (options.preset) {
272
- const preset = PRESETS[options.preset];
273
- if (!preset) {
274
- logger.error(`Unknown preset: ${options.preset}`);
275
- logger.info(`Available: ${Object.keys(PRESETS).join(", ")}`);
276
- process.exit(1);
277
- }
278
- Object.assign(options, preset);
279
- }
280
- if (options.color && !COLORS.includes(options.color)) {
281
- logger.warn(`Unknown color: ${options.color}. Using default.`);
282
- }
283
- if (options.size && !SIZES.includes(options.size)) {
284
- logger.warn(`Unknown size: ${options.size}. Using default.`);
285
- }
286
- if (options.position && !POSITIONS.includes(options.position)) {
287
- logger.warn(`Unknown position: ${options.position}. Using default.`);
288
- }
289
- if (options.a11y && !A11Y_LEVELS.includes(options.a11y)) {
290
- logger.warn(`Unknown accessibility level: ${options.a11y}. Using default.`);
291
- }
292
- logger.newline();
293
- logger.info(`Component: ${validatedComponent}`);
294
- logger.info(`Color: ${options.color ?? "default"}`);
295
- logger.info(`Size: ${options.size ?? "default"}`);
296
- logger.info(`Variant: ${options.variant ?? "default"}`);
297
- logger.info(`Shape: ${options.shape ?? "default"}`);
298
- if (options.position) {
299
- logger.info(`Position: ${options.position}`);
300
- }
301
- logger.info(`Animation: ${options.animation ?? "default"}`);
302
- logger.info(`Elevation: ${options.elevation ?? "default"}`);
303
- logger.info(`Accessibility: ${options.a11y ?? "default"}`);
304
- logger.newline();
305
- logger.startSpinner("Generating component...");
306
- const variantConfig = {
307
- color: options.color,
308
- size: options.size,
309
- variant: options.variant,
310
- shape: options.shape,
311
- position: options.position,
312
- animation: options.animation,
313
- elevation: options.elevation,
314
- a11y: options.a11y
315
- };
316
- const code = generateComponentCode(validatedComponent, variantConfig);
317
- logger.stopSpinnerSuccess("Component generated");
318
- if (options.dryRun) {
319
- logger.newline();
320
- logger.header("Generated Code (Preview)");
321
- logger.code(code);
322
- logger.newline();
323
- logger.info("Dry run mode - No files written");
324
- return;
325
- }
326
- const componentName = capitalize(validatedComponent);
327
- const outputPath = path.join(process.cwd(), options.output, `${componentName}.tsx`);
328
- logger.startSpinner(`Writing to ${outputPath}...`);
329
- await fs.mkdir(path.dirname(outputPath), { recursive: true });
330
- await fs.writeFile(outputPath, code, "utf-8");
331
- logger.stopSpinnerSuccess(`Created: ${outputPath}`);
332
- logger.newline();
333
- logger.box(
334
- `\u2728 ${componentName} component added!
335
-
336
- File: ${outputPath}
337
- Color: ${options.color ?? "default"}
338
- Size: ${options.size ?? "default"}`,
339
- { title: "Success", borderColor: "green" }
340
- );
341
- logger.newline();
342
- logger.info("Usage:");
343
- logger.code(` import { ${componentName} } from './components/${componentName}';`);
344
- logger.code(
345
- ` <${componentName} color="${options.color ?? "primary"}" size="${options.size ?? "md"}" />`
346
- );
347
- logger.newline();
348
- } catch (error) {
349
- logger.stopSpinner();
350
- logger.error("Failed to add component");
351
- if (error instanceof Error) {
352
- logger.debug(error.stack || error.message);
353
- }
354
- process.exit(1);
355
- }
356
- });
357
- async function promptVariantConfig() {
358
- const answers = await import_inquirer.default.prompt([
359
- {
360
- type: "list",
361
- name: "component",
362
- message: "Select component:",
363
- choices: AVAILABLE_COMPONENTS.map((c) => ({ name: capitalize(c), value: c }))
364
- },
365
- {
366
- type: "list",
367
- name: "color",
368
- message: "Color:",
369
- choices: [
370
- new import_inquirer.default.Separator("--- Semantic ---"),
371
- { name: "Primary (Blue)", value: "primary" },
372
- { name: "Secondary (Purple)", value: "secondary" },
373
- { name: "Success (Green)", value: "success" },
374
- { name: "Warning (Yellow)", value: "warning" },
375
- { name: "Error (Red)", value: "error" },
376
- { name: "Info (Cyan)", value: "info" },
377
- new import_inquirer.default.Separator("--- Palette ---"),
378
- { name: "Blue", value: "blue" },
379
- { name: "Red", value: "red" },
380
- { name: "Green", value: "green" },
381
- { name: "Yellow", value: "yellow" },
382
- { name: "Purple", value: "purple" },
383
- { name: "Gray", value: "gray" },
384
- { name: "Orange", value: "orange" },
385
- { name: "Pink", value: "pink" }
386
- ],
387
- default: "blue"
388
- },
389
- {
390
- type: "list",
391
- name: "size",
392
- message: "Size:",
393
- choices: [
394
- { name: "Extra Small (xs)", value: "xs" },
395
- { name: "Small (sm)", value: "sm" },
396
- { name: "Medium (md)", value: "md" },
397
- { name: "Large (lg)", value: "lg" },
398
- { name: "Extra Large (xl)", value: "xl" },
399
- { name: "2X Large (2xl)", value: "2xl" }
400
- ],
401
- default: "md"
402
- },
403
- {
404
- type: "list",
405
- name: "variant",
406
- message: "Variant:",
407
- choices: (answers2) => {
408
- const comp = answers2.component;
409
- return (VARIANTS[comp] || ["solid", "outline", "ghost"]).map((v) => ({
410
- name: capitalize(v),
411
- value: v
412
- }));
413
- }
414
- },
415
- {
416
- type: "list",
417
- name: "shape",
418
- message: "Shape:",
419
- choices: SHAPES.map((s) => ({ name: capitalize(s), value: s })),
420
- default: "rounded"
421
- },
422
- {
423
- type: "list",
424
- name: "animation",
425
- message: "Animation:",
426
- choices: ANIMATIONS.map((a) => ({ name: capitalize(a), value: a })),
427
- default: "standard"
428
- },
429
- {
430
- type: "list",
431
- name: "elevation",
432
- message: "Elevation/Shadow:",
433
- choices: ELEVATIONS.map((e) => ({ name: e === "none" ? "None" : e.toUpperCase(), value: e })),
434
- default: "md"
435
- }
436
- ]);
437
- return answers;
438
- }
439
- function capitalize(str) {
440
- return str.charAt(0).toUpperCase() + str.slice(1);
441
- }
442
- function generateComponentCode(component, config) {
443
- const name = capitalize(component);
444
- const propsInterface = `${name}Props`;
445
- return `/**
446
- * ${name} Component
447
- *
448
- * Generated with Nikkory Vibe CLI
449
- * Configuration: color=${config.color}, size=${config.size}, variant=${config.variant || "default"}
450
- */
451
-
452
- 'use client';
453
-
454
- import React, { forwardRef } from 'react';
455
- import { ${name} as Vibe${name} } from '@nikkory/vibe-library/core';
456
-
457
- export interface ${propsInterface} {
458
- children?: React.ReactNode;
459
- className?: string;
460
- // Override default config
461
- color?: string;
462
- size?: string;
463
- variant?: string;
464
- shape?: string;
465
- animation?: string;
466
- elevation?: string;
467
- }
468
-
469
- /**
470
- * Pre-configured ${name} with:
471
- * - Color: ${config.color}
472
- * - Size: ${config.size}
473
- * - Variant: ${config.variant || "default"}
474
- * - Shape: ${config.shape}
475
- * - Animation: ${config.animation}
476
- * - Elevation: ${config.elevation}
477
- */
478
- export const ${name} = forwardRef<HTMLElement, ${propsInterface}>(
479
- (
480
- {
481
- children,
482
- className = '',
483
- color = '${config.color}',
484
- size = '${config.size}',
485
- variant = '${config.variant || "solid"}',
486
- shape = '${config.shape}',
487
- animation = '${config.animation}',
488
- elevation = '${config.elevation}',
489
- ...props
490
- },
491
- ref
492
- ) => {
493
- return (
494
- <Vibe${name}
495
- ref={ref}
496
- color={color}
497
- size={size}
498
- variant={variant}
499
- shape={shape}
500
- animation={animation}
501
- elevation={elevation}
502
- className={className}
503
- {...props}
504
- >
505
- {children}
506
- </Vibe${name}>
507
- );
508
- }
509
- );
510
-
511
- ${name}.displayName = '${name}';
512
-
513
- export default ${name};
514
- `;
515
- }
516
-
517
- // src/commands/copy.ts
518
- var fsSync = __toESM(require("fs"));
519
- var fs2 = __toESM(require("fs/promises"));
520
- var path2 = __toESM(require("path"));
521
- var import_commander2 = require("commander");
522
- var DESIGN_SYSTEMS = [
523
- "material-design",
524
- "ios-hig",
525
- "glassmorphism",
526
- "neumorphism",
527
- "minimalism",
528
- "brutalism"
529
- ];
530
- var TIERS = ["basic", "standard", "enterprise"];
531
- var COMPONENTS = [
532
- // Core
533
- "button",
534
- "input",
535
- "textarea",
536
- "select",
537
- "checkbox",
538
- "radio",
539
- "switch",
540
- "slider",
541
- // Display
542
- "badge",
543
- "avatar",
544
- "card",
545
- "tooltip",
546
- "popover",
547
- // Feedback
548
- "alert",
549
- "toast",
550
- "progress",
551
- "spinner",
552
- "skeleton",
553
- // Navigation
554
- "tabs",
555
- "breadcrumb",
556
- "pagination",
557
- "stepper",
558
- "menu",
559
- // Overlay
560
- "modal",
561
- "drawer",
562
- "dropdown",
563
- "dialog",
564
- // Data
565
- "table",
566
- "list",
567
- "tree",
568
- "timeline",
569
- // Media
570
- "image",
571
- "video",
572
- "audio",
573
- "carousel",
574
- "gallery",
575
- // Form
576
- "form",
577
- "field",
578
- "label",
579
- "error-message",
580
- // Layout
581
- "container",
582
- "grid",
583
- "flex",
584
- "divider",
585
- "spacer",
586
- // Typography
587
- "heading",
588
- "text",
589
- "link",
590
- "code",
591
- // Charts
592
- "chart",
593
- "sparkline",
594
- "gauge",
595
- // Special
596
- "rating",
597
- "transfer",
598
- "color-picker",
599
- "date-picker",
600
- "file-upload"
601
- ];
602
- var DESIGN_ALIASES = {
603
- material: "material-design",
604
- md: "material-design",
605
- ios: "ios-hig",
606
- hig: "ios-hig",
607
- glass: "glassmorphism",
608
- neu: "neumorphism",
609
- neomorphism: "neumorphism",
610
- minimal: "minimalism",
611
- min: "minimalism",
612
- brutal: "brutalism"
613
- };
614
- var copyCommand = new import_commander2.Command("copy").alias("cp").description("Copy pre-built components from the library (zero-token)").argument(
615
- "[component]",
616
- "Component to copy (button, card, etc. or path like button/glassmorphism/enterprise)"
617
- ).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) => {
618
- try {
619
- logger.header("\u{1F4CB} Nikkory Vibe - Zero-Token Copy");
620
- if (options.all) {
621
- await copyAllComponents(options);
622
- return;
623
- }
624
- if (!component) {
625
- logger.error("Please specify a component to copy");
626
- logger.newline();
627
- logger.info("Usage:");
628
- logger.code(" vibe copy button");
629
- logger.code(" vibe copy button/glassmorphism");
630
- logger.code(" vibe copy button/glassmorphism/enterprise");
631
- logger.code(" vibe copy --all --design=brutalism");
632
- logger.newline();
633
- logger.info("Available components:");
634
- logger.code(` ${COMPONENTS.slice(0, 10).join(", ")}...`);
635
- logger.info(` Run 'vibe list templates' for full list`);
636
- process.exit(1);
637
- }
638
- const parsed = parseComponentPath(component, options);
639
- if (!validateComponentPath(parsed)) {
640
- process.exit(1);
641
- }
642
- logger.newline();
643
- logger.info(`Component: ${capitalize2(parsed.component)}`);
644
- logger.info(`Design System: ${formatDesignSystem(parsed.designSystem)}`);
645
- logger.info(`Tier: ${capitalize2(parsed.tier)}`);
646
- logger.newline();
647
- await copyComponent(parsed, options);
648
- } catch (error) {
649
- logger.stopSpinner();
650
- logger.error("Copy failed");
651
- if (error instanceof Error) {
652
- logger.debug(error.stack || error.message);
653
- }
654
- process.exit(1);
655
- }
656
- });
657
- function parseComponentPath(input, options) {
658
- const parts = input.split("/").filter(Boolean);
659
- const component = parts[0] ?? "";
660
- let designSystem = options.design ?? "material-design";
661
- let tier = options.tier ?? "standard";
662
- if (parts.length === 2 && parts[1]) {
663
- designSystem = normalizeDesignSystem(parts[1]);
664
- } else if (parts.length >= 3 && parts[1] && parts[2]) {
665
- designSystem = normalizeDesignSystem(parts[1]);
666
- tier = parts[2];
667
- }
668
- designSystem = normalizeDesignSystem(designSystem);
669
- return { component, designSystem, tier };
670
- }
671
- function normalizeDesignSystem(design) {
672
- const lower = design.toLowerCase();
673
- return DESIGN_ALIASES[lower] || lower;
674
- }
675
- function validateComponentPath(parsed) {
676
- if (!COMPONENTS.includes(parsed.component)) {
677
- logger.error(`Unknown component: ${parsed.component}`);
678
- logger.info(`Available: ${COMPONENTS.slice(0, 8).join(", ")}...`);
679
- return false;
680
- }
681
- if (!DESIGN_SYSTEMS.includes(parsed.designSystem)) {
682
- logger.error(`Unknown design system: ${parsed.designSystem}`);
683
- logger.info(`Available: ${DESIGN_SYSTEMS.join(", ")}`);
684
- return false;
685
- }
686
- if (!TIERS.includes(parsed.tier)) {
687
- logger.error(`Unknown tier: ${parsed.tier}`);
688
- logger.info(`Available: ${TIERS.join(", ")}`);
689
- return false;
690
- }
691
- return true;
692
- }
693
- async function copyComponent(parsed, options) {
694
- const { component, designSystem, tier } = parsed;
695
- const libraryRoot = findLibraryRoot();
696
- const sourcePath = path2.join(
697
- libraryRoot,
698
- "src",
699
- "components",
700
- component,
701
- designSystem,
702
- `${tier}.tsx`
703
- );
704
- const sourceExists = await fileExists(sourcePath);
705
- if (!sourceExists) {
706
- logger.error(`Component not found: ${sourcePath}`);
707
- logger.info("This component may not be available yet.");
708
- logger.info("Run `vibe list templates` to see available components.");
709
- process.exit(1);
710
- }
711
- const outputDir = path2.join(process.cwd(), options.output || "./components");
712
- const fileName = `${capitalize2(component)}.tsx`;
713
- const outputPath = path2.join(outputDir, fileName);
714
- const outputExists = await fileExists(outputPath);
715
- if (outputExists && !options.overwrite) {
716
- logger.error(`File already exists: ${outputPath}`);
717
- logger.info("Use --overwrite to replace it");
718
- process.exit(1);
719
- }
720
- logger.startSpinner(`Reading ${component}...`);
721
- const sourceCode = await fs2.readFile(sourcePath, "utf-8");
722
- logger.stopSpinnerSuccess("Source loaded");
723
- const transformedCode = transformComponent(sourceCode, parsed);
724
- if (options.dryRun) {
725
- logger.newline();
726
- logger.header("Preview (Dry Run)");
727
- logger.code(`${transformedCode.slice(0, 1e3)}
728
- ...`);
729
- logger.newline();
730
- logger.info(`Would write to: ${outputPath}`);
731
- logger.info(`Lines: ${transformedCode.split("\n").length}`);
732
- return;
733
- }
734
- logger.startSpinner(`Writing to ${outputPath}...`);
735
- await fs2.mkdir(outputDir, { recursive: true });
736
- await fs2.writeFile(outputPath, transformedCode, "utf-8");
737
- logger.stopSpinnerSuccess("Component copied");
738
- logger.newline();
739
- logger.box(
740
- `\u2728 ${capitalize2(component)} copied successfully!
741
-
742
- File: ${outputPath}
743
- Design: ${formatDesignSystem(designSystem)}
744
- Tier: ${capitalize2(tier)}
745
- Lines: ${transformedCode.split("\n").length}`,
746
- { title: "Success", borderColor: "green" }
747
- );
748
- logger.newline();
749
- logger.info("Usage:");
750
- logger.code(
751
- ` import { ${capitalize2(component)} } from './components/${capitalize2(component)}';`
752
- );
753
- logger.newline();
754
- }
755
- async function copyAllComponents(options) {
756
- const designSystem = normalizeDesignSystem(options.design || "material-design");
757
- const tier = options.tier || "standard";
758
- logger.newline();
759
- logger.info(`Copying all components...`);
760
- logger.info(`Design System: ${formatDesignSystem(designSystem)}`);
761
- logger.info(`Tier: ${capitalize2(tier)}`);
762
- logger.newline();
763
- const libraryRoot = findLibraryRoot();
764
- let copied = 0;
765
- let skipped = 0;
766
- const errors = [];
767
- for (const component of COMPONENTS) {
768
- const sourcePath = path2.join(
769
- libraryRoot,
770
- "src",
771
- "components",
772
- component,
773
- designSystem,
774
- `${tier}.tsx`
775
- );
776
- const exists = await fileExists(sourcePath);
777
- if (!exists) {
778
- skipped++;
779
- continue;
780
- }
781
- try {
782
- await copyComponent({ component, designSystem, tier }, { ...options, all: false });
783
- copied++;
784
- } catch (error) {
785
- errors.push(component);
786
- }
787
- }
788
- logger.newline();
789
- logger.box(
790
- `\u{1F4E6} Bulk Copy Complete
791
-
792
- Copied: ${copied} components
793
- Skipped: ${skipped} (not available)
794
- Errors: ${errors.length}`,
795
- { title: "Summary", borderColor: copied > 0 ? "green" : "yellow" }
796
- );
797
- if (errors.length > 0) {
798
- logger.warn(`Failed: ${errors.join(", ")}`);
799
- }
800
- }
801
- function transformComponent(code, parsed) {
802
- const { component, designSystem, tier } = parsed;
803
- const header = `/**
804
- * ${capitalize2(component)} Component
805
- *
806
- * Copied from @nikkory/vibe-library
807
- * Design System: ${formatDesignSystem(designSystem)}
808
- * Tier: ${capitalize2(tier)}
809
- *
810
- * Zero-token generation - No AI needed
811
- * Just copy, paste, and customize!
812
- */
813
-
814
- `;
815
- let transformed = code;
816
- transformed = transformed.replace(/from ['"]@nikkory\/vibe-library\/core['"]/g, "from './core'");
817
- transformed = transformed.replace(/from ['"]@nikkory\/vibe-library['"]/g, "from './index'");
818
- if (!transformed.includes("'use client'")) {
819
- transformed = `'use client';
820
-
821
- ${transformed}`;
822
- }
823
- return `${header}${transformed}`;
824
- }
825
- function findLibraryRoot() {
826
- const possiblePaths = [
827
- path2.join(process.cwd(), "node_modules", "@nikkory", "vibe-library"),
828
- path2.join(process.cwd(), "..", "..", "packages", "library"),
829
- path2.join(__dirname, "..", "..", "..", "library"),
830
- // Development path
831
- "m:/AI Workspace/nikkory-vibe/packages/library"
832
- ];
833
- for (const p of possiblePaths) {
834
- try {
835
- fsSync.accessSync(p);
836
- return p;
837
- } catch {
838
- }
839
- }
840
- return possiblePaths[possiblePaths.length - 1] ?? "m:/AI Workspace/nikkory-vibe/packages/library";
841
- }
842
- async function fileExists(filePath) {
843
- try {
844
- await fs2.access(filePath);
845
- return true;
846
- } catch {
847
- return false;
848
- }
849
- }
850
- function capitalize2(str) {
851
- return str.charAt(0).toUpperCase() + str.slice(1);
852
- }
853
- function formatDesignSystem(design) {
854
- const names = {
855
- "material-design": "Material Design",
856
- "ios-hig": "iOS HIG",
857
- glassmorphism: "Glassmorphism",
858
- neumorphism: "Neumorphism",
859
- minimalism: "Minimalism",
860
- brutalism: "Brutalism"
861
- };
862
- return names[design] || capitalize2(design);
863
- }
864
-
865
- // src/commands/doctor/index.ts
866
- var import_commander8 = require("commander");
867
-
868
- // src/commands/doctor/fix.ts
869
- var import_promises = require("fs/promises");
870
- var import_chalk2 = __toESM(require("chalk"));
871
- var import_commander3 = require("commander");
872
- var import_glob = require("glob");
873
-
874
- // src/lib/code-doctor-stub.ts
875
- var CodeDoctor = class {
876
- config;
877
- constructor(config = {}) {
878
- this.config = {
879
- tier: config.tier ?? "standard",
880
- autoFix: config.autoFix ?? false,
881
- strict: config.strict ?? false,
882
- categories: config.categories,
883
- wcagLevel: config.wcagLevel ?? "AA"
884
- };
885
- }
886
- /**
887
- * Analyze code string
888
- */
889
- analyze(code, filename) {
890
- const lines = code.split("\n").length;
891
- return Promise.resolve({
892
- filename,
893
- issues: [],
894
- healthScore: 100,
895
- tier: this.config.tier ?? "standard",
896
- metadata: {
897
- linesOfCode: lines,
898
- analyzedAt: /* @__PURE__ */ new Date(),
899
- categories: this.config.categories ?? ["typescript", "react"]
900
- }
901
- });
902
- }
903
- /**
904
- * Process URL (fetch and analyze)
905
- */
906
- processUrl(url) {
907
- return Promise.resolve({
908
- filename: url,
909
- issues: [
910
- {
911
- id: "stub-001",
912
- category: "typescript",
913
- severity: "info",
914
- message: "Code Doctor is being migrated. URL processing unavailable.",
915
- location: { line: 1, column: 1 },
916
- autoFixable: false
917
- }
918
- ],
919
- healthScore: 0,
920
- tier: this.config.tier ?? "standard",
921
- metadata: {
922
- linesOfCode: 0,
923
- analyzedAt: /* @__PURE__ */ new Date(),
924
- categories: []
925
- }
926
- });
927
- }
928
- /**
929
- * Fix issues in code
930
- */
931
- fix(code, _filename) {
932
- return Promise.resolve({ code, fixed: 0 });
933
- }
934
- /**
935
- * Analyze and fix (returns DiagnosticResult with fixedCode)
936
- */
937
- async analyzeAndFix(code, filename) {
938
- const result = await this.analyze(code, filename);
939
- return {
940
- ...result,
941
- fixedCode: code,
942
- fixesApplied: 0
943
- };
944
- }
945
- /**
946
- * Upgrade code to higher tier
947
- */
948
- upgradeTier(code, _targetTier) {
949
- return Promise.resolve({ code, changes: 0 });
950
- }
951
- /**
952
- * Generate report
953
- */
954
- generateReport(results, format) {
955
- if (format === "json") {
956
- return Promise.resolve(JSON.stringify(results, null, 2));
957
- }
958
- return Promise.resolve(`# Code Doctor Report
959
-
960
- Migration in progress. ${results.length} files analyzed.`);
961
- }
962
- /**
963
- * Upgrade tier (stub)
964
- */
965
- upgrade(code, _fromTier, _toTier) {
966
- return Promise.resolve({ code, changes: 0 });
967
- }
968
- };
969
-
970
- // src/commands/doctor/fix.ts
971
- var fixCommand = new import_commander3.Command("fix").description("Auto-fix issues in code").argument("<path>", "File or directory to fix").option("-d, --dry-run", "Preview fixes without applying").option("-c, --categories <list>", "Categories to fix (comma-separated)").option("-y, --yes", "Skip confirmation prompt").option("--backup", "Create backup before fixing").option("-v, --verbose", "Verbose output").action(async (path5, options) => {
972
- try {
973
- const categories = options.categories ? options.categories.split(",").map((c) => c.trim()) : void 0;
974
- const doctor = new CodeDoctor({
975
- tier: "standard",
976
- autoFix: true,
977
- categories
978
- });
979
- const files = await (0, import_glob.glob)(path5.includes("*") ? path5 : `${path5}/**/*.{tsx,ts,jsx,js}`, {
980
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"]
981
- });
982
- let filesToProcess = [];
983
- if (files.length === 0) {
984
- try {
985
- await (0, import_promises.readFile)(path5, "utf-8");
986
- filesToProcess = [path5];
987
- } catch {
988
- console.error(import_chalk2.default.red(`No files found at: ${path5}`));
989
- process.exit(1);
990
- }
991
- } else {
992
- filesToProcess = files;
993
- }
994
- console.log(import_chalk2.default.blue(`Found ${filesToProcess.length} file(s) to process`));
995
- console.log("");
996
- let totalFixedFiles = 0;
997
- let totalFixes = 0;
998
- const fixedFiles = [];
999
- for (const file of filesToProcess) {
1000
- try {
1001
- const code = await (0, import_promises.readFile)(file, "utf-8");
1002
- const result = await doctor.analyzeAndFix(code, file);
1003
- if (result.fixedCode && result.fixedCode !== code) {
1004
- const fixCount = result.fixesApplied ?? 0;
1005
- totalFixedFiles++;
1006
- totalFixes += fixCount;
1007
- fixedFiles.push({ file, fixes: [`${fixCount} fixes applied`] });
1008
- if (options.verbose || options.dryRun) {
1009
- console.log(import_chalk2.default.green(`\u2713 ${file} (${fixCount} fixes)`));
1010
- }
1011
- if (!options.dryRun) {
1012
- if (options.backup) {
1013
- await (0, import_promises.copyFile)(file, `${file}.bak`);
1014
- }
1015
- await (0, import_promises.writeFile)(file, result.fixedCode, "utf-8");
1016
- }
1017
- } else if (options.verbose) {
1018
- console.log(import_chalk2.default.dim(`\u25CB ${file} (no fixes needed)`));
1019
- }
1020
- } catch {
1021
- if (options.verbose) {
1022
- console.log(import_chalk2.default.yellow(`\u26A0 Skipped: ${file}`));
1023
- }
1024
- }
1025
- }
1026
- console.log("");
1027
- console.log(import_chalk2.default.bold("\u2550".repeat(60)));
1028
- console.log(import_chalk2.default.bold(options.dryRun ? " DRY RUN - No changes made" : " Fix Summary"));
1029
- console.log(import_chalk2.default.bold("\u2550".repeat(60)));
1030
- console.log("");
1031
- console.log(`Files processed: ${import_chalk2.default.bold(filesToProcess.length)}`);
1032
- console.log(`Files fixed: ${import_chalk2.default.green(totalFixedFiles)}`);
1033
- console.log(`Total fixes applied: ${import_chalk2.default.blue(totalFixes)}`);
1034
- console.log("");
1035
- if (options.dryRun && totalFixedFiles > 0) {
1036
- console.log(import_chalk2.default.yellow("Run without --dry-run to apply fixes."));
1037
- }
1038
- if (options.backup && !options.dryRun && totalFixedFiles > 0) {
1039
- console.log(import_chalk2.default.dim(`Backup files created with .bak extension.`));
1040
- }
1041
- console.log("");
1042
- console.log(import_chalk2.default.dim("\u2550".repeat(60)));
1043
- console.log(import_chalk2.default.dim(" Powered by Nikkory"));
1044
- console.log(import_chalk2.default.dim("\u2550".repeat(60)));
1045
- } catch (error) {
1046
- console.error(
1047
- import_chalk2.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`)
1048
- );
1049
- process.exit(1);
1050
- }
1051
- });
1052
-
1053
- // src/commands/doctor/report.ts
1054
- var import_promises2 = require("fs/promises");
1055
- var import_chalk3 = __toESM(require("chalk"));
1056
- var import_commander4 = require("commander");
1057
- var import_glob2 = require("glob");
1058
- var reportCommand = new import_commander4.Command("report").description("Generate detailed diagnostic report").argument("<path>", "File or directory to analyze").option("-f, --format <format>", "Output format (text, json, markdown, html, sarif)", "text").option("-o, --output <file>", "Write report to file").option("--group-by <key>", "Group issues by (category, severity, file)", "category").option("--include-code", "Include code snippets in report").option("-v, --verbose", "Verbose output").action(async (path5, options) => {
1059
- try {
1060
- const doctor = new CodeDoctor({
1061
- tier: "standard",
1062
- autoFix: false
1063
- });
1064
- const files = await (0, import_glob2.glob)(path5.includes("*") ? path5 : `${path5}/**/*.{tsx,ts,jsx,js}`, {
1065
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"]
1066
- });
1067
- let filesToProcess = [];
1068
- if (files.length === 0) {
1069
- try {
1070
- await (0, import_promises2.readFile)(path5, "utf-8");
1071
- filesToProcess = [path5];
1072
- } catch {
1073
- console.error(import_chalk3.default.red(`No files found at: ${path5}`));
1074
- process.exit(1);
1075
- }
1076
- } else {
1077
- filesToProcess = files;
1078
- }
1079
- if (!options.output) {
1080
- console.log(import_chalk3.default.blue(`Analyzing ${filesToProcess.length} file(s)...`));
1081
- }
1082
- const results = [];
1083
- for (const file of filesToProcess) {
1084
- try {
1085
- const code = await (0, import_promises2.readFile)(file, "utf-8");
1086
- const result = await doctor.analyze(code, file);
1087
- results.push(result);
1088
- } catch {
1089
- }
1090
- }
1091
- let report;
1092
- const format = options.format ?? "text";
1093
- if (results.length === 1) {
1094
- report = generateBatchReport(results, {
1095
- format,
1096
- groupBy: options.groupBy ?? "category",
1097
- includeCode: options.includeCode ?? false
1098
- });
1099
- } else {
1100
- report = generateBatchReport(results, {
1101
- format,
1102
- groupBy: options.groupBy ?? "category",
1103
- includeCode: options.includeCode ?? false
1104
- });
1105
- }
1106
- if (options.output) {
1107
- await (0, import_promises2.writeFile)(options.output, report, "utf-8");
1108
- console.log(import_chalk3.default.green(`Report written to: ${options.output}`));
1109
- } else {
1110
- console.log(report);
1111
- }
1112
- } catch (error) {
1113
- console.error(
1114
- import_chalk3.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`)
1115
- );
1116
- process.exit(1);
1117
- }
1118
- });
1119
- function generateBatchReport(results, options) {
1120
- const format = options.format;
1121
- if (format === "json") {
1122
- return JSON.stringify(
1123
- {
1124
- summary: {
1125
- totalFiles: results.length,
1126
- totalIssues: results.reduce((a, r) => a + r.issues.length, 0),
1127
- averageScore: Math.round(results.reduce((a, r) => a + r.healthScore, 0) / results.length),
1128
- healthyFiles: results.filter((r) => r.healthScore >= 90).length
1129
- },
1130
- files: results
1131
- },
1132
- null,
1133
- 2
1134
- );
1135
- }
1136
- if (format === "markdown") {
1137
- const lines2 = [];
1138
- lines2.push("# Code Doctor Report");
1139
- lines2.push("");
1140
- lines2.push("## Summary");
1141
- lines2.push("");
1142
- lines2.push(`| Metric | Value |`);
1143
- lines2.push(`|--------|-------|`);
1144
- lines2.push(`| Total Files | ${results.length} |`);
1145
- lines2.push(`| Total Issues | ${results.reduce((a, r) => a + r.issues.length, 0)} |`);
1146
- lines2.push(
1147
- `| Average Score | ${Math.round(results.reduce((a, r) => a + r.healthScore, 0) / results.length)}/100 |`
1148
- );
1149
- lines2.push(`| Healthy Files | ${results.filter((r) => r.healthScore >= 90).length} |`);
1150
- lines2.push("");
1151
- lines2.push("## Files by Health Score");
1152
- lines2.push("");
1153
- const sortedResults2 = [...results].sort((a, b) => a.healthScore - b.healthScore);
1154
- for (const result of sortedResults2.slice(0, 20)) {
1155
- const emoji = result.healthScore >= 90 ? "\u{1F49A}" : result.healthScore >= 70 ? "\u{1F49B}" : result.healthScore >= 50 ? "\u{1F9E1}" : "\u2764\uFE0F";
1156
- lines2.push(
1157
- `- ${emoji} **${result.filename}** - ${result.healthScore}/100 (${result.issues.length} issues)`
1158
- );
1159
- }
1160
- if (sortedResults2.length > 20) {
1161
- lines2.push(`- ... and ${sortedResults2.length - 20} more files`);
1162
- }
1163
- lines2.push("");
1164
- lines2.push("---");
1165
- lines2.push("*Powered by Nikkory*");
1166
- return lines2.join("\n");
1167
- }
1168
- const lines = [];
1169
- lines.push("\u2550".repeat(60));
1170
- lines.push(" CODE DOCTOR v1.1 - Batch Report");
1171
- lines.push("\u2550".repeat(60));
1172
- lines.push("");
1173
- lines.push(`Total Files: ${results.length}`);
1174
- lines.push(`Total Issues: ${results.reduce((a, r) => a + r.issues.length, 0)}`);
1175
- lines.push(
1176
- `Average Score: ${Math.round(results.reduce((a, r) => a + r.healthScore, 0) / results.length)}/100`
1177
- );
1178
- lines.push(`Healthy Files (90+): ${results.filter((r) => r.healthScore >= 90).length}`);
1179
- lines.push("");
1180
- lines.push("\u2500".repeat(60));
1181
- lines.push("Files by Health Score:");
1182
- lines.push("\u2500".repeat(60));
1183
- const sortedResults = [...results].sort((a, b) => a.healthScore - b.healthScore);
1184
- for (const result of sortedResults.slice(0, 20)) {
1185
- const emoji = result.healthScore >= 90 ? "\u{1F49A}" : result.healthScore >= 70 ? "\u{1F49B}" : result.healthScore >= 50 ? "\u{1F9E1}" : "\u2764\uFE0F";
1186
- lines.push(
1187
- ` ${emoji} ${result.filename} (${result.healthScore}/100, ${result.issues.length} issues)`
1188
- );
1189
- }
1190
- if (sortedResults.length > 20) {
1191
- lines.push(` ... and ${sortedResults.length - 20} more files`);
1192
- }
1193
- lines.push("");
1194
- lines.push("\u2550".repeat(60));
1195
- lines.push(" Powered by Nikkory");
1196
- lines.push("\u2550".repeat(60));
1197
- return lines.join("\n");
1198
- }
1199
-
1200
- // src/commands/doctor/scan.ts
1201
- var import_promises3 = require("fs/promises");
1202
- var import_chalk4 = __toESM(require("chalk"));
1203
- var import_commander5 = require("commander");
1204
- var import_glob3 = require("glob");
1205
- function getHealthEmoji(score) {
1206
- if (score >= 90) return "\u{1F49A}";
1207
- if (score >= 70) return "\u{1F49B}";
1208
- if (score >= 50) return "\u{1F9E1}";
1209
- return "\u2764\uFE0F";
1210
- }
1211
- function getSeverityIcon(severity) {
1212
- switch (severity) {
1213
- case "critical":
1214
- return "\u{1F480}";
1215
- case "error":
1216
- return "\u2717";
1217
- case "warning":
1218
- return "\u26A0";
1219
- default:
1220
- return "\u2139";
1221
- }
1222
- }
1223
- function formatDuration(ms) {
1224
- if (ms < 1e3) return `${ms}ms`;
1225
- if (ms < 6e4) return `${(ms / 1e3).toFixed(2)}s`;
1226
- return `${Math.floor(ms / 6e4)}m ${Math.floor(ms % 6e4 / 1e3)}s`;
1227
- }
1228
- function calculateMetrics(results, skipped, durationMs) {
1229
- let totalIssues = 0;
1230
- let criticalCount = 0;
1231
- let errorCount = 0;
1232
- let warningCount = 0;
1233
- let infoCount = 0;
1234
- let autoFixableCount = 0;
1235
- let totalScore = 0;
1236
- for (const result of results) {
1237
- totalIssues += result.issues.length;
1238
- totalScore += result.healthScore;
1239
- for (const issue of result.issues) {
1240
- switch (issue.severity) {
1241
- case "critical":
1242
- criticalCount++;
1243
- break;
1244
- case "error":
1245
- errorCount++;
1246
- break;
1247
- case "warning":
1248
- warningCount++;
1249
- break;
1250
- default:
1251
- infoCount++;
1252
- break;
1253
- }
1254
- if (issue.autoFixable) autoFixableCount++;
1255
- }
1256
- }
1257
- return {
1258
- totalFiles: results.length + skipped,
1259
- scannedFiles: results.length,
1260
- skippedFiles: skipped,
1261
- totalIssues,
1262
- criticalCount,
1263
- errorCount,
1264
- warningCount,
1265
- infoCount,
1266
- avgScore: results.length > 0 ? Math.round(totalScore / results.length) : 0,
1267
- healthyCount: results.filter((r) => r.healthScore >= 90).length,
1268
- autoFixableCount,
1269
- scanDurationMs: durationMs
1270
- };
1271
- }
1272
- function outputJson(results, metrics) {
1273
- const output = {
1274
- version: "1.1.0",
1275
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1276
- metrics,
1277
- results: results.map((r) => ({
1278
- file: r.filename,
1279
- score: r.healthScore,
1280
- issues: r.issues
1281
- }))
1282
- };
1283
- console.log(JSON.stringify(output, null, 2));
1284
- }
1285
- function outputConsole(results, metrics, verbose) {
1286
- console.log("");
1287
- console.log(import_chalk4.default.bold("\u2550".repeat(70)));
1288
- console.log(import_chalk4.default.bold(" CODE DOCTOR v1.1 - Enterprise Scan Results"));
1289
- console.log(import_chalk4.default.bold("\u2550".repeat(70)));
1290
- console.log("");
1291
- console.log(
1292
- import_chalk4.default.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")
1293
- );
1294
- console.log(
1295
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.bold(" SUMMARY ") + import_chalk4.default.cyan("\u2502")
1296
- );
1297
- console.log(
1298
- import_chalk4.default.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")
1299
- );
1300
- console.log(
1301
- `${import_chalk4.default.cyan("\u2502")} Health Score: ${import_chalk4.default.bold(metrics.avgScore.toString().padEnd(3))}/100 ${getHealthEmoji(metrics.avgScore)} ${import_chalk4.default.cyan("\u2502")}`
1302
- );
1303
- console.log(
1304
- import_chalk4.default.cyan("\u2502") + ` Files Scanned: ${import_chalk4.default.bold(metrics.scannedFiles.toString())} `.slice(
1305
- 0,
1306
- 67
1307
- ) + import_chalk4.default.cyan("\u2502")
1308
- );
1309
- console.log(
1310
- import_chalk4.default.cyan("\u2502") + ` Healthy (90+): ${import_chalk4.default.green(metrics.healthyCount.toString())} (${Math.round(metrics.healthyCount / Math.max(metrics.scannedFiles, 1) * 100)}%) `.slice(
1311
- 0,
1312
- 67
1313
- ) + import_chalk4.default.cyan("\u2502")
1314
- );
1315
- console.log(
1316
- import_chalk4.default.cyan("\u2502") + ` Scan Duration: ${formatDuration(metrics.scanDurationMs)} `.slice(
1317
- 0,
1318
- 67
1319
- ) + import_chalk4.default.cyan("\u2502")
1320
- );
1321
- console.log(
1322
- import_chalk4.default.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")
1323
- );
1324
- console.log("");
1325
- console.log(
1326
- import_chalk4.default.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")
1327
- );
1328
- console.log(
1329
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.bold(" ISSUES BREAKDOWN ") + import_chalk4.default.cyan("\u2502")
1330
- );
1331
- console.log(
1332
- import_chalk4.default.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")
1333
- );
1334
- console.log(
1335
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.red("\u{1F480} Critical:")} ${metrics.criticalCount.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1336
- );
1337
- console.log(
1338
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.red("\u2717 Errors:")} ${metrics.errorCount.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1339
- );
1340
- console.log(
1341
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.yellow("\u26A0 Warnings:")} ${metrics.warningCount.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1342
- );
1343
- console.log(
1344
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.blue("\u2139 Info:")} ${metrics.infoCount.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1345
- );
1346
- console.log(
1347
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.green("\u{1F527} Auto-fixable:")} ${metrics.autoFixableCount.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1348
- );
1349
- console.log(import_chalk4.default.cyan("\u2502") + import_chalk4.default.dim("\u2500".repeat(69)) + import_chalk4.default.cyan("\u2502"));
1350
- console.log(
1351
- `${import_chalk4.default.cyan("\u2502")} ${import_chalk4.default.bold("Total Issues:")} ${metrics.totalIssues.toString().padEnd(5)} ${import_chalk4.default.cyan("\u2502")}`
1352
- );
1353
- console.log(
1354
- import_chalk4.default.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")
1355
- );
1356
- console.log("");
1357
- const filesWithIssues = results.filter((r) => r.issues.length > 0).sort((a, b) => a.healthScore - b.healthScore);
1358
- if (filesWithIssues.length > 0) {
1359
- console.log(
1360
- import_chalk4.default.cyan("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")
1361
- );
1362
- console.log(
1363
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.bold(" FILES WITH ISSUES ") + import_chalk4.default.cyan("\u2502")
1364
- );
1365
- console.log(
1366
- import_chalk4.default.cyan("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")
1367
- );
1368
- const displayCount = verbose ? filesWithIssues.length : Math.min(filesWithIssues.length, 10);
1369
- for (let i = 0; i < displayCount; i++) {
1370
- const result = filesWithIssues[i];
1371
- const emoji = getHealthEmoji(result.healthScore);
1372
- const fileName = result.filename.length > 45 ? `...${result.filename.slice(-42)}` : result.filename;
1373
- console.log(
1374
- `${import_chalk4.default.cyan("\u2502")} ${emoji} ${fileName.padEnd(50)} ${import_chalk4.default.bold(result.healthScore.toString().padStart(3))}/100${import_chalk4.default.cyan(" \u2502")}`
1375
- );
1376
- if (verbose) {
1377
- const issueLimit = Math.min(result.issues.length, 5);
1378
- for (let j = 0; j < issueLimit; j++) {
1379
- const issue = result.issues[j];
1380
- const icon = getSeverityIcon(issue.severity);
1381
- const msg = issue.message.length > 50 ? `${issue.message.slice(0, 47)}...` : issue.message;
1382
- console.log(
1383
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.dim(` ${icon} L${issue.location.line}: ${msg}`.padEnd(69)) + import_chalk4.default.cyan("\u2502")
1384
- );
1385
- }
1386
- if (result.issues.length > issueLimit) {
1387
- console.log(
1388
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.dim(` ... and ${result.issues.length - issueLimit} more issues`.padEnd(69)) + import_chalk4.default.cyan("\u2502")
1389
- );
1390
- }
1391
- }
1392
- }
1393
- if (!verbose && filesWithIssues.length > 10) {
1394
- console.log(
1395
- import_chalk4.default.cyan("\u2502") + import_chalk4.default.dim(` ... and ${filesWithIssues.length - 10} more files with issues`.padEnd(69)) + import_chalk4.default.cyan("\u2502")
1396
- );
1397
- }
1398
- console.log(
1399
- import_chalk4.default.cyan("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")
1400
- );
1401
- console.log("");
1402
- }
1403
- if (metrics.criticalCount > 0 || metrics.errorCount > 0) {
1404
- console.log(
1405
- import_chalk4.default.yellow("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")
1406
- );
1407
- console.log(
1408
- import_chalk4.default.yellow("\u2502") + import_chalk4.default.bold(" RECOMMENDATIONS ") + import_chalk4.default.yellow("\u2502")
1409
- );
1410
- console.log(
1411
- import_chalk4.default.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524")
1412
- );
1413
- if (metrics.criticalCount > 0) {
1414
- console.log(
1415
- import_chalk4.default.yellow("\u2502") + import_chalk4.default.red(" \u26A0 CRITICAL issues require immediate attention! ") + import_chalk4.default.yellow("\u2502")
1416
- );
1417
- }
1418
- if (metrics.autoFixableCount > 0) {
1419
- console.log(
1420
- import_chalk4.default.yellow("\u2502") + ` \u{1F4A1} ${metrics.autoFixableCount} issues can be auto-fixed with: vibe doctor fix <path> `.slice(
1421
- 0,
1422
- 69
1423
- ) + import_chalk4.default.yellow("\u2502")
1424
- );
1425
- }
1426
- if (metrics.avgScore < 70) {
1427
- console.log(
1428
- `${import_chalk4.default.yellow("\u2502")} \u{1F4C8} Consider upgrading to enterprise tier for better code quality ${import_chalk4.default.yellow("\u2502")}`
1429
- );
1430
- }
1431
- console.log(
1432
- import_chalk4.default.yellow("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")
1433
- );
1434
- console.log("");
1435
- }
1436
- console.log(import_chalk4.default.dim("\u2550".repeat(70)));
1437
- console.log(import_chalk4.default.dim(" Powered by Nikkory \u2022 https://nikkory.dev"));
1438
- console.log(import_chalk4.default.dim("\u2550".repeat(70)));
1439
- }
1440
- var scanCommand = new import_commander5.Command("scan").description("Scan code for issues with enterprise-grade analysis").argument("<path>", "File, directory, or URL to scan").option("-c, --categories <list>", "Categories to check (comma-separated)").option("-l, --level <level>", "WCAG accessibility level (A, AA, AAA)", "AA").option("-s, --strict", "Enable strict mode (more rules)").option("-p, --pattern <glob>", "File pattern to match", "**/*.{tsx,ts,jsx,js}").option("-e, --exclude <glob>", "Pattern to exclude", "**/node_modules/**").option("--parallel <number>", "Number of parallel scans", "4").option("--json", "Output as JSON").option("--ci", "CI mode (exit with error code on issues)").option("--min-score <number>", "Minimum health score for CI", "70").option("-v, --verbose", "Verbose output with all issues").action(async (path5, options) => {
1441
- const startTime = Date.now();
1442
- try {
1443
- const isUrl = path5.startsWith("http://") || path5.startsWith("https://");
1444
- const categories = options.categories ? options.categories.split(",").map((c) => c.trim()) : void 0;
1445
- const doctor = new CodeDoctor({
1446
- tier: "enterprise",
1447
- autoFix: false,
1448
- strict: options.strict ?? false,
1449
- categories,
1450
- wcagLevel: options.level ?? "AA"
1451
- });
1452
- const results = [];
1453
- let skippedCount = 0;
1454
- if (isUrl) {
1455
- if (!options.json) {
1456
- console.log(import_chalk4.default.blue("\u{1F310} Fetching code from URL..."));
1457
- }
1458
- const result = await doctor.processUrl(path5);
1459
- results.push(result);
1460
- } else {
1461
- const pattern = options.pattern ?? "**/*.{tsx,ts,jsx,js}";
1462
- const exclude = options.exclude ?? "**/node_modules/**";
1463
- const files = await (0, import_glob3.glob)(path5.includes("*") ? path5 : `${path5}/${pattern}`, {
1464
- ignore: [exclude, "**/dist/**", "**/build/**", "**/.git/**", "**/.next/**"],
1465
- nodir: true
1466
- });
1467
- if (files.length === 0) {
1468
- try {
1469
- const code = await (0, import_promises3.readFile)(path5, "utf-8");
1470
- const result = await doctor.analyze(code, path5);
1471
- results.push(result);
1472
- } catch {
1473
- console.error(import_chalk4.default.red(`\u274C No files found at: ${path5}`));
1474
- process.exit(1);
1475
- }
1476
- } else {
1477
- if (!options.json) {
1478
- console.log(import_chalk4.default.blue(`\u{1F50D} Scanning ${files.length} files...`));
1479
- console.log("");
1480
- }
1481
- const parallelCount = parseInt(options.parallel ?? "4", 10);
1482
- const batchSize = Math.ceil(files.length / parallelCount);
1483
- const batches = [];
1484
- for (let i = 0; i < files.length; i += batchSize) {
1485
- batches.push(files.slice(i, i + batchSize));
1486
- }
1487
- const batchResults = await Promise.all(
1488
- batches.map(async (batch) => {
1489
- const localResults = [];
1490
- let localSkipped = 0;
1491
- for (const file of batch) {
1492
- try {
1493
- const code = await (0, import_promises3.readFile)(file, "utf-8");
1494
- const result = await doctor.analyze(code, file);
1495
- localResults.push(result);
1496
- if (options.verbose && !options.json) {
1497
- const emoji = getHealthEmoji(result.healthScore);
1498
- console.log(
1499
- ` ${emoji} ${file} (${result.healthScore}/100, ${result.issues.length} issues)`
1500
- );
1501
- }
1502
- } catch {
1503
- localSkipped++;
1504
- if (options.verbose && !options.json) {
1505
- console.log(import_chalk4.default.yellow(` \u26A0 Skipped: ${file}`));
1506
- }
1507
- }
1508
- }
1509
- return { results: localResults, skipped: localSkipped };
1510
- })
1511
- );
1512
- for (const batch of batchResults) {
1513
- results.push(...batch.results);
1514
- skippedCount += batch.skipped;
1515
- }
1516
- }
1517
- }
1518
- const duration = Date.now() - startTime;
1519
- const metrics = calculateMetrics(results, skippedCount, duration);
1520
- if (options.json) {
1521
- outputJson(results, metrics);
1522
- } else {
1523
- outputConsole(results, metrics, options.verbose ?? false);
1524
- }
1525
- if (options.ci) {
1526
- const minScore = parseInt(options.minScore ?? "70", 10);
1527
- if (metrics.avgScore < minScore) {
1528
- console.error(
1529
- import_chalk4.default.red(`
1530
- \u274C CI Check Failed: Average score ${metrics.avgScore} < ${minScore}`)
1531
- );
1532
- process.exit(2);
1533
- }
1534
- if (metrics.criticalCount > 0) {
1535
- console.error(
1536
- import_chalk4.default.red(`
1537
- \u274C CI Check Failed: ${metrics.criticalCount} critical issue(s) found`)
1538
- );
1539
- process.exit(2);
1540
- }
1541
- console.log(import_chalk4.default.green(`
1542
- \u2705 CI Check Passed: Score ${metrics.avgScore}/100`));
1543
- }
1544
- } catch (error) {
1545
- console.error(
1546
- import_chalk4.default.red(`\u274C Error: ${error instanceof Error ? error.message : "Unknown error"}`)
1547
- );
1548
- process.exit(1);
1549
- }
1550
- });
1551
-
1552
- // src/commands/doctor/upgrade.ts
1553
- var import_promises4 = require("fs/promises");
1554
- var import_chalk5 = __toESM(require("chalk"));
1555
- var import_commander6 = require("commander");
1556
- var import_glob4 = require("glob");
1557
- var upgradeCommand = new import_commander6.Command("upgrade").description("Upgrade code to higher quality tier").argument("<path>", "File or directory to upgrade").option("-t, --tier <tier>", "Target tier (standard, enterprise)", "enterprise").option("-d, --dry-run", "Preview upgrades without applying").option("-o, --output <file>", "Write to different file").option("--backup", "Create backup before modifying").option("-v, --verbose", "Verbose output").action(async (path5, options) => {
1558
- try {
1559
- const targetTier = options.tier ?? "enterprise";
1560
- if (targetTier !== "standard" && targetTier !== "enterprise") {
1561
- console.error(import_chalk5.default.red("Invalid tier. Use: standard or enterprise"));
1562
- process.exit(1);
1563
- }
1564
- const doctor = new CodeDoctor({
1565
- tier: "enterprise",
1566
- autoFix: true
1567
- });
1568
- const files = await (0, import_glob4.glob)(path5.includes("*") ? path5 : `${path5}/**/*.{tsx,ts,jsx,js}`, {
1569
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"]
1570
- });
1571
- let filesToProcess = [];
1572
- if (files.length === 0) {
1573
- try {
1574
- await (0, import_promises4.readFile)(path5, "utf-8");
1575
- filesToProcess = [path5];
1576
- } catch {
1577
- console.error(import_chalk5.default.red(`No files found at: ${path5}`));
1578
- process.exit(1);
1579
- }
1580
- } else {
1581
- filesToProcess = files;
1582
- }
1583
- console.log(
1584
- import_chalk5.default.blue(`Upgrading ${filesToProcess.length} file(s) to ${targetTier} tier...`)
1585
- );
1586
- console.log("");
1587
- let totalUpgraded = 0;
1588
- const upgradedFiles = [];
1589
- for (const file of filesToProcess) {
1590
- try {
1591
- const code = await (0, import_promises4.readFile)(file, "utf-8");
1592
- const { code: upgradedCode, changes } = await doctor.upgradeTier(code, targetTier);
1593
- if (changes > 0) {
1594
- totalUpgraded++;
1595
- upgradedFiles.push({ file, upgrades: [`${changes} changes applied`] });
1596
- if (options.verbose || options.dryRun) {
1597
- console.log(import_chalk5.default.green(`\u2713 ${file} (${changes} changes)`));
1598
- }
1599
- if (!options.dryRun) {
1600
- if (options.backup) {
1601
- await (0, import_promises4.copyFile)(file, `${file}.bak`);
1602
- }
1603
- const outputPath = options.output ?? file;
1604
- await (0, import_promises4.writeFile)(outputPath, upgradedCode, "utf-8");
1605
- }
1606
- } else if (options.verbose) {
1607
- console.log(import_chalk5.default.dim(`\u25CB ${file} (already at target tier)`));
1608
- }
1609
- } catch {
1610
- if (options.verbose) {
1611
- console.log(import_chalk5.default.yellow(`\u26A0 Skipped: ${file}`));
1612
- }
1613
- }
1614
- }
1615
- console.log("");
1616
- console.log(import_chalk5.default.bold("\u2550".repeat(60)));
1617
- console.log(import_chalk5.default.bold(options.dryRun ? " DRY RUN - No changes made" : " Upgrade Summary"));
1618
- console.log(import_chalk5.default.bold("\u2550".repeat(60)));
1619
- console.log("");
1620
- console.log(`Target tier: ${import_chalk5.default.bold(targetTier)}`);
1621
- console.log(`Files processed: ${import_chalk5.default.bold(filesToProcess.length)}`);
1622
- console.log(`Files upgraded: ${import_chalk5.default.green(totalUpgraded)}`);
1623
- console.log("");
1624
- if (totalUpgraded > 0) {
1625
- console.log("Upgrades applied:");
1626
- const allUpgrades = upgradedFiles.flatMap((f) => f.upgrades);
1627
- const uniqueUpgrades = [...new Set(allUpgrades)];
1628
- for (const upgrade of uniqueUpgrades) {
1629
- console.log(import_chalk5.default.dim(` \u2713 ${upgrade}`));
1630
- }
1631
- console.log("");
1632
- }
1633
- if (options.dryRun && totalUpgraded > 0) {
1634
- console.log(import_chalk5.default.yellow("Run without --dry-run to apply upgrades."));
1635
- }
1636
- console.log("");
1637
- console.log(import_chalk5.default.dim("\u2500".repeat(60)));
1638
- console.log(import_chalk5.default.dim("Tier Comparison:"));
1639
- console.log(import_chalk5.default.dim("\u2500".repeat(60)));
1640
- console.log(import_chalk5.default.dim(" Basic \u2192 Quick prototypes, minimal features"));
1641
- console.log(import_chalk5.default.dim(" Standard \u2192 Production apps, forwardRef, displayName"));
1642
- console.log(import_chalk5.default.dim(" Enterprise\u2192 Mission-critical, memo, useCallback, a11y"));
1643
- console.log("");
1644
- console.log(import_chalk5.default.dim("\u2550".repeat(60)));
1645
- console.log(import_chalk5.default.dim(" Powered by Nikkory"));
1646
- console.log(import_chalk5.default.dim("\u2550".repeat(60)));
1647
- } catch (error) {
1648
- console.error(
1649
- import_chalk5.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`)
1650
- );
1651
- process.exit(1);
1652
- }
1653
- });
1654
-
1655
- // src/commands/doctor/watch.ts
1656
- var import_fs = require("fs");
1657
- var import_promises5 = require("fs/promises");
1658
- var path3 = __toESM(require("path"));
1659
- var import_chalk6 = __toESM(require("chalk"));
1660
- var import_commander7 = require("commander");
1661
- var import_glob5 = require("glob");
1662
- function getHealthEmoji2(score) {
1663
- if (score >= 90) return "\u{1F49A}";
1664
- if (score >= 70) return "\u{1F49B}";
1665
- if (score >= 50) return "\u{1F9E1}";
1666
- return "\u2764\uFE0F";
1667
- }
1668
- function getSeverityColor(severity) {
1669
- switch (severity) {
1670
- case "critical":
1671
- return import_chalk6.default.red.bold;
1672
- case "error":
1673
- return import_chalk6.default.red;
1674
- case "warning":
1675
- return import_chalk6.default.yellow;
1676
- default:
1677
- return import_chalk6.default.blue;
1678
- }
1679
- }
1680
- function formatTime() {
1681
- return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
1682
- }
1683
- function clearScreen() {
1684
- process.stdout.write("\x1Bc");
1685
- }
1686
- function displayHeader() {
1687
- console.log("");
1688
- console.log(
1689
- import_chalk6.default.cyan.bold("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")
1690
- );
1691
- console.log(
1692
- import_chalk6.default.cyan.bold("\u2551") + import_chalk6.default.white.bold(" \u{1F534} NIKKORY VIBE - AI AGENT INSPECTOR (WATCH MODE) ") + import_chalk6.default.cyan.bold("\u2551")
1693
- );
1694
- console.log(
1695
- import_chalk6.default.cyan.bold("\u2551") + import_chalk6.default.dim(" Monitoring code quality in realtime... ") + import_chalk6.default.cyan.bold("\u2551")
1696
- );
1697
- console.log(
1698
- import_chalk6.default.cyan.bold("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")
1699
- );
1700
- console.log("");
1701
- }
1702
- function displayChange(filename, result, prevState, quiet) {
1703
- const time = formatTime();
1704
- const emoji = getHealthEmoji2(result.healthScore);
1705
- const shortName = filename.length > 40 ? `...${filename.slice(-37)}` : filename;
1706
- let scoreChange = "";
1707
- if (prevState) {
1708
- const diff = result.healthScore - prevState.lastScore;
1709
- if (diff > 0) {
1710
- scoreChange = import_chalk6.default.green(` (+${diff})`);
1711
- } else if (diff < 0) {
1712
- scoreChange = import_chalk6.default.red(` (${diff})`);
1713
- }
1714
- }
1715
- console.log(
1716
- `${import_chalk6.default.dim(`[${time}]`)} ${emoji} ${import_chalk6.default.white(shortName)}${import_chalk6.default.bold(
1717
- ` ${result.healthScore}/100`
1718
- )}${scoreChange}${import_chalk6.default.dim(` (${result.issues.length} issues)`)}`
1719
- );
1720
- if (!quiet && result.issues.length > 0) {
1721
- const topIssues = result.issues.slice(0, 3);
1722
- for (const issue of topIssues) {
1723
- const color = getSeverityColor(issue.severity);
1724
- const msg = issue.message.length > 55 ? `${issue.message.slice(0, 52)}...` : issue.message;
1725
- console.log(import_chalk6.default.dim(" ") + color(`L${issue.location.line}: ${msg}`));
1726
- }
1727
- if (result.issues.length > 3) {
1728
- console.log(import_chalk6.default.dim(` ... and ${result.issues.length - 3} more issues`));
1729
- }
1730
- }
1731
- }
1732
- function displaySummary(fileStates) {
1733
- let totalScore = 0;
1734
- let totalIssues = 0;
1735
- let healthyCount = 0;
1736
- for (const state of fileStates.values()) {
1737
- totalScore += state.lastScore;
1738
- totalIssues += state.lastIssueCount;
1739
- if (state.lastScore >= 90) healthyCount++;
1740
- }
1741
- const avgScore = fileStates.size > 0 ? Math.round(totalScore / fileStates.size) : 100;
1742
- const emoji = getHealthEmoji2(avgScore);
1743
- console.log("");
1744
- console.log(import_chalk6.default.cyan("\u2500".repeat(70)));
1745
- console.log(
1746
- ` ${emoji} Average Score: ${import_chalk6.default.bold(avgScore.toString())}/100 \u2502 Files: ${fileStates.size} \u2502 Healthy: ${import_chalk6.default.green(healthyCount.toString())} \u2502 Issues: ${import_chalk6.default.yellow(totalIssues.toString())}`
1747
- );
1748
- console.log(import_chalk6.default.cyan("\u2500".repeat(70)));
1749
- console.log(import_chalk6.default.dim(" Press Ctrl+C to stop watching"));
1750
- console.log("");
1751
- }
1752
- async function startWatch(targetPath, doctor, options) {
1753
- const fileStates = /* @__PURE__ */ new Map();
1754
- const debounceMs = parseInt(options.debounce ?? "300", 10);
1755
- const debounceTimers = /* @__PURE__ */ new Map();
1756
- if (options.clear) clearScreen();
1757
- displayHeader();
1758
- console.log(import_chalk6.default.blue(` \u{1F4C1} Watching: ${targetPath}`));
1759
- console.log(import_chalk6.default.dim(` \u23F1 Debounce: ${debounceMs}ms`));
1760
- console.log("");
1761
- const pattern = "**/*.{tsx,ts,jsx,js}";
1762
- const files = await (0, import_glob5.glob)(`${targetPath}/${pattern}`, {
1763
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.next/**"],
1764
- nodir: true
1765
- });
1766
- console.log(import_chalk6.default.dim(` Found ${files.length} files to watch`));
1767
- console.log("");
1768
- console.log(import_chalk6.default.blue(" \u{1F50D} Running initial scan..."));
1769
- console.log("");
1770
- for (const file of files) {
1771
- try {
1772
- const code = await (0, import_promises5.readFile)(file, "utf-8");
1773
- const result = await doctor.analyze(code, file);
1774
- fileStates.set(file, {
1775
- lastScore: result.healthScore,
1776
- lastIssueCount: result.issues.length,
1777
- lastCheckTime: Date.now()
1778
- });
1779
- if (result.issues.length > 0) {
1780
- displayChange(file, result, void 0, options.quiet ?? false);
1781
- }
1782
- } catch {
1783
- }
1784
- }
1785
- displaySummary(fileStates);
1786
- const watcher = (0, import_fs.watch)(targetPath, { recursive: true }, (_eventType, filename) => {
1787
- if (!filename) return;
1788
- const fullPath = path3.join(targetPath, filename);
1789
- if (!/\.(tsx?|jsx?)$/.test(filename)) return;
1790
- if (/(node_modules|dist|build|\.git|\.next)/.test(filename)) return;
1791
- const existingTimer = debounceTimers.get(fullPath);
1792
- if (existingTimer) {
1793
- clearTimeout(existingTimer);
1794
- }
1795
- const timer = setTimeout(() => {
1796
- debounceTimers.delete(fullPath);
1797
- void (async () => {
1798
- try {
1799
- const code = await (0, import_promises5.readFile)(fullPath, "utf-8");
1800
- const result = await doctor.analyze(code, fullPath);
1801
- const prevState = fileStates.get(fullPath);
1802
- fileStates.set(fullPath, {
1803
- lastScore: result.healthScore,
1804
- lastIssueCount: result.issues.length,
1805
- lastCheckTime: Date.now()
1806
- });
1807
- if (options.clear) {
1808
- clearScreen();
1809
- displayHeader();
1810
- }
1811
- displayChange(fullPath, result, prevState, options.quiet ?? false);
1812
- if (options.bell && result.issues.some((i) => i.severity === "error" || i.severity === "critical")) {
1813
- process.stdout.write("\x07");
1814
- }
1815
- displaySummary(fileStates);
1816
- } catch {
1817
- fileStates.delete(fullPath);
1818
- }
1819
- })();
1820
- }, debounceMs);
1821
- debounceTimers.set(fullPath, timer);
1822
- });
1823
- process.on("SIGINT", () => {
1824
- watcher.close();
1825
- console.log("");
1826
- console.log(import_chalk6.default.cyan(" \u{1F44B} Watch mode stopped"));
1827
- console.log("");
1828
- process.exit(0);
1829
- });
1830
- await new Promise(() => {
1831
- });
1832
- }
1833
- var watchCommand = new import_commander7.Command("watch").description("Watch files and run quality checks in realtime (AI Agent Inspector daemon)").argument("[path]", "Directory to watch", "./src").option("-c, --categories <list>", "Categories to check (comma-separated)").option("-l, --level <level>", "WCAG accessibility level (A, AA, AAA)", "AA").option("-s, --strict", "Enable strict mode (more rules)").option("-d, --debounce <ms>", "Debounce time in milliseconds", "300").option("--clear", "Clear screen on each change").option("--bell", "Ring bell on errors").option("-q, --quiet", "Only show file names and scores").action(async (targetPath, options) => {
1834
- try {
1835
- const categories = options.categories ? options.categories.split(",").map((c) => c.trim()) : void 0;
1836
- const doctor = new CodeDoctor({
1837
- tier: "enterprise",
1838
- autoFix: false,
1839
- strict: options.strict ?? false,
1840
- categories,
1841
- wcagLevel: options.level ?? "AA"
1842
- });
1843
- await startWatch(targetPath, doctor, options);
1844
- } catch (error) {
1845
- console.error(
1846
- import_chalk6.default.red(`\u274C Error: ${error instanceof Error ? error.message : "Unknown error"}`)
1847
- );
1848
- process.exit(1);
1849
- }
1850
- });
1851
-
1852
- // src/commands/doctor/index.ts
1853
- var doctorCommand = new import_commander8.Command("doctor").description("Code Doctor - Diagnose and fix code issues (AI Agent Inspector)").addCommand(scanCommand).addCommand(fixCommand).addCommand(reportCommand).addCommand(upgradeCommand).addCommand(watchCommand);
1854
-
1855
- // src/commands/init.ts
1856
- var fs3 = __toESM(require("fs/promises"));
1857
- var path4 = __toESM(require("path"));
1858
- var import_commander9 = require("commander");
1859
-
1860
- // src/utils/prompts.ts
1861
- var import_inquirer2 = __toESM(require("inquirer"));
1862
- async function promptProjectInit() {
1863
- const answers = await import_inquirer2.default.prompt([
1864
- {
1865
- type: "input",
1866
- name: "projectName",
1867
- message: "Project name:",
1868
- validate: (input) => {
1869
- if (!input) return "Project name is required";
1870
- if (!/^[a-z][a-z0-9-]*$/.test(input)) {
1871
- return "Project name must be lowercase kebab-case (e.g., my-app)";
1872
- }
1873
- return true;
1874
- }
1875
- },
1876
- {
1877
- type: "list",
1878
- name: "framework",
1879
- message: "Frontend framework:",
1880
- choices: [
1881
- { name: "React (Next.js)", value: "react" },
1882
- { name: "Vue (Nuxt)", value: "vue" },
1883
- { name: "Angular", value: "angular" },
1884
- { name: "Svelte (SvelteKit)", value: "svelte" },
1885
- { name: "Solid (SolidStart)", value: "solid" }
1886
- ],
1887
- default: "react"
1888
- },
1889
- {
1890
- type: "list",
1891
- name: "designSystem",
1892
- message: "Default design system:",
1893
- choices: [
1894
- { name: "Material Design 3", value: "material-design" },
1895
- { name: "iOS HIG", value: "ios-hig" },
1896
- { name: "Glassmorphism", value: "glassmorphism" },
1897
- { name: "Custom", value: "custom" }
1898
- ],
1899
- default: "material-design"
1900
- },
1901
- {
1902
- type: "confirm",
1903
- name: "includeBackend",
1904
- message: "Include backend (NestJS)?",
1905
- default: false
1906
- }
1907
- ]);
1908
- return answers;
1909
- }
1910
-
1911
- // src/commands/init.ts
1912
- function generateClaudeMd(config) {
1913
- const tier = config.tier || "standard";
1914
- return `# Claude Code Instructions - ${config.projectName}
1915
-
1916
- > Auto-generated by Nikkory Vibe. AI Agent will automatically follow these quality rules.
1917
-
1918
- ## Project Overview
1919
-
1920
- - **Framework**: ${config.framework}
1921
- - **Design System**: ${config.designSystem}
1922
- - **Styling**: TailwindCSS
1923
- - **Quality Tier**: ${tier}
1924
-
1925
- ---
1926
-
1927
- # \u{1F534} AI AGENT INSPECTOR - MANDATORY QUALITY RULES
1928
-
1929
- **CRITICAL**: These rules are AUTOMATICALLY ENFORCED. AI Agent MUST follow ALL rules below for EVERY code change. No exceptions. No simplification.
1930
-
1931
- ## ESLint Zero-Error Rules (MANDATORY)
1932
-
1933
- ### Import Order (ALWAYS enforce)
1934
-
1935
- \`\`\`typescript
1936
- // \u2705 CORRECT - React first, blank line between groups
1937
- import React, { useState, useCallback, memo, forwardRef } from 'react';
1938
-
1939
- import { cn } from '@/lib/utils';
1940
- import { Button } from '@/components';
1941
-
1942
- // \u274C WRONG - No blank lines, wrong order
1943
- import { Button } from '@/components';
1944
- import React from 'react';
1945
- import { cn } from '@/lib/utils';
1946
- \`\`\`
1947
-
1948
- ### Explicit Return Types (ALWAYS add)
1949
-
1950
- \`\`\`typescript
1951
- // \u2705 CORRECT
1952
- const handleClick = (e: React.MouseEvent<HTMLButtonElement>): void => {
1953
- console.log(e);
1954
- };
1955
-
1956
- // \u274C WRONG - Missing return type
1957
- const handleClick = (e) => {
1958
- console.log(e);
1959
- };
1960
- \`\`\`
1961
-
1962
- ### No Unused Variables (ALWAYS prefix with _)
1963
-
1964
- \`\`\`typescript
1965
- // \u2705 CORRECT
1966
- const { name, age: _age, email } = user; // _age unused but valid
1967
-
1968
- // \u274C WRONG
1969
- const { name, age, email } = user; // age unused = ERROR
1970
- \`\`\`
1971
-
1972
- ### No \`any\` Type (ALWAYS use \`unknown\`)
1973
-
1974
- \`\`\`typescript
1975
- // \u2705 CORRECT
1976
- const handleData = (data: unknown): void => {};
1977
-
1978
- // \u274C WRONG
1979
- const handleData = (data: any): void => {};
1980
- \`\`\`
1981
-
1982
- ### No Non-Null Assertion (ALWAYS use optional chaining)
1983
-
1984
- \`\`\`typescript
1985
- // \u2705 CORRECT
1986
- ref.current?.focus();
1987
-
1988
- // \u274C WRONG
1989
- ref.current!.focus();
1990
- \`\`\`
1991
-
1992
- ## TypeScript Strict Mode (MANDATORY)
1993
-
1994
- | Pattern | Required | Example |
1995
- |---------|----------|---------|
1996
- | Explicit return types | YES | \`(): void\`, \`(): string\` |
1997
- | No implicit any | YES | Always type parameters |
1998
- | Strict null checks | YES | Use \`?.\` and \`??\` |
1999
- | Interface over type | YES | For object shapes |
2000
-
2001
- ## React Component Patterns
2002
-
2003
- ### Basic Tier
2004
-
2005
- \`\`\`typescript
2006
- import React from 'react';
2007
-
2008
- interface ComponentProps {
2009
- children?: React.ReactNode;
2010
- className?: string;
2011
- }
2012
-
2013
- export const Component: React.FC<ComponentProps> = ({
2014
- children,
2015
- className,
2016
- }) => {
2017
- return <div className={className}>{children}</div>;
2018
- };
2019
- \`\`\`
2020
-
2021
- ### Standard Tier (forwardRef + displayName)
2022
-
2023
- \`\`\`typescript
2024
- import React, { forwardRef } from 'react';
2025
-
2026
- interface ComponentProps {
2027
- children?: React.ReactNode;
2028
- variant?: 'primary' | 'secondary';
2029
- }
2030
-
2031
- export const Component = forwardRef<HTMLDivElement, ComponentProps>(
2032
- ({ children, variant = 'primary', ...props }, ref) => {
2033
- return <div ref={ref} {...props}>{children}</div>;
2034
- }
2035
- );
2036
-
2037
- Component.displayName = 'Component'; // REQUIRED!
2038
- \`\`\`
2039
-
2040
- ### Enterprise Tier (memo + forwardRef + displayName)
2041
-
2042
- \`\`\`typescript
2043
- import React, { memo, forwardRef, useCallback } from 'react';
2044
-
2045
- interface ComponentProps {
2046
- children?: React.ReactNode;
2047
- analyticsEvent?: string;
2048
- onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
2049
- }
2050
-
2051
- export const Component = memo(
2052
- forwardRef<HTMLDivElement, ComponentProps>(
2053
- ({ children, analyticsEvent, onClick, ...props }, ref) => {
2054
- const handleClick = useCallback(
2055
- (e: React.MouseEvent<HTMLDivElement>): void => {
2056
- if (analyticsEvent && typeof window !== 'undefined') {
2057
- (window as unknown as { dataLayer?: unknown[] }).dataLayer?.push({
2058
- event: analyticsEvent,
2059
- });
2060
- }
2061
- onClick?.(e);
2062
- },
2063
- [analyticsEvent, onClick]
2064
- );
2065
-
2066
- return <div ref={ref} onClick={handleClick} {...props}>{children}</div>;
2067
- }
2068
- )
2069
- );
2070
-
2071
- Component.displayName = 'Component'; // REQUIRED!
2072
- \`\`\`
2073
-
2074
- ## Debugging Rules (NEVER SKIP)
2075
-
2076
- When debugging or fixing issues:
2077
-
2078
- 1. **NEVER simplify code** - Fix the actual issue, don't remove features
2079
- 2. **NEVER remove types** - Keep all TypeScript annotations
2080
- 3. **NEVER use \`any\`** - Use \`unknown\` if type is unclear
2081
- 4. **ALWAYS preserve patterns** - forwardRef, memo, displayName
2082
- 5. **ALWAYS run lint check** - \`pnpm lint\` before considering done
2083
- 6. **ALWAYS check types** - \`pnpm type-check\` before considering done
2084
-
2085
- ## Pre-Commit Checklist (AUTO-ENFORCE)
2086
-
2087
- Before ANY commit, AI Agent MUST verify:
2088
-
2089
- - [ ] All imports have correct order with blank lines
2090
- - [ ] All functions have explicit return types
2091
- - [ ] No unused variables (prefix with _ if intentionally unused)
2092
- - [ ] No \`any\` types (use \`unknown\` instead)
2093
- - [ ] No non-null assertions (use \`?.\` instead)
2094
- - [ ] forwardRef components have displayName
2095
- - [ ] Enterprise components use memo()
2096
- - [ ] useEffect cleanup has \`: void\` return type
2097
- - [ ] Event handlers have proper React event types
2098
-
2099
- ## Quick Fix Reference
2100
-
2101
- | Error | Quick Fix |
2102
- |-------|-----------|
2103
- | \`import/order\` | Add blank line between import groups |
2104
- | \`explicit-function-return-type\` | Add \`: void\`, \`: string\`, etc. |
2105
- | \`no-unused-vars\` | Prefix with \`_\` |
2106
- | \`no-explicit-any\` | Use \`unknown\` |
2107
- | \`no-non-null-assertion\` | Use \`?.\` optional chaining |
2108
- | \`TS2304: Cannot find name\` | Add missing import |
2109
- | \`TS2322: Type not assignable\` | Fix type or cast properly |
2110
- | \`TS6133: Unused declaration\` | Remove or prefix with \`_\` |
2111
-
2112
- ---
2113
-
2114
- **Powered by Nikkory Vibe**
2115
- `;
2116
- }
2117
- var initCommand = new import_commander9.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(
2118
- async (projectName, options) => {
2119
- try {
2120
- logger.header("\u{1F3A8} Nikkory Vibe - Project Initialization");
2121
- let config;
2122
- if (!projectName) {
2123
- const promptConfig = await promptProjectInit();
2124
- projectName = promptConfig.projectName;
2125
- config = {
2126
- ...promptConfig,
2127
- tier: options.tier ?? "standard"
2128
- };
2129
- } else {
2130
- config = {
2131
- projectName,
2132
- framework: options.framework ?? "react",
2133
- designSystem: options.design ?? "material-design",
2134
- tier: options.tier ?? "standard",
2135
- includeBackend: options.backend ?? false
2136
- };
2137
- }
2138
- const projectPath = path4.join(process.cwd(), projectName);
2139
- try {
2140
- await fs3.access(projectPath);
2141
- logger.error(`Directory "${projectName}" already exists`);
2142
- process.exit(1);
2143
- } catch {
2144
- }
2145
- logger.newline();
2146
- logger.info(`Creating project: ${projectName}`);
2147
- logger.info(`Framework: ${config.framework}`);
2148
- logger.info(`Design System: ${config.designSystem}`);
2149
- logger.info(`Quality Tier: ${config.tier}`);
2150
- if (config.includeBackend) {
2151
- logger.info(`Backend: NestJS`);
2152
- }
2153
- logger.newline();
2154
- logger.startSpinner("Creating project structure...");
2155
- await fs3.mkdir(projectPath, { recursive: true });
2156
- await createProjectStructure(projectPath, config);
2157
- logger.stopSpinnerSuccess("Project structure created");
2158
- logger.startSpinner("Creating package.json...");
2159
- await createPackageJson(projectPath, config);
2160
- logger.stopSpinnerSuccess("package.json created");
2161
- logger.startSpinner("Creating configuration files...");
2162
- await createConfigFiles(projectPath, config);
2163
- logger.stopSpinnerSuccess("Configuration files created");
2164
- if (options.claude !== false) {
2165
- logger.startSpinner("Creating CLAUDE.md (AI Agent Inspector)...");
2166
- await createClaudeMd(projectPath, config);
2167
- logger.stopSpinnerSuccess("CLAUDE.md created - AI Agent Inspector enabled");
2168
- }
2169
- logger.startSpinner("Creating README.md...");
2170
- await createReadme(projectPath, config);
2171
- logger.stopSpinnerSuccess("README.md created");
2172
- logger.newline();
2173
- logger.box(
2174
- `\u2728 Project "${projectName}" created successfully!
2175
-
2176
- Location: ${projectPath}
2177
- Framework: ${config.framework}
2178
- Design: ${config.designSystem}
2179
- Tier: ${config.tier}
2180
- AI Inspector: ${options.claude !== false ? "Enabled" : "Disabled"}`,
2181
- { title: "Success", borderColor: "green" }
2182
- );
2183
- if (options.claude !== false) {
2184
- logger.newline();
2185
- logger.info("\u{1F534} AI Agent Inspector is enabled!");
2186
- logger.info(" Claude Code will automatically enforce quality rules.");
2187
- logger.info(" No manual commands needed - just code!");
2188
- }
2189
- logger.newline();
2190
- logger.info("Next steps:");
2191
- logger.code(` cd ${projectName}`);
2192
- if (options.install ?? true) {
2193
- logger.code(` pnpm install`);
2194
- }
2195
- logger.code(` pnpm dev`);
2196
- logger.newline();
2197
- logger.info("Generate your first component:");
2198
- logger.code(` vibe smart button --style glassmorphism --tier ${config.tier}`);
2199
- logger.newline();
2200
- } catch (error) {
2201
- logger.stopSpinner();
2202
- logger.error("Project initialization failed");
2203
- if (error instanceof Error) {
2204
- logger.debug(error.stack || error.message);
2205
- }
2206
- process.exit(1);
2207
- }
2208
- }
2209
- );
2210
- async function createProjectStructure(projectPath, config) {
2211
- const dirs = ["src/components", "src/pages", "src/styles", "src/utils", "public", ".claude"];
2212
- if (config.includeBackend) {
2213
- dirs.push("api/src/modules", "api/src/common", "api/prisma");
2214
- }
2215
- for (const dir of dirs) {
2216
- await fs3.mkdir(path4.join(projectPath, dir), { recursive: true });
2217
- }
2218
- }
2219
- async function createClaudeMd(projectPath, config) {
2220
- const content = generateClaudeMd(config);
2221
- await fs3.writeFile(path4.join(projectPath, "CLAUDE.md"), content, "utf-8");
2222
- }
2223
- async function createPackageJson(projectPath, config) {
2224
- const packageJson = {
2225
- name: config.projectName,
2226
- version: "0.1.0",
2227
- private: true,
2228
- scripts: {
2229
- dev: config.framework === "react" ? "next dev" : "vite dev",
2230
- build: config.framework === "react" ? "next build" : "vite build",
2231
- start: config.framework === "react" ? "next start" : "vite preview",
2232
- lint: "eslint . --ext .ts,.tsx",
2233
- "type-check": "tsc --noEmit"
2234
- },
2235
- dependencies: getFrameworkDependencies(config.framework),
2236
- devDependencies: {
2237
- "@types/node": "^20.0.0",
2238
- "@types/react": "^18.0.0",
2239
- "@types/react-dom": "^18.0.0",
2240
- typescript: "^5.0.0",
2241
- eslint: "^8.0.0",
2242
- "@nikkory/vibe-cli": "^1.0.0"
2243
- }
2244
- };
2245
- await fs3.writeFile(
2246
- path4.join(projectPath, "package.json"),
2247
- JSON.stringify(packageJson, null, 2),
2248
- "utf-8"
2249
- );
2250
- }
2251
- function getFrameworkDependencies(framework) {
2252
- const deps = {
2253
- react: {
2254
- react: "^18.2.0",
2255
- "react-dom": "^18.2.0",
2256
- next: "^14.0.0",
2257
- tailwindcss: "^3.4.0"
2258
- },
2259
- vue: {
2260
- vue: "^3.3.0",
2261
- nuxt: "^3.8.0",
2262
- tailwindcss: "^3.4.0"
2263
- },
2264
- angular: {
2265
- "@angular/core": "^17.0.0",
2266
- "@angular/common": "^17.0.0",
2267
- "@angular/platform-browser": "^17.0.0"
2268
- },
2269
- svelte: {
2270
- svelte: "^4.0.0",
2271
- "@sveltejs/kit": "^2.0.0",
2272
- tailwindcss: "^3.4.0"
2273
- },
2274
- solid: {
2275
- "solid-js": "^1.8.0",
2276
- "solid-start": "^0.4.0",
2277
- tailwindcss: "^3.4.0"
2278
- }
2279
- };
2280
- return deps[framework] ?? deps["react"] ?? {};
2281
- }
2282
- async function createConfigFiles(projectPath, _config) {
2283
- const tsConfig = {
2284
- compilerOptions: {
2285
- target: "ES2020",
2286
- lib: ["ES2020", "DOM", "DOM.Iterable"],
2287
- jsx: "preserve",
2288
- module: "ESNext",
2289
- moduleResolution: "bundler",
2290
- resolveJsonModule: true,
2291
- allowJs: true,
2292
- strict: true,
2293
- noImplicitAny: true,
2294
- strictNullChecks: true,
2295
- esModuleInterop: true,
2296
- skipLibCheck: true,
2297
- forceConsistentCasingInFileNames: true,
2298
- incremental: true,
2299
- paths: {
2300
- "@/*": ["./src/*"]
2301
- }
2302
- },
2303
- include: ["src/**/*"],
2304
- exclude: ["node_modules"]
2305
- };
2306
- await fs3.writeFile(
2307
- path4.join(projectPath, "tsconfig.json"),
2308
- JSON.stringify(tsConfig, null, 2),
2309
- "utf-8"
2310
- );
2311
- const gitignore = `# Dependencies
2312
- node_modules
2313
- .pnpm-store
2314
-
2315
- # Build output
2316
- dist
2317
- .next
2318
- out
2319
- build
2320
-
2321
- # Environment
2322
- .env
2323
- .env.local
2324
- .env.*.local
2325
-
2326
- # IDE
2327
- .vscode
2328
- .idea
2329
- *.swp
2330
- *.swo
2331
-
2332
- # OS
2333
- .DS_Store
2334
- Thumbs.db
2335
-
2336
- # Logs
2337
- *.log
2338
- npm-debug.log*
2339
- yarn-debug.log*
2340
- yarn-error.log*
2341
- `;
2342
- await fs3.writeFile(path4.join(projectPath, ".gitignore"), gitignore, "utf-8");
2343
- }
2344
- async function createReadme(projectPath, config) {
2345
- const readme = `# ${config.projectName}
2346
-
2347
- Generated with **Nikkory Vibe** \u2728
2348
-
2349
- ## Tech Stack
2350
-
2351
- - **Framework**: ${config.framework}
2352
- - **Design System**: ${config.designSystem}
2353
- - **Quality Tier**: ${config.tier}
2354
- - **Styling**: TailwindCSS
2355
- - **TypeScript**: 5.0+
2356
-
2357
- ## AI Agent Inspector
2358
-
2359
- This project includes **AI Agent Inspector** via \`CLAUDE.md\`.
2360
- When using Claude Code, AI will automatically:
2361
-
2362
- - \u2705 Follow ESLint zero-error rules
2363
- - \u2705 Use TypeScript strict mode patterns
2364
- - \u2705 Apply correct React component patterns for ${config.tier} tier
2365
- - \u2705 Never simplify code when debugging
2366
- - \u2705 Run lint/type checks before completing tasks
2367
-
2368
- **No manual commands needed - just code!**
2369
-
2370
- ## Getting Started
2371
-
2372
- \`\`\`bash
2373
- # Install dependencies
2374
- pnpm install
2375
-
2376
- # Run development server
2377
- pnpm dev
2378
-
2379
- # Build for production
2380
- pnpm build
2381
- \`\`\`
2382
-
2383
- ## Generate Components
2384
-
2385
- \`\`\`bash
2386
- # Generate a component with Smart Generator
2387
- vibe smart button --style glassmorphism --tier ${config.tier}
2388
-
2389
- # List all 50 design styles
2390
- vibe smart --list-styles
2391
-
2392
- # Generate all 3 tiers at once
2393
- vibe smart card --style brutalism --all-tiers
2394
-
2395
- # Preview without writing
2396
- vibe smart input --style neumorphism --dry-run
2397
- \`\`\`
2398
-
2399
- ## Code Quality
2400
-
2401
- \`\`\`bash
2402
- # Run ESLint
2403
- pnpm lint
2404
-
2405
- # Run TypeScript check
2406
- pnpm type-check
2407
-
2408
- # Run Code Doctor
2409
- vibe doctor scan ./src
2410
- \`\`\`
2411
-
2412
- ## Project Structure
2413
-
2414
- \`\`\`
2415
- ${config.projectName}/
2416
- \u251C\u2500\u2500 src/
2417
- \u2502 \u251C\u2500\u2500 components/ # React components
2418
- \u2502 \u251C\u2500\u2500 pages/ # Page components
2419
- \u2502 \u251C\u2500\u2500 styles/ # Global styles
2420
- \u2502 \u2514\u2500\u2500 utils/ # Utilities
2421
- \u251C\u2500\u2500 public/ # Static assets
2422
- \u251C\u2500\u2500 CLAUDE.md # AI Agent Inspector rules
2423
- \u2514\u2500\u2500 package.json
2424
- \`\`\`
2425
-
2426
- ## Learn More
2427
-
2428
- - [Nikkory Vibe Documentation](https://vibe.nikkory.com/docs)
2429
- - [Design Systems](https://vibe.nikkory.com/docs/design-systems)
2430
- - [CLI Reference](https://vibe.nikkory.com/docs/cli)
2431
-
2432
- ---
2433
-
2434
- Powered by Nikkory
2435
- `;
2436
- await fs3.writeFile(path4.join(projectPath, "README.md"), readme, "utf-8");
2437
- }
2438
-
2439
- // src/commands/list.ts
2440
- var import_commander10 = require("commander");
2441
- var listCommand = new import_commander10.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) => {
2442
- try {
2443
- if (options.json) {
2444
- const data = getAllData();
2445
- console.log(JSON.stringify(data, null, 2));
2446
- return;
2447
- }
2448
- logger.header("\u{1F3A8} Nikkory Vibe - Available Options");
2449
- switch (category) {
2450
- case "templates":
2451
- listTemplates();
2452
- break;
2453
- case "designs":
2454
- case "design-systems":
2455
- listDesignSystems();
2456
- break;
2457
- case "tiers":
2458
- listTiers();
2459
- break;
2460
- case "frameworks":
2461
- listFrameworks();
2462
- break;
2463
- case "all":
2464
- default:
2465
- listTemplates();
2466
- logger.newline();
2467
- listDesignSystems();
2468
- logger.newline();
2469
- listTiers();
2470
- logger.newline();
2471
- listFrameworks();
2472
- break;
2473
- }
2474
- logger.newline();
2475
- logger.info("Generate a component:");
2476
- logger.code(" vibe generate component MyButton --design material-design");
2477
- logger.newline();
2478
- } catch (error) {
2479
- logger.error("Failed to list options");
2480
- if (error instanceof Error) {
2481
- logger.debug(error.stack || error.message);
2482
- }
2483
- process.exit(1);
2484
- }
2485
- });
2486
- function listTemplates() {
2487
- logger.newline();
2488
- logger.info("\u{1F4E6} Available Templates:");
2489
- logger.separator();
2490
- const templates = [
2491
- { name: "Button", value: "button", description: "Interactive button components" },
2492
- { name: "Card", value: "card", description: "Content container cards" },
2493
- { name: "Input", value: "input", description: "Form input fields" },
2494
- { name: "Modal", value: "modal", description: "Dialog/modal overlays" },
2495
- { name: "Table", value: "table", description: "Data tables" },
2496
- { name: "Form", value: "form", description: "Form layouts" },
2497
- { name: "Navigation", value: "navigation", description: "Nav bars and menus" },
2498
- { name: "Hero", value: "hero", description: "Hero sections" },
2499
- { name: "Feature", value: "feature", description: "Feature showcases" },
2500
- { name: "Pricing", value: "pricing", description: "Pricing tables" }
2501
- ];
2502
- logger.table(
2503
- templates.map((t) => ({
2504
- Template: t.name,
2505
- ID: t.value,
2506
- Description: t.description
2507
- }))
2508
- );
2509
- }
2510
- function listDesignSystems() {
2511
- logger.newline();
2512
- logger.info("\u{1F3A8} Available Design Systems:");
2513
- logger.separator();
2514
- const designs = [
2515
- {
2516
- name: "Material Design 3",
2517
- value: "material-design",
2518
- category: "Modern"
2519
- },
2520
- {
2521
- name: "iOS Human Interface Guidelines",
2522
- value: "ios-hig",
2523
- category: "Mobile"
2524
- },
2525
- {
2526
- name: "Glassmorphism",
2527
- value: "glassmorphism",
2528
- category: "Modern"
2529
- },
2530
- {
2531
- name: "Neumorphism",
2532
- value: "neumorphism",
2533
- category: "Modern"
2534
- },
2535
- {
2536
- name: "Minimalism",
2537
- value: "minimalism",
2538
- category: "Clean"
2539
- },
2540
- {
2541
- name: "Brutalism",
2542
- value: "brutalism",
2543
- category: "Bold"
2544
- },
2545
- {
2546
- name: "Cyberpunk",
2547
- value: "cyberpunk",
2548
- category: "Futuristic"
2549
- },
2550
- {
2551
- name: "Retro",
2552
- value: "retro",
2553
- category: "Vintage"
2554
- }
2555
- ];
2556
- logger.table(
2557
- designs.map((d) => ({
2558
- "Design System": d.name,
2559
- ID: d.value,
2560
- Category: d.category
2561
- }))
2562
- );
2563
- }
2564
- function listTiers() {
2565
- logger.newline();
2566
- logger.info("\u2B50 Quality Tiers:");
2567
- logger.separator();
2568
- const tiers = [
2569
- {
2570
- tier: "Basic",
2571
- id: "basic",
2572
- description: "Prototype/demo quality",
2573
- features: "2-3 variants, basic styling",
2574
- loc: "~60 LOC"
2575
- },
2576
- {
2577
- tier: "Standard",
2578
- id: "standard",
2579
- description: "Production-ready",
2580
- features: "5+ variants, accessibility, dark mode",
2581
- loc: "~200 LOC"
2582
- },
2583
- {
2584
- tier: "Enterprise",
2585
- id: "enterprise",
2586
- description: "Mission-critical",
2587
- features: "All features + analytics + advanced animations",
2588
- loc: "~350 LOC"
2589
- }
2590
- ];
2591
- logger.table(
2592
- tiers.map((t) => ({
2593
- Tier: t.tier,
2594
- ID: t.id,
2595
- Description: t.description,
2596
- Features: t.features,
2597
- Size: t.loc
2598
- }))
2599
- );
2600
- }
2601
- function listFrameworks() {
2602
- logger.newline();
2603
- logger.info("\u{1F680} Supported Frameworks:");
2604
- logger.separator();
2605
- const frameworks = [
2606
- { name: "React", value: "react", extension: ".tsx" },
2607
- { name: "Vue", value: "vue", extension: ".vue" },
2608
- { name: "Angular", value: "angular", extension: ".component.ts" },
2609
- { name: "Svelte", value: "svelte", extension: ".svelte" },
2610
- { name: "Solid", value: "solid", extension: ".tsx" }
2611
- ];
2612
- logger.table(
2613
- frameworks.map((f) => ({
2614
- Framework: f.name,
2615
- ID: f.value,
2616
- Extension: f.extension
2617
- }))
2618
- );
2619
- }
2620
- function getAllData() {
2621
- return {
2622
- templates: [
2623
- "button",
2624
- "card",
2625
- "input",
2626
- "modal",
2627
- "table",
2628
- "form",
2629
- "navigation",
2630
- "hero",
2631
- "feature",
2632
- "pricing"
2633
- ],
2634
- designSystems: [
2635
- "material-design",
2636
- "ios-hig",
2637
- "glassmorphism",
2638
- "neumorphism",
2639
- "minimalism",
2640
- "brutalism",
2641
- "cyberpunk",
2642
- "retro"
2643
- ],
2644
- tiers: ["basic", "standard", "enterprise"],
2645
- frameworks: ["react", "vue", "angular", "svelte", "solid"]
2646
- };
2647
- }
2648
-
2649
- // src/commands/matrix-generate.ts
2650
- var import_commander11 = require("commander");
2651
- var import_chalk7 = __toESM(require("chalk"));
2652
- var import_ora2 = __toESM(require("ora"));
2653
- var import_vibe_engine = require("@nikkory/vibe-engine");
2654
-
2655
- // src/generators/component-generator.ts
2656
- var import_promises6 = require("fs/promises");
2657
- var import_path = require("path");
2658
- var ComponentGenerator = class {
2659
- /**
2660
- * Write generated code to file
2661
- *
2662
- * @param filePath - Absolute file path
2663
- * @param code - Generated code content
2664
- * @returns Promise<void>
2665
- */
2666
- async writeToFile(filePath, code) {
2667
- await (0, import_promises6.mkdir)((0, import_path.dirname)(filePath), { recursive: true });
2668
- await (0, import_promises6.writeFile)(filePath, code, "utf-8");
2669
- }
2670
- /**
2671
- * Format code with syntax highlighting (for terminal output)
2672
- *
2673
- * @param code - Code to format
2674
- * @returns Formatted code string
2675
- *
2676
- * Note: Simple pass-through for now. Could use chalk for syntax highlighting.
2677
- */
2678
- formatCode(code) {
2679
- return code;
2680
- }
2681
- };
2682
-
2683
- // src/commands/matrix-generate.ts
2684
- var matrixGenerateCommand = new import_commander11.Command("add").alias("gen").alias("generate").description("Add/Generate UI component using Matrix system (24 factors, 12 design systems, 3 tiers)").argument("<component>", "Component ID (e.g., button, input, card)").option(
2685
- "-s, --design-system <system>",
2686
- "Design system (material-design, ios-hig, glassmorphism, neumorphism, brutalism, minimalism, fluent, carbon, ant-design, chakra, atlassian, blueprint)",
2687
- "material-design"
2688
- ).option(
2689
- "-t, --tier <tier>",
2690
- "Quality tier (basic, standard, enterprise)",
2691
- "standard"
2692
- ).option(
2693
- "-f, --factor-overrides <json>",
2694
- `Factor overrides as JSON (e.g., '{"4":"xl","17":"lg"}')`
2695
- ).option(
2696
- "-o, --output <path>",
2697
- "Output file path"
2698
- ).action(async (componentId, options) => {
2699
- const spinner = (0, import_ora2.default)("Generating component...").start();
2700
- try {
2701
- const resolver = new import_vibe_engine.MatrixResolver();
2702
- const templateEngine = new import_vibe_engine.TemplateEngine();
2703
- let factor24Config;
2704
- if (options.factorOverrides) {
2705
- try {
2706
- factor24Config = JSON.parse(options.factorOverrides);
2707
- } catch (parseError) {
2708
- spinner.fail(import_chalk7.default.red("Invalid JSON in --factor-overrides"));
2709
- if (parseError instanceof Error) {
2710
- console.error(import_chalk7.default.gray(parseError.message));
2711
- }
2712
- process.exit(1);
2713
- }
2714
- }
2715
- const input = {
2716
- componentId,
2717
- designSystem: options.designSystem,
2718
- tier: options.tier,
2719
- factor24Config
2720
- };
2721
- const config = resolver.resolve(input);
2722
- const code = templateEngine.generate(config);
2723
- const generator = new ComponentGenerator();
2724
- if (options.output) {
2725
- await generator.writeToFile(options.output, code);
2726
- spinner.succeed(import_chalk7.default.green(`Generated ${config.componentName} \u2192 ${options.output}`));
2727
- } else {
2728
- spinner.succeed(import_chalk7.default.green(`Generated ${config.componentName}`));
2729
- console.log(code);
2730
- }
2731
- console.log(import_chalk7.default.cyan("\nComponent Info:"));
2732
- console.log(` ${import_chalk7.default.gray("Name:")} ${config.componentName}`);
2733
- console.log(` ${import_chalk7.default.gray("Tier:")} ${config.tier}`);
2734
- console.log(` ${import_chalk7.default.gray("Design System:")} ${config.designSystem}`);
2735
- console.log(` ${import_chalk7.default.gray("HTML Element:")} <${config.elementType}>`);
2736
- console.log(` ${import_chalk7.default.gray("Class Names:")} ${config.classNames.join(" ")}`);
2737
- console.log("");
2738
- } catch (error) {
2739
- spinner.fail(import_chalk7.default.red(`Error: ${error.message}`));
2740
- process.exit(1);
2741
- }
2742
- });
2743
-
2744
- // src/config/schema.ts
2745
- function isNikkoryVibeConfig(value) {
2746
- if (typeof value !== "object" || value === null) {
2747
- return false;
2748
- }
2749
- const config = value;
2750
- if (config["defaultScope"] !== void 0 && typeof config["defaultScope"] !== "string") {
2751
- return false;
2752
- }
2753
- if (config["defaultTier"] !== void 0 && !["basic", "standard", "enterprise"].includes(config["defaultTier"])) {
2754
- return false;
2755
- }
2756
- if (config["defaultDesignSystem"] !== void 0 && typeof config["defaultDesignSystem"] !== "string") {
2757
- return false;
2758
- }
2759
- return true;
2760
- }
2761
- var DEFAULT_CONFIG = {
2762
- defaultScope: "react",
2763
- defaultTier: "standard",
2764
- defaultDesignSystem: "material-design",
2765
- outputStructure: {
2766
- atoms: "./src/components/atoms",
2767
- components: "./src/components",
2768
- sections: "./src/sections",
2769
- pages: "./src/pages",
2770
- layouts: "./src/layouts",
2771
- templates: "./src/templates"
2772
- },
2773
- frameworks: {
2774
- react: {
2775
- typescript: true,
2776
- styleLibrary: "tailwind"
2777
- },
2778
- vue: {
2779
- typescript: true,
2780
- styleLibrary: "tailwind"
2781
- },
2782
- svelte: {
2783
- typescript: true,
2784
- styleLibrary: "tailwind"
2785
- },
2786
- angular: {
2787
- typescript: true,
2788
- styleLibrary: "tailwind"
2789
- },
2790
- pattern: {
2791
- typescript: true
2792
- },
2793
- engine: {
2794
- typescript: true
2795
- }
2796
- },
2797
- forceOverwrite: false,
2798
- verbose: false,
2799
- dryRun: false
2800
- };
2801
-
2802
- // src/config/loader.ts
2803
- var import_node_fs = require("fs");
2804
- var import_node_path = require("path");
2805
- var import_node_url = require("url");
2806
- var CONFIG_FILE_NAMES = [
2807
- "nikkory-vibe.config.ts",
2808
- "nikkory-vibe.config.mts",
2809
- "nikkory-vibe.config.js",
2810
- "nikkory-vibe.config.mjs",
2811
- "nikkory-vibe.config.cjs"
2812
- ];
2813
- function findConfigFile(searchDir = process.cwd()) {
2814
- for (const fileName of CONFIG_FILE_NAMES) {
2815
- const filePath = (0, import_node_path.resolve)(searchDir, fileName);
2816
- if ((0, import_node_fs.existsSync)(filePath)) {
2817
- return filePath;
2818
- }
2819
- }
2820
- return void 0;
2821
- }
2822
- async function loadConfigFile(configPath) {
2823
- try {
2824
- const fileUrl = (0, import_node_url.pathToFileURL)(configPath).href;
2825
- const module2 = await import(fileUrl);
2826
- const config = "default" in module2 ? module2.default : module2;
2827
- if (!isNikkoryVibeConfig(config)) {
2828
- throw new Error(`Invalid config file: ${configPath}`);
2829
- }
2830
- return config;
2831
- } catch (error) {
2832
- throw new Error(
2833
- `Failed to load config file: ${configPath}
2834
- ${error instanceof Error ? error.message : String(error)}`
2835
- );
2836
- }
2837
- }
2838
- async function loadConfig(options) {
2839
- const { configPath, searchDir = process.cwd() } = options || {};
2840
- if (configPath) {
2841
- const resolvedPath = (0, import_node_path.resolve)(searchDir, configPath);
2842
- if (!(0, import_node_fs.existsSync)(resolvedPath)) {
2843
- throw new Error(`Config file not found: ${resolvedPath}`);
2844
- }
2845
- const userConfig = await loadConfigFile(resolvedPath);
2846
- return mergeConfig(DEFAULT_CONFIG, userConfig);
2847
- }
2848
- const discoveredPath = findConfigFile(searchDir);
2849
- if (discoveredPath) {
2850
- const userConfig = await loadConfigFile(discoveredPath);
2851
- return mergeConfig(DEFAULT_CONFIG, userConfig);
2852
- }
2853
- return DEFAULT_CONFIG;
2854
- }
2855
- function mergeConfig(defaultConfig, userConfig) {
2856
- const merged = { ...defaultConfig };
2857
- if (userConfig.defaultScope !== void 0) {
2858
- merged.defaultScope = userConfig.defaultScope;
2859
- }
2860
- if (userConfig.defaultTier !== void 0) {
2861
- merged.defaultTier = userConfig.defaultTier;
2862
- }
2863
- if (userConfig.defaultDesignSystem !== void 0) {
2864
- merged.defaultDesignSystem = userConfig.defaultDesignSystem;
2865
- }
2866
- if (userConfig.forceOverwrite !== void 0) {
2867
- merged.forceOverwrite = userConfig.forceOverwrite;
2868
- }
2869
- if (userConfig.verbose !== void 0) {
2870
- merged.verbose = userConfig.verbose;
2871
- }
2872
- if (userConfig.dryRun !== void 0) {
2873
- merged.dryRun = userConfig.dryRun;
2874
- }
2875
- if (userConfig.outputStructure) {
2876
- merged.outputStructure = {
2877
- ...defaultConfig.outputStructure,
2878
- ...userConfig.outputStructure
2879
- };
2880
- }
2881
- if (userConfig.frameworks) {
2882
- merged.frameworks = { ...defaultConfig.frameworks };
2883
- for (const [scopeKey, frameworkConfig] of Object.entries(userConfig.frameworks)) {
2884
- const scope = scopeKey;
2885
- if (merged.frameworks) {
2886
- merged.frameworks[scope] = {
2887
- ...defaultConfig.frameworks?.[scope],
2888
- ...frameworkConfig
2889
- };
2890
- }
2891
- }
2892
- }
2893
- return merged;
2894
- }
2895
-
2896
- // src/scopes/react.ts
2897
- var import_vibe_engine2 = require("@nikkory/vibe-engine");
2898
- var import_chalk8 = __toESM(require("chalk"));
2899
- var ReactScopeHandler = class {
2900
- scope = "react";
2901
- available = true;
2902
- /**
2903
- * Generate React component/section/page
2904
- *
2905
- * Routes to legacy generate command (which has ComponentGenerator, SectionGenerator, PageGenerator).
2906
- * This is a temporary delegation until generators are moved to @nikkory/vibe-react.
2907
- *
2908
- * @param granularity - Component size
2909
- * @param target - Target name (e.g., "button", "hero-section")
2910
- * @param options - CLI options
2911
- * @returns Promise<void>
2912
- */
2913
- async generate(granularity, target, options) {
2914
- logger.header("\u{1F3A8} Nikkory Vibe - React Generator");
2915
- logger.info(`Generating ${granularity}: ${import_chalk8.default.cyan(target)}`);
2916
- logger.info(`Tier: ${options.tier || "standard"}`);
2917
- logger.info(`Design: ${options.designSystem || "material-design"}`);
2918
- logger.newline();
2919
- logger.warn("Using legacy generation (generators will move to @nikkory/vibe-react in future)");
2920
- logger.info("Please use the legacy command for now:");
2921
- const granularityToType = {
2922
- atom: "component",
2923
- component: "component",
2924
- section: "section",
2925
- page: "page",
2926
- layout: "page",
2927
- template: "page"
2928
- };
2929
- const legacyType = granularityToType[granularity];
2930
- logger.code(` vibe generate ${legacyType} ${target} --tier=${options.tier || "standard"}`);
2931
- logger.newline();
2932
- throw new Error("React generation will be implemented when generators move to @nikkory/vibe-react");
2933
- }
2934
- /**
2935
- * List available React components
2936
- *
2937
- * Shows components filtered by granularity or all if not specified.
2938
- * Groups by category and shows metadata (design systems, tiers, new/popular badges).
2939
- *
2940
- * @param granularity - Optional filter by granularity
2941
- * @returns Promise<void>
2942
- */
2943
- async list(granularity) {
2944
- logger.header("\u{1F4E6} React Components");
2945
- logger.newline();
2946
- const components = import_vibe_engine2.ALL_COMPONENTS;
2947
- if (granularity) {
2948
- logger.info(`Showing ${import_chalk8.default.cyan(granularity)} components:`);
2949
- logger.newline();
2950
- }
2951
- logger.info(`Total: ${import_chalk8.default.cyan(String(components.length))} components`);
2952
- logger.newline();
2953
- const stable = (0, import_vibe_engine2.getStableComponents)();
2954
- logger.info(import_chalk8.default.green("\u2705 Stable Components (Production Ready):"));
2955
- stable.slice(0, 10).forEach((comp) => {
2956
- logger.info(` ${comp.icon} ${import_chalk8.default.white(comp.name)} - ${comp.category}`);
2957
- });
2958
- logger.newline();
2959
- logger.info(import_chalk8.default.gray(`... and ${stable.length - 10} more`));
2960
- logger.newline();
2961
- logger.info(import_chalk8.default.gray("Use: nikkory-vibe react generate <granularity> <name>"));
2962
- logger.info(import_chalk8.default.gray("Search: nikkory-vibe react search <keyword>"));
2963
- }
2964
- /**
2965
- * Search React components by keyword
2966
- *
2967
- * Searches component registry by name, tags, and category.
2968
- * Uses relevance scoring to rank results.
2969
- *
2970
- * @param keyword - Search term
2971
- * @returns Promise<void>
2972
- */
2973
- async search(keyword) {
2974
- logger.header(`\u{1F50D} Search: "${keyword}"`);
2975
- logger.newline();
2976
- const results = (0, import_vibe_engine2.searchComponents)(keyword);
2977
- if (results.length === 0) {
2978
- logger.warn(`No components found matching "${keyword}"`);
2979
- logger.info("Try searching for: button, card, form, modal, table");
2980
- return;
2981
- }
2982
- logger.info(`Found ${import_chalk8.default.cyan(String(results.length))} results:`);
2983
- logger.newline();
2984
- results.forEach((comp, index) => {
2985
- const badges = [];
2986
- if (comp.isNew) badges.push(import_chalk8.default.green("NEW"));
2987
- if (comp.isPopular) badges.push(import_chalk8.default.yellow("POPULAR"));
2988
- logger.info(`${import_chalk8.default.gray(`${index + 1}.`)} ${comp.icon} ${import_chalk8.default.white(comp.name)}${badges.length > 0 ? ` [${badges.join(" ")}]` : ""}`);
2989
- logger.info(` ${import_chalk8.default.gray(comp.category)} \u2022 ${comp.designSystems.length} designs \u2022 ${comp.tiers.length} tiers`);
2990
- if (comp.tags && comp.tags.length > 0) {
2991
- logger.info(` ${import_chalk8.default.gray("Tags:")} ${comp.tags.join(", ")}`);
2992
- }
2993
- logger.newline();
2994
- });
2995
- logger.info(import_chalk8.default.gray("Generate: nikkory-vibe react generate atom <name>"));
2996
- }
2997
- /**
2998
- * Get detailed info about React component
2999
- *
3000
- * Shows all available metadata:
3001
- * - Design systems supported
3002
- * - Tiers available
3003
- * - Props/variants
3004
- * - Usage examples
3005
- *
3006
- * @param granularity - Component size
3007
- * @param target - Target name
3008
- * @returns Promise<void>
3009
- */
3010
- async info(granularity, target) {
3011
- logger.header(`\u2139\uFE0F Component Info: ${target}`);
3012
- logger.newline();
3013
- const results = (0, import_vibe_engine2.searchComponents)(target);
3014
- const component = results.find((c) => c.id.toLowerCase() === target.toLowerCase());
3015
- if (!component) {
3016
- logger.warn(`Component "${target}" not found in registry`);
3017
- logger.info("Try searching first: nikkory-vibe react search <keyword>");
3018
- return;
3019
- }
3020
- logger.info(`${component.icon} ${import_chalk8.default.white(component.name)}`);
3021
- logger.info(`${import_chalk8.default.gray("Category:")} ${component.category}`);
3022
- logger.info(`${import_chalk8.default.gray("Complexity:")} ${component.complexity}`);
3023
- logger.info(`${import_chalk8.default.gray("Status:")} ${component.status}`);
3024
- logger.newline();
3025
- logger.info(import_chalk8.default.cyan("Design Systems:"));
3026
- component.designSystems.forEach((ds) => {
3027
- logger.info(` \u2022 ${ds}`);
3028
- });
3029
- logger.newline();
3030
- logger.info(import_chalk8.default.cyan("Tiers:"));
3031
- component.tiers.forEach((tier) => {
3032
- logger.info(` \u2022 ${tier}`);
3033
- });
3034
- logger.newline();
3035
- if (component.tags && component.tags.length > 0) {
3036
- logger.info(import_chalk8.default.cyan("Tags:"));
3037
- logger.info(` ${component.tags.join(", ")}`);
3038
- logger.newline();
3039
- }
3040
- const badges = [];
3041
- if (component.isNew) badges.push(import_chalk8.default.green("NEW"));
3042
- if (component.isPopular) badges.push(import_chalk8.default.yellow("POPULAR"));
3043
- if (badges.length > 0) {
3044
- logger.info(`${badges.join(" ")}`);
3045
- logger.newline();
3046
- }
3047
- logger.info(import_chalk8.default.gray("Generate this component:"));
3048
- logger.code(` nikkory-vibe react generate ${granularity} ${target} --tier=enterprise`);
3049
- }
3050
- };
3051
-
3052
- // src/scopes/pattern.ts
3053
- var import_chalk9 = __toESM(require("chalk"));
3054
- var PatternScopeHandler = class {
3055
- scope = "pattern";
3056
- available = true;
3057
- /**
3058
- * Generate pattern boilerplate code
3059
- *
3060
- * @param granularity - Pattern complexity level
3061
- * @param target - Pattern name (e.g., "auth-jwt", "payment-stripe")
3062
- * @param options - CLI options
3063
- * @returns Promise<void>
3064
- */
3065
- async generate(_granularity, target, options) {
3066
- logger.header("\u{1F4D0} Nikkory Vibe - Pattern Generator");
3067
- logger.info(`Pattern: ${import_chalk9.default.cyan(target)}`);
3068
- logger.info(`Tier: ${options.tier || "standard"}`);
3069
- logger.newline();
3070
- logger.warn("Pattern generation coming soon!");
3071
- logger.info("Available patterns will include:");
3072
- logger.info(" \u2022 Authentication (JWT, OAuth, SAML)");
3073
- logger.info(" \u2022 Payment (Stripe, PayPal, Square)");
3074
- logger.info(" \u2022 Caching (Redis, Memcached)");
3075
- logger.info(" \u2022 Queue (Bull, BeeQueue)");
3076
- logger.info(" \u2022 Search (Algolia, Elasticsearch)");
3077
- logger.newline();
3078
- logger.info("For now, use the patterns package directly:");
3079
- logger.code(" import { AuthPattern } from '@nikkory/vibe-patterns';");
3080
- }
3081
- /**
3082
- * List available patterns
3083
- *
3084
- * Shows all patterns organized by category:
3085
- * - Authentication & Authorization
3086
- * - Payment Processing
3087
- * - Data Storage
3088
- * - Communication
3089
- * - Infrastructure
3090
- *
3091
- * @param granularity - Optional filter by complexity
3092
- * @returns Promise<void>
3093
- */
3094
- async list(_granularity) {
3095
- logger.header("\u{1F4D0} Design Patterns");
3096
- logger.newline();
3097
- logger.info(import_chalk9.default.cyan("Authentication & Authorization:"));
3098
- logger.info(" \u{1F510} jwt-auth - JWT token authentication");
3099
- logger.info(" \u{1F510} oauth2 - OAuth 2.0 flow");
3100
- logger.info(" \u{1F510} saml-sso - SAML single sign-on");
3101
- logger.info(" \u{1F510} rbac - Role-based access control");
3102
- logger.newline();
3103
- logger.info(import_chalk9.default.cyan("Payment Processing:"));
3104
- logger.info(" \u{1F4B3} stripe-checkout - Stripe payment integration");
3105
- logger.info(" \u{1F4B3} paypal-express - PayPal Express Checkout");
3106
- logger.info(" \u{1F4B3} subscription - Recurring billing");
3107
- logger.newline();
3108
- logger.info(import_chalk9.default.cyan("Data Storage:"));
3109
- logger.info(" \u{1F4BE} redis-cache - Redis caching layer");
3110
- logger.info(" \u{1F4BE} s3-upload - AWS S3 file uploads");
3111
- logger.info(" \u{1F4BE} postgres-pool - PostgreSQL connection pooling");
3112
- logger.newline();
3113
- logger.info(import_chalk9.default.cyan("Communication:"));
3114
- logger.info(" \u{1F4E7} email-sendgrid - SendGrid email service");
3115
- logger.info(" \u{1F4E7} sms-twilio - Twilio SMS integration");
3116
- logger.info(" \u{1F4E7} websocket - Real-time WebSocket");
3117
- logger.newline();
3118
- logger.info(import_chalk9.default.cyan("Infrastructure:"));
3119
- logger.info(" \u{1F680} queue-bull - Bull queue system");
3120
- logger.info(" \u{1F680} search-elastic - Elasticsearch integration");
3121
- logger.info(" \u{1F680} logging-winston - Winston logger setup");
3122
- logger.newline();
3123
- if (_granularity) {
3124
- logger.info(import_chalk9.default.gray(`Filtered by: ${_granularity}`));
3125
- }
3126
- logger.info(import_chalk9.default.gray("Use: nikkory-vibe pattern generate <complexity> <name>"));
3127
- }
3128
- /**
3129
- * Search patterns by keyword
3130
- *
3131
- * @param keyword - Search term
3132
- * @returns Promise<void>
3133
- */
3134
- async search(keyword) {
3135
- logger.header(`\u{1F50D} Pattern Search: "${keyword}"`);
3136
- logger.newline();
3137
- const patterns = {
3138
- auth: ["jwt-auth", "oauth2", "saml-sso", "rbac"],
3139
- payment: ["stripe-checkout", "paypal-express", "subscription"],
3140
- cache: ["redis-cache"],
3141
- storage: ["s3-upload", "postgres-pool"],
3142
- email: ["email-sendgrid", "sms-twilio"],
3143
- queue: ["queue-bull"],
3144
- search: ["search-elastic"],
3145
- log: ["logging-winston"]
3146
- };
3147
- const lowerKeyword = keyword.toLowerCase();
3148
- const results = [];
3149
- Object.entries(patterns).forEach(([category, items]) => {
3150
- if (category.includes(lowerKeyword)) {
3151
- results.push(...items);
3152
- } else {
3153
- items.forEach((item) => {
3154
- if (item.includes(lowerKeyword)) {
3155
- results.push(item);
3156
- }
3157
- });
3158
- }
3159
- });
3160
- if (results.length === 0) {
3161
- logger.warn(`No patterns found matching "${keyword}"`);
3162
- logger.info("Try: auth, payment, cache, queue, email");
3163
- return;
3164
- }
3165
- logger.info(`Found ${import_chalk9.default.cyan(String(results.length))} patterns:`);
3166
- logger.newline();
3167
- results.forEach((pattern, index) => {
3168
- logger.info(`${import_chalk9.default.gray(`${index + 1}.`)} ${pattern}`);
3169
- });
3170
- logger.newline();
3171
- logger.info(import_chalk9.default.gray("Get info: nikkory-vibe pattern info template <pattern-name>"));
3172
- }
3173
- /**
3174
- * Get detailed info about pattern
3175
- *
3176
- * @param granularity - Pattern complexity
3177
- * @param target - Pattern name
3178
- * @returns Promise<void>
3179
- */
3180
- async info(_granularity, target) {
3181
- logger.header(`\u2139\uFE0F Pattern Info: ${target}`);
3182
- logger.newline();
3183
- const patterns = {
3184
- "jwt-auth": {
3185
- name: "JWT Authentication",
3186
- description: "JSON Web Token authentication with refresh tokens",
3187
- tier: "standard",
3188
- deps: ["jsonwebtoken", "bcrypt"]
3189
- },
3190
- "stripe-checkout": {
3191
- name: "Stripe Checkout",
3192
- description: "Complete Stripe payment integration",
3193
- tier: "enterprise",
3194
- deps: ["stripe", "@stripe/react-stripe-js"]
3195
- },
3196
- "redis-cache": {
3197
- name: "Redis Caching",
3198
- description: "Redis-based caching layer with TTL support",
3199
- tier: "standard",
3200
- deps: ["ioredis"]
3201
- }
3202
- };
3203
- const pattern = patterns[target];
3204
- if (!pattern) {
3205
- logger.warn(`Pattern "${target}" not found`);
3206
- logger.info("Try searching: nikkory-vibe pattern search <keyword>");
3207
- return;
3208
- }
3209
- logger.info(import_chalk9.default.white(pattern.name));
3210
- logger.info(`${import_chalk9.default.gray("Description:")} ${pattern.description}`);
3211
- logger.info(`${import_chalk9.default.gray("Tier:")} ${pattern.tier}`);
3212
- logger.newline();
3213
- logger.info(import_chalk9.default.cyan("Dependencies:"));
3214
- pattern.deps.forEach((dep) => {
3215
- logger.info(` \u2022 ${dep}`);
3216
- });
3217
- logger.newline();
3218
- logger.info(import_chalk9.default.gray("Generate this pattern:"));
3219
- logger.code(` nikkory-vibe pattern generate template ${target}`);
3220
- }
3221
- };
3222
-
3223
- // src/scopes/engine.ts
3224
- var import_chalk10 = __toESM(require("chalk"));
3225
- var EngineScopeHandler = class {
3226
- scope = "engine";
3227
- available = true;
3228
- /**
3229
- * Engine scope does not support generate
3230
- * Use react/vue/etc scopes for generation
3231
- *
3232
- * @throws Error - Always throws
3233
- */
3234
- async generate(_granularity, _target, _options) {
3235
- logger.error("Engine scope does not support generation");
3236
- logger.info("Use framework scopes instead:");
3237
- logger.code(" nikkory-vibe react generate atom button");
3238
- logger.code(" nikkory-vibe vue generate component Card");
3239
- throw new Error("Engine scope does not support generation");
3240
- }
3241
- /**
3242
- * List available engine exports
3243
- *
3244
- * Shows all public exports from @nikkory/vibe-engine:
3245
- * - Generators (ComponentGenerator, SectionGenerator, PageGenerator)
3246
- * - Constants (DESIGN_SYSTEMS, TIERS, COLORS, etc.)
3247
- * - Utilities (cn, Result, Option, etc.)
3248
- * - Types and interfaces
3249
- *
3250
- * @param granularity - Optional filter (not used for engine)
3251
- * @returns Promise<void>
3252
- */
3253
- async list(granularity) {
3254
- logger.header("\u2699\uFE0F Vibe Engine Exports");
3255
- logger.newline();
3256
- logger.info(import_chalk10.default.cyan("Generators:"));
3257
- logger.info(" \u{1F3ED} ComponentGenerator - Generate components (atoms/molecules)");
3258
- logger.info(" \u{1F3ED} SectionGenerator - Generate sections (organisms)");
3259
- logger.info(" \u{1F3ED} PageGenerator - Generate complete pages");
3260
- logger.info(" \u{1F3ED} TemplateGenerator - Generate full templates");
3261
- logger.newline();
3262
- logger.info(import_chalk10.default.cyan("Constants (24-Factor Design System):"));
3263
- logger.info(" \u{1F3A8} DESIGN_SYSTEMS - 6 design systems");
3264
- logger.info(" \u{1F3A8} TIERS - 3 quality tiers (basic, standard, enterprise)");
3265
- logger.info(" \u{1F3A8} COLORS - Color palette");
3266
- logger.info(" \u{1F3A8} SIZES - Size scale");
3267
- logger.info(" \u{1F3A8} VARIANTS - Component variants");
3268
- logger.info(" \u{1F3A8} SHAPES - Border radius styles");
3269
- logger.info(" \u{1F3A8} POSITIONS - Layout positions");
3270
- logger.info(" \u{1F3A8} STATES - Interactive states");
3271
- logger.info(" \u{1F3A8} ANIMATIONS - Animation presets");
3272
- logger.info(" \u{1F3A8} ELEVATIONS - Shadow depths");
3273
- logger.info(" \u{1F3A8} + 13 more factors... (see docs)");
3274
- logger.newline();
3275
- logger.info(import_chalk10.default.cyan("Utilities:"));
3276
- logger.info(" \u{1F6E0}\uFE0F cn() - Tailwind class merger");
3277
- logger.info(" \u{1F6E0}\uFE0F Result<T, E> - Railway-oriented programming");
3278
- logger.info(" \u{1F6E0}\uFE0F Option<T> - Maybe monad");
3279
- logger.info(" \u{1F6E0}\uFE0F Logger - Structured logging");
3280
- logger.info(" \u{1F6E0}\uFE0F ValidationUtils - Input validation");
3281
- logger.newline();
3282
- logger.info(import_chalk10.default.cyan("Component Registry:"));
3283
- logger.info(" \u{1F4E6} ALL_COMPONENTS - 169 components");
3284
- logger.info(" \u{1F4E6} searchUIComponents() - Search by keyword");
3285
- logger.info(" \u{1F4E6} getPopularComponents() - 15 popular");
3286
- logger.info(" \u{1F4E6} getNewComponents() - 7 new");
3287
- logger.newline();
3288
- if (granularity) {
3289
- logger.info(import_chalk10.default.gray(`Note: Engine scope ignores granularity filter`));
3290
- }
3291
- logger.info(import_chalk10.default.gray("Import from engine:"));
3292
- logger.code(" import { ComponentGenerator, DESIGN_SYSTEMS } from '@nikkory/vibe-engine';");
3293
- }
3294
- /**
3295
- * Search engine exports
3296
- *
3297
- * @param keyword - Search term
3298
- * @returns Promise<void>
3299
- */
3300
- async search(keyword) {
3301
- logger.header(`\u{1F50D} Engine Search: "${keyword}"`);
3302
- logger.newline();
3303
- const exports2 = {
3304
- generator: ["ComponentGenerator", "SectionGenerator", "PageGenerator", "TemplateGenerator"],
3305
- constant: ["DESIGN_SYSTEMS", "TIERS", "COLORS", "SIZES", "VARIANTS", "SHAPES"],
3306
- utility: ["cn", "Result", "Option", "Logger", "ValidationUtils"],
3307
- component: ["ALL_COMPONENTS", "searchUIComponents", "getPopularComponents"]
3308
- };
3309
- const lowerKeyword = keyword.toLowerCase();
3310
- const results = [];
3311
- Object.entries(exports2).forEach(([category, items]) => {
3312
- if (category.includes(lowerKeyword)) {
3313
- results.push(...items);
3314
- } else {
3315
- items.forEach((item) => {
3316
- if (item.toLowerCase().includes(lowerKeyword)) {
3317
- results.push(item);
3318
- }
3319
- });
3320
- }
3321
- });
3322
- if (results.length === 0) {
3323
- logger.warn(`No exports found matching "${keyword}"`);
3324
- logger.info("Try: generator, constant, utility, component");
3325
- return;
3326
- }
3327
- logger.info(`Found ${import_chalk10.default.cyan(String(results.length))} exports:`);
3328
- logger.newline();
3329
- results.forEach((exp, index) => {
3330
- logger.info(`${import_chalk10.default.gray(`${index + 1}.`)} ${exp}`);
3331
- });
3332
- logger.newline();
3333
- logger.info(import_chalk10.default.gray("Get info: nikkory-vibe engine info template <export-name>"));
3334
- }
3335
- /**
3336
- * Get detailed info about engine export
3337
- *
3338
- * @param granularity - Complexity level
3339
- * @param target - Export name
3340
- * @returns Promise<void>
3341
- */
3342
- async info(_granularity, target) {
3343
- logger.header(`\u2139\uFE0F Engine Export: ${target}`);
3344
- logger.newline();
3345
- const info = {
3346
- ComponentGenerator: {
3347
- description: "Generate React/Vue/Svelte components from templates",
3348
- type: "class",
3349
- usage: `const generator = new ComponentGenerator();
3350
- const result = await generator.generate({
3351
- name: 'MyButton',
3352
- template: 'button',
3353
- designSystem: 'material-design',
3354
- tier: 'enterprise',
3355
- framework: 'react',
3356
- });`
3357
- },
3358
- DESIGN_SYSTEMS: {
3359
- description: "6 design systems: Material Design, iOS HIG, Glassmorphism, Neumorphism, Brutalism, Minimalism",
3360
- type: "constant",
3361
- usage: `import { DESIGN_SYSTEMS } from '@nikkory/vibe-engine';
3362
- // ['material-design', 'ios-hig', 'glassmorphism', 'neumorphism', 'brutalism', 'minimalism']`
3363
- },
3364
- cn: {
3365
- description: "Merge Tailwind CSS classes with conflict resolution",
3366
- type: "function",
3367
- usage: `import { cn } from '@nikkory/vibe-engine';
3368
- const classes = cn('px-4 py-2', isActive && 'bg-blue-500');`
3369
- },
3370
- Result: {
3371
- description: "Railway-oriented programming for error handling",
3372
- type: "type",
3373
- usage: `import { Result } from '@nikkory/vibe-engine';
3374
- function divide(a: number, b: number): Result<number, Error> {
3375
- if (b === 0) return Result.fail(new Error('Division by zero'));
3376
- return Result.ok(a / b);
3377
- }`
3378
- }
3379
- };
3380
- const exportInfo = info[target];
3381
- if (!exportInfo) {
3382
- logger.warn(`Export "${target}" not found in engine`);
3383
- logger.info("Try searching: nikkory-vibe engine search <keyword>");
3384
- return;
3385
- }
3386
- logger.info(import_chalk10.default.white(target));
3387
- logger.info(`${import_chalk10.default.gray("Type:")} ${exportInfo.type}`);
3388
- logger.info(`${import_chalk10.default.gray("Description:")} ${exportInfo.description}`);
3389
- logger.newline();
3390
- logger.info(import_chalk10.default.cyan("Usage:"));
3391
- logger.code(exportInfo.usage);
3392
- logger.newline();
3393
- logger.info(import_chalk10.default.gray("Documentation:"));
3394
- logger.info(" https://docs.nikkory.com/vibe-engine");
3395
- }
3396
- };
3397
-
3398
- // src/scopes/vue.ts
3399
- var import_chalk11 = __toESM(require("chalk"));
3400
- var VueScopeHandler = class {
3401
- scope = "vue";
3402
- available = false;
3403
- // Not available yet
3404
- /**
3405
- * Generate Vue component
3406
- *
3407
- * @throws Error - Not implemented yet
3408
- */
3409
- async generate(_granularity, _target, _options) {
3410
- this.showComingSoonMessage("generate");
3411
- throw new Error("Vue scope not available yet");
3412
- }
3413
- /**
3414
- * List Vue components
3415
- *
3416
- * @throws Error - Not implemented yet
3417
- */
3418
- async list(_granularity) {
3419
- this.showComingSoonMessage("list");
3420
- throw new Error("Vue scope not available yet");
3421
- }
3422
- /**
3423
- * Search Vue components
3424
- *
3425
- * @throws Error - Not implemented yet
3426
- */
3427
- async search(_keyword) {
3428
- this.showComingSoonMessage("search");
3429
- throw new Error("Vue scope not available yet");
3430
- }
3431
- /**
3432
- * Get Vue component info
3433
- *
3434
- * @throws Error - Not implemented yet
3435
- */
3436
- async info(_granularity, _target) {
3437
- this.showComingSoonMessage("info");
3438
- throw new Error("Vue scope not available yet");
3439
- }
3440
- /**
3441
- * Show coming soon message
3442
- *
3443
- * @param action - Action being attempted
3444
- * @returns void
3445
- */
3446
- showComingSoonMessage(action) {
3447
- logger.header("\u{1F6A7} Vue Support - Coming Soon");
3448
- logger.newline();
3449
- logger.warn(`Vue scope is not available yet (action: ${action})`);
3450
- logger.newline();
3451
- logger.info("Vue 3 support is planned for v4.1.0");
3452
- logger.info("Features will include:");
3453
- logger.info(" \u2022 Composition API components");
3454
- logger.info(" \u2022 TypeScript support");
3455
- logger.info(" \u2022 Pinia state management");
3456
- logger.info(" \u2022 Vue Router integration");
3457
- logger.info(" \u2022 Vite optimization");
3458
- logger.newline();
3459
- logger.info("For now, use React scope:");
3460
- logger.code(` nikkory-vibe react ${action} ...`);
3461
- logger.newline();
3462
- logger.info(import_chalk11.default.gray("Track progress: https://github.com/kemonra/nikkory-vibe/issues"));
3463
- }
3464
- };
3465
-
3466
- // src/scopes/svelte.ts
3467
- var import_chalk12 = __toESM(require("chalk"));
3468
- var SvelteScopeHandler = class {
3469
- scope = "svelte";
3470
- available = false;
3471
- // Not available yet
3472
- /**
3473
- * Generate Svelte component
3474
- *
3475
- * @throws Error - Not implemented yet
3476
- */
3477
- async generate(_granularity, _target, _options) {
3478
- this.showComingSoonMessage("generate");
3479
- throw new Error("Svelte scope not available yet");
3480
- }
3481
- /**
3482
- * List Svelte components
3483
- *
3484
- * @throws Error - Not implemented yet
3485
- */
3486
- async list(_granularity) {
3487
- this.showComingSoonMessage("list");
3488
- throw new Error("Svelte scope not available yet");
3489
- }
3490
- /**
3491
- * Search Svelte components
3492
- *
3493
- * @throws Error - Not implemented yet
3494
- */
3495
- async search(_keyword) {
3496
- this.showComingSoonMessage("search");
3497
- throw new Error("Svelte scope not available yet");
3498
- }
3499
- /**
3500
- * Get Svelte component info
3501
- *
3502
- * @throws Error - Not implemented yet
3503
- */
3504
- async info(_granularity, _target) {
3505
- this.showComingSoonMessage("info");
3506
- throw new Error("Svelte scope not available yet");
3507
- }
3508
- /**
3509
- * Show coming soon message
3510
- *
3511
- * @param action - Action being attempted
3512
- * @returns void
3513
- */
3514
- showComingSoonMessage(action) {
3515
- logger.header("\u{1F6A7} Svelte Support - Coming Soon");
3516
- logger.newline();
3517
- logger.warn(`Svelte scope is not available yet (action: ${action})`);
3518
- logger.newline();
3519
- logger.info("Svelte support is planned for v4.2.0");
3520
- logger.info("Features will include:");
3521
- logger.info(" \u2022 Svelte 4+ components");
3522
- logger.info(" \u2022 TypeScript support");
3523
- logger.info(" \u2022 SvelteKit integration");
3524
- logger.info(" \u2022 Reactive stores");
3525
- logger.info(" \u2022 Reactive statements");
3526
- logger.newline();
3527
- logger.info("For now, use React scope:");
3528
- logger.code(` nikkory-vibe react ${action} ...`);
3529
- logger.newline();
3530
- logger.info(import_chalk12.default.gray("Track progress: https://github.com/kemonra/nikkory-vibe/issues"));
3531
- }
3532
- };
3533
-
3534
- // src/scopes/index.ts
3535
- var registry = /* @__PURE__ */ new Map();
3536
- registry.set("react", new ReactScopeHandler());
3537
- registry.set("pattern", new PatternScopeHandler());
3538
- registry.set("engine", new EngineScopeHandler());
3539
- registry.set("vue", new VueScopeHandler());
3540
- registry.set("svelte", new SvelteScopeHandler());
3541
- function getScopeHandler(scope) {
3542
- return registry.get(scope);
3543
- }
3544
- function getAvailableScopes() {
3545
- return Array.from(registry.entries()).filter(([_scope, handler]) => handler.available).map(([scope]) => scope);
3546
- }
3547
-
3548
- // src/interactive/wizard.ts
3549
- var import_chalk13 = __toESM(require("chalk"));
3550
- var import_inquirer3 = __toESM(require("inquirer"));
3551
-
3552
- // src/interactive/questions.ts
3553
- var scopeQuestion = [
3554
- {
3555
- type: "list",
3556
- name: "scope",
3557
- message: "Which framework would you like to use?",
3558
- choices: () => {
3559
- const available = getAvailableScopes();
3560
- return available.map((scope) => ({
3561
- name: getScopeLabel(scope),
3562
- value: scope
3563
- }));
3564
- },
3565
- default: "react"
3566
- }
3567
- ];
3568
- var actionQuestion = [
3569
- {
3570
- type: "list",
3571
- name: "action",
3572
- message: "What would you like to do?",
3573
- choices: [
3574
- { name: "\u{1F3A8} Generate - Create a new component", value: "generate" },
3575
- { name: "\u{1F4CB} List - Show available components", value: "list" },
3576
- { name: "\u{1F50D} Search - Find components by keyword", value: "search" },
3577
- { name: "\u2139\uFE0F Info - Show component details", value: "info" },
3578
- { name: "\u{1F441}\uFE0F Preview - Preview component in browser", value: "preview" }
3579
- ],
3580
- default: "generate"
3581
- }
3582
- ];
3583
- var granularityQuestion = [
3584
- {
3585
- type: "list",
3586
- name: "granularity",
3587
- message: "What size component do you need?",
3588
- choices: [
3589
- { name: "\u269B\uFE0F Atom - Small UI primitive (button, input)", value: "atom" },
3590
- { name: "\u{1F9E9} Component - Composite UI (card, modal)", value: "component" },
3591
- { name: "\u{1F4D0} Section - Page section (hero, pricing)", value: "section" },
3592
- { name: "\u{1F4C4} Page - Complete page", value: "page" },
3593
- { name: "\u{1F3AF} Layout - Layout template", value: "layout" },
3594
- { name: "\u{1F4E6} Template - Full page template", value: "template" }
3595
- ],
3596
- default: "component"
3597
- }
3598
- ];
3599
- var targetQuestion = [
3600
- {
3601
- type: "input",
3602
- name: "target",
3603
- message: "What should the component be called?",
3604
- validate: (input) => {
3605
- if (!input || input.trim().length === 0) {
3606
- return "Component name is required";
3607
- }
3608
- if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(input)) {
3609
- return "Component name must start with a letter and contain only letters, numbers, hyphens, and underscores";
3610
- }
3611
- return true;
3612
- }
3613
- }
3614
- ];
3615
- var tierQuestion = [
3616
- {
3617
- type: "list",
3618
- name: "tier",
3619
- message: "Which quality tier do you need?",
3620
- choices: [
3621
- {
3622
- name: "\u{1F7E2} Basic - Quick prototype (30-50 LOC)",
3623
- value: "basic"
3624
- },
3625
- {
3626
- name: "\u{1F7E1} Standard - Production ready (50-150 LOC)",
3627
- value: "standard"
3628
- },
3629
- {
3630
- name: "\u{1F534} Enterprise - Full features (150-300 LOC)",
3631
- value: "enterprise"
3632
- }
3633
- ],
3634
- default: "standard"
3635
- }
3636
- ];
3637
- var designSystemQuestion = [
3638
- {
3639
- type: "list",
3640
- name: "designSystem",
3641
- message: "Which design system would you like to use?",
3642
- choices: [
3643
- { name: "\u{1F4F1} Material Design 3 (Google)", value: "material-design" },
3644
- { name: "\u{1F34E} iOS HIG (Apple)", value: "ios-hig" },
3645
- { name: "\u{1FA9F} Glassmorphism (Frosted glass)", value: "glassmorphism" },
3646
- { name: "\u{1F518} Neumorphism (Soft UI)", value: "neumorphism" },
3647
- { name: "\u{1F9F1} Brutalism (Bold & raw)", value: "brutalism" },
3648
- { name: "\u2728 Minimalism (Clean & simple)", value: "minimalism" }
3649
- ],
3650
- default: "material-design"
3651
- }
3652
- ];
3653
- var outputQuestion = [
3654
- {
3655
- type: "input",
3656
- name: "output",
3657
- message: "Where should the file be saved? (leave empty for default)",
3658
- default: ""
3659
- }
3660
- ];
3661
- var confirmQuestion = [
3662
- {
3663
- type: "confirm",
3664
- name: "confirm",
3665
- message: "Generate this component?",
3666
- default: true
3667
- }
3668
- ];
3669
- var searchKeywordQuestion = [
3670
- {
3671
- type: "input",
3672
- name: "keyword",
3673
- message: "Enter search keyword:",
3674
- validate: (input) => {
3675
- if (!input || input.trim().length === 0) {
3676
- return "Search keyword is required";
3677
- }
3678
- return true;
3679
- }
3680
- }
3681
- ];
3682
- function getScopeLabel(scope) {
3683
- const labels = {
3684
- react: "\u269B\uFE0F React",
3685
- vue: "\u{1F49A} Vue",
3686
- svelte: "\u{1F7E0} Svelte",
3687
- angular: "\u{1F53A} Angular",
3688
- pattern: "\u{1F3AF} Pattern",
3689
- engine: "\u2699\uFE0F Engine"
3690
- };
3691
- return labels[scope] || scope;
3692
- }
3693
-
3694
- // src/interactive/wizard.ts
3695
- async function startWizard(initialScope) {
3696
- console.log(
3697
- import_chalk13.default.cyan("\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n") + import_chalk13.default.cyan("\u2551") + import_chalk13.default.white(" Welcome to Nikkory Vibe Wizard ") + import_chalk13.default.cyan("\u2551\n") + import_chalk13.default.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n")
3698
- );
3699
- const answers = {};
3700
- if (initialScope) {
3701
- answers.scope = initialScope;
3702
- console.log(import_chalk13.default.gray(`Using scope: ${initialScope}
3703
- `));
3704
- } else {
3705
- const scopeAnswer = await import_inquirer3.default.prompt(scopeQuestion);
3706
- answers.scope = scopeAnswer.scope;
3707
- }
3708
- if (!answers.scope) {
3709
- console.error(import_chalk13.default.red("Error: No scope selected"));
3710
- return;
3711
- }
3712
- const actionAnswer = await import_inquirer3.default.prompt(actionQuestion);
3713
- answers.action = actionAnswer.action;
3714
- switch (answers.action) {
3715
- case "generate":
3716
- await handleGenerateFlow(answers);
3717
- break;
3718
- case "list":
3719
- await handleListFlow(answers);
3720
- break;
3721
- case "search":
3722
- await handleSearchFlow(answers);
3723
- break;
3724
- case "info":
3725
- await handleInfoFlow(answers);
3726
- break;
3727
- case "preview":
3728
- await handlePreviewFlow(answers);
3729
- break;
3730
- default:
3731
- console.error(import_chalk13.default.red(`Unknown action: ${answers.action}`));
3732
- }
3733
- }
3734
- async function handleGenerateFlow(answers) {
3735
- const granularityAnswer = await import_inquirer3.default.prompt(granularityQuestion);
3736
- answers.granularity = granularityAnswer.granularity;
3737
- const targetAnswer = await import_inquirer3.default.prompt(targetQuestion);
3738
- answers.target = targetAnswer.target;
3739
- const tierAnswer = await import_inquirer3.default.prompt(tierQuestion);
3740
- answers.tier = tierAnswer.tier;
3741
- const designAnswer = await import_inquirer3.default.prompt(designSystemQuestion);
3742
- answers.designSystem = designAnswer.designSystem;
3743
- const outputAnswer = await import_inquirer3.default.prompt(outputQuestion);
3744
- answers.output = outputAnswer.output || void 0;
3745
- console.log(
3746
- import_chalk13.default.cyan("\n\u{1F4CB} Summary:\n") + import_chalk13.default.gray(` Scope: ${answers.scope}
3747
- `) + import_chalk13.default.gray(` Granularity: ${answers.granularity}
3748
- `) + import_chalk13.default.gray(` Component: ${answers.target}
3749
- `) + import_chalk13.default.gray(` Tier: ${answers.tier}
3750
- `) + import_chalk13.default.gray(` Design System: ${answers.designSystem}
3751
- `) + (answers.output ? import_chalk13.default.gray(` Output: ${answers.output}
3752
- `) : "")
3753
- );
3754
- const confirmAnswer = await import_inquirer3.default.prompt(confirmQuestion);
3755
- if (!confirmAnswer.confirm) {
3756
- console.log(import_chalk13.default.yellow("\n\u274C Cancelled\n"));
3757
- return;
3758
- }
3759
- await executeGenerate(answers);
3760
- }
3761
- async function handleListFlow(answers) {
3762
- const filterAnswer = await import_inquirer3.default.prompt([
3763
- {
3764
- type: "confirm",
3765
- name: "filter",
3766
- message: "Filter by granularity?",
3767
- default: false
3768
- }
3769
- ]);
3770
- if (filterAnswer.filter) {
3771
- const granularityAnswer = await import_inquirer3.default.prompt(granularityQuestion);
3772
- answers.granularity = granularityAnswer.granularity;
3773
- }
3774
- await executeList(answers);
3775
- }
3776
- async function handleSearchFlow(answers) {
3777
- const keywordAnswer = await import_inquirer3.default.prompt(searchKeywordQuestion);
3778
- answers.keyword = keywordAnswer.keyword;
3779
- await executeSearch(answers);
3780
- }
3781
- async function handleInfoFlow(answers) {
3782
- const granularityAnswer = await import_inquirer3.default.prompt(granularityQuestion);
3783
- answers.granularity = granularityAnswer.granularity;
3784
- const targetAnswer = await import_inquirer3.default.prompt(targetQuestion);
3785
- answers.target = targetAnswer.target;
3786
- await executeInfo(answers);
3787
- }
3788
- async function handlePreviewFlow(answers) {
3789
- const granularityAnswer = await import_inquirer3.default.prompt(granularityQuestion);
3790
- answers.granularity = granularityAnswer.granularity;
3791
- const targetAnswer = await import_inquirer3.default.prompt(targetQuestion);
3792
- answers.target = targetAnswer.target;
3793
- const tierAnswer = await import_inquirer3.default.prompt(tierQuestion);
3794
- answers.tier = tierAnswer.tier;
3795
- const designAnswer = await import_inquirer3.default.prompt(designSystemQuestion);
3796
- answers.designSystem = designAnswer.designSystem;
3797
- await executePreview(answers);
3798
- }
3799
- async function executeGenerate(answers) {
3800
- if (!answers.scope || !answers.granularity || !answers.target) {
3801
- console.error(import_chalk13.default.red("Error: Missing required parameters"));
3802
- return;
3803
- }
3804
- const handler = getScopeHandler(answers.scope);
3805
- if (!handler) {
3806
- console.error(import_chalk13.default.red(`Error: No handler found for scope "${answers.scope}"`));
3807
- return;
3808
- }
3809
- const options = {
3810
- tier: answers.tier || "standard",
3811
- designSystem: answers.designSystem || "material-design",
3812
- output: answers.output
3813
- };
3814
- try {
3815
- await handler.generate(answers.granularity, answers.target, options);
3816
- } catch (error) {
3817
- console.error(
3818
- import_chalk13.default.red(`
3819
- Error: ${error instanceof Error ? error.message : String(error)}`)
3820
- );
3821
- }
3822
- }
3823
- async function executeList(answers) {
3824
- if (!answers.scope) {
3825
- console.error(import_chalk13.default.red("Error: No scope selected"));
3826
- return;
3827
- }
3828
- const handler = getScopeHandler(answers.scope);
3829
- if (!handler) {
3830
- console.error(import_chalk13.default.red(`Error: No handler found for scope "${answers.scope}"`));
3831
- return;
3832
- }
3833
- try {
3834
- await handler.list(answers.granularity);
3835
- } catch (error) {
3836
- console.error(
3837
- import_chalk13.default.red(`
3838
- Error: ${error instanceof Error ? error.message : String(error)}`)
3839
- );
3840
- }
3841
- }
3842
- async function executeSearch(answers) {
3843
- if (!answers.scope || !answers.keyword) {
3844
- console.error(import_chalk13.default.red("Error: Missing required parameters"));
3845
- return;
3846
- }
3847
- const handler = getScopeHandler(answers.scope);
3848
- if (!handler) {
3849
- console.error(import_chalk13.default.red(`Error: No handler found for scope "${answers.scope}"`));
3850
- return;
3851
- }
3852
- try {
3853
- await handler.search(answers.keyword);
3854
- } catch (error) {
3855
- console.error(
3856
- import_chalk13.default.red(`
3857
- Error: ${error instanceof Error ? error.message : String(error)}`)
3858
- );
3859
- }
3860
- }
3861
- async function executeInfo(answers) {
3862
- if (!answers.scope || !answers.granularity || !answers.target) {
3863
- console.error(import_chalk13.default.red("Error: Missing required parameters"));
3864
- return;
3865
- }
3866
- const handler = getScopeHandler(answers.scope);
3867
- if (!handler) {
3868
- console.error(import_chalk13.default.red(`Error: No handler found for scope "${answers.scope}"`));
3869
- return;
3870
- }
3871
- try {
3872
- await handler.info(answers.granularity, answers.target);
3873
- } catch (error) {
3874
- console.error(
3875
- import_chalk13.default.red(`
3876
- Error: ${error instanceof Error ? error.message : String(error)}`)
3877
- );
3878
- }
3879
- }
3880
- async function executePreview(answers) {
3881
- if (!answers.scope || !answers.granularity || !answers.target) {
3882
- console.error(import_chalk13.default.red("Error: Missing required parameters"));
3883
- return;
3884
- }
3885
- const handler = getScopeHandler(answers.scope);
3886
- if (!handler) {
3887
- console.error(import_chalk13.default.red(`Error: No handler found for scope "${answers.scope}"`));
3888
- return;
3889
- }
3890
- if (!handler.preview) {
3891
- console.error(import_chalk13.default.red(`Error: ${answers.scope} handler does not support preview`));
3892
- return;
3893
- }
3894
- const options = {
3895
- tier: answers.tier || "standard",
3896
- designSystem: answers.designSystem || "material-design"
3897
- };
3898
- try {
3899
- await handler.preview(answers.granularity, answers.target, options);
3900
- } catch (error) {
3901
- console.error(
3902
- import_chalk13.default.red(`
3903
- Error: ${error instanceof Error ? error.message : String(error)}`)
3904
- );
3905
- }
3906
- }
3907
-
3908
- // src/types/enums.ts
3909
- function isAvailableScope(scope) {
3910
- return ["react", "pattern", "engine"].includes(scope);
3911
- }
3912
- function isValidAction(action) {
3913
- return ["generate", "list", "search", "info", "preview", "add"].includes(action);
3914
- }
3915
-
3916
- // src/types/granularity.ts
3917
- function isValidGranularity(granularity) {
3918
- return ["atom", "component", "section", "page", "layout", "template"].includes(granularity);
3919
- }
3920
-
3921
- // src/cli.ts
3922
- var program = new import_commander12.Command();
3923
- var componentCount = 169;
3924
- var designSystemCount = 12;
3925
- var tierCount = 3;
3926
- var y = import_chalk14.default.hex("#fcb800");
3927
- var banner = `
3928
- ${y.bold("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557")}
3929
- ${y.bold("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D")}
3930
- ${y.bold("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2554\u255D ")}
3931
- ${y.bold("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u255A\u2588\u2588\u2554\u255D ")}
3932
- ${y.bold("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 ")}
3933
- ${y.bold("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D ")}
3934
-
3935
- ${y.bold(" \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ")}
3936
- ${y.bold(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ")}
3937
- ${y.bold(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 ")}
3938
- ${y.bold(" \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D ")}
3939
- ${y.bold(" \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ")}
3940
- ${y.bold(" \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D ")}
3941
-
3942
- ${y(" happy together")} ${import_chalk14.default.white("\u2022 v4.0.0")}
3943
-
3944
- ${import_chalk14.default.gray(" Multi-Framework Code Generator")}
3945
- ${import_chalk14.default.gray(" React \u2022 Vue \u2022 Svelte \u2022 Angular \u2022 Pattern")}
3946
-
3947
- ${y(` ${componentCount} Components`)} ${import_chalk14.default.gray("\xD7")} ${y(`${designSystemCount} Design Systems`)} ${import_chalk14.default.gray("\xD7")} ${y(`${tierCount} Tiers`)} ${import_chalk14.default.gray("=")} ${import_chalk14.default.white.bold(`${componentCount * designSystemCount * tierCount}+ variations`)}
3948
- `;
3949
- program.name("nikkory-vibe").description("Nikkory Vibe - Multi-framework UI component generator").version("4.0.0").addHelpText("before", banner);
3950
- async function handleScopeCommand(scope, action, granularity, target, options) {
3951
- let config;
3952
- try {
3953
- config = await loadConfig({
3954
- configPath: options?.config
3955
- });
3956
- } catch (error) {
3957
- console.error(
3958
- import_chalk14.default.red(`Error loading config: ${error instanceof Error ? error.message : String(error)}`)
3959
- );
3960
- process.exit(1);
3961
- }
3962
- const mergedOptions = {
3963
- tier: options?.tier || config.defaultTier,
3964
- designSystem: options?.designSystem || config.defaultDesignSystem,
3965
- output: options?.output,
3966
- dryRun: options?.dryRun ?? config.dryRun,
3967
- verbose: options?.verbose ?? config.verbose,
3968
- force: options?.force ?? config.forceOverwrite,
3969
- interactive: options?.interactive,
3970
- frameworks: options?.frameworks,
3971
- config: options?.config,
3972
- yes: options?.yes
3973
- };
3974
- if (!isAvailableScope(scope)) {
3975
- const available = getAvailableScopes();
3976
- console.error(
3977
- import_chalk14.default.red(`Error: Scope "${scope}" is not available yet.
3978
- `) + import_chalk14.default.yellow(`Available scopes: ${available.join(", ")}
3979
- `) + import_chalk14.default.gray("Planned: vue, svelte, angular")
3980
- );
3981
- process.exit(1);
3982
- }
3983
- if (!isValidAction(action)) {
3984
- console.error(
3985
- import_chalk14.default.red(`Error: Action "${action}" is not valid.
3986
- `) + import_chalk14.default.yellow("Valid actions: generate, list, search, info, preview")
3987
- );
3988
- process.exit(1);
3989
- }
3990
- const handler = getScopeHandler(scope);
3991
- if (!handler) {
3992
- console.error(import_chalk14.default.red(`Error: No handler found for scope "${scope}"`));
3993
- process.exit(1);
3994
- }
3995
- try {
3996
- switch (action) {
3997
- case "generate":
3998
- if (!granularity || !target) {
3999
- console.error(
4000
- import_chalk14.default.red("Error: generate requires granularity and target\n") + import_chalk14.default.yellow("Usage: nikkory-vibe react generate atom button --tier=enterprise")
4001
- );
4002
- process.exit(1);
4003
- }
4004
- if (!isValidGranularity(granularity)) {
4005
- console.error(
4006
- import_chalk14.default.red(`Error: Invalid granularity "${granularity}"
4007
- `) + import_chalk14.default.yellow("Valid: atom, component, section, page, layout, template")
4008
- );
4009
- process.exit(1);
4010
- }
4011
- await handler.generate(granularity, target, mergedOptions);
4012
- break;
4013
- case "list":
4014
- await handler.list(
4015
- granularity && isValidGranularity(granularity) ? granularity : void 0
4016
- );
4017
- break;
4018
- case "search":
4019
- if (!granularity) {
4020
- console.error(
4021
- import_chalk14.default.red("Error: search requires a keyword\n") + import_chalk14.default.yellow('Usage: nikkory-vibe react search "authentication"')
4022
- );
4023
- process.exit(1);
4024
- }
4025
- await handler.search(granularity);
4026
- break;
4027
- case "info":
4028
- if (!granularity || !target) {
4029
- console.error(
4030
- import_chalk14.default.red("Error: info requires granularity and target\n") + import_chalk14.default.yellow("Usage: nikkory-vibe react info atom button")
4031
- );
4032
- process.exit(1);
4033
- }
4034
- if (!isValidGranularity(granularity)) {
4035
- console.error(import_chalk14.default.red(`Error: Invalid granularity "${granularity}"`));
4036
- process.exit(1);
4037
- }
4038
- await handler.info(granularity, target);
4039
- break;
4040
- case "preview":
4041
- if (!granularity || !target) {
4042
- console.error(
4043
- import_chalk14.default.red("Error: preview requires granularity and target\n") + import_chalk14.default.yellow("Usage: nikkory-vibe react preview component MyCard")
4044
- );
4045
- process.exit(1);
4046
- }
4047
- if (!isValidGranularity(granularity)) {
4048
- console.error(import_chalk14.default.red(`Error: Invalid granularity "${granularity}"`));
4049
- process.exit(1);
4050
- }
4051
- if (handler.preview) {
4052
- await handler.preview(granularity, target, mergedOptions);
4053
- } else {
4054
- console.error(import_chalk14.default.red(`Error: ${scope} handler does not support preview`));
4055
- process.exit(1);
4056
- }
4057
- break;
4058
- default:
4059
- console.error(import_chalk14.default.red(`Error: Unknown action "${action}"`));
4060
- process.exit(1);
4061
- }
4062
- } catch (error) {
4063
- console.error(import_chalk14.default.red(`
4064
- ${error instanceof Error ? error.message : String(error)}`));
4065
- console.log(
4066
- import_chalk14.default.gray("\nFor now, use legacy commands:\n") + import_chalk14.default.yellow(" vibe generate component MyButton\n") + import_chalk14.default.yellow(" vibe list\n")
4067
- );
4068
- process.exit(1);
4069
- }
4070
- }
4071
- var scopes = ["react", "vue", "svelte", "angular", "pattern", "engine"];
4072
- scopes.forEach((scope) => {
4073
- const scopeCommand = new import_commander12.Command(scope).description(`${scope.charAt(0).toUpperCase() + scope.slice(1)} framework commands`).argument("[action]", "Action (generate, list, search, info, preview)").argument("[granularity]", "Granularity (atom, component, section, page, layout, template)").argument("[target]", "Target name").option("-o, --output <path>", "Output file path").option("--tier <tier>", "Quality tier (basic, standard, enterprise)", "standard").option("-d, --design <system>", "Design system", "material-design").option("--dry-run", "Preview without writing files").option("--interactive", "Interactive mode with prompts").option("-f, --frameworks <frameworks...>", "Target frameworks for multi-framework generation").option("--config <path>", "Path to config file").option("--verbose", "Verbose output").option("--force", "Force overwrite existing files").option("-y, --yes", "Skip confirmation prompts").action(
4074
- async (action, granularity, target, cmdOptions) => {
4075
- if (cmdOptions?.["interactive"]) {
4076
- await startWizard(scope);
4077
- return;
4078
- }
4079
- const options = {
4080
- output: cmdOptions?.["output"],
4081
- tier: cmdOptions?.["tier"],
4082
- designSystem: cmdOptions?.["design"],
4083
- dryRun: cmdOptions?.["dryRun"],
4084
- interactive: cmdOptions?.["interactive"],
4085
- frameworks: cmdOptions?.["frameworks"],
4086
- config: cmdOptions?.["config"],
4087
- verbose: cmdOptions?.["verbose"],
4088
- force: cmdOptions?.["force"],
4089
- yes: cmdOptions?.["yes"]
4090
- };
4091
- await handleScopeCommand(scope, action || "list", granularity, target, options);
4092
- }
4093
- );
4094
- program.addCommand(scopeCommand);
4095
- });
4096
- program.addCommand(addCommand);
4097
- program.addCommand(listCommand);
4098
- program.addCommand(copyCommand);
4099
- program.addCommand(doctorCommand);
4100
- program.addCommand(initCommand);
4101
- program.addCommand(matrixGenerateCommand);
4102
- program.parse();
4103
- if (!process.argv.slice(2).length) {
4104
- console.log(banner);
4105
- program.outputHelp();
4106
- }