@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/index.js +30 -1
- package/package.json +3 -3
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -4106
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
|
-
}
|