mycontext-cli 0.1.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.
Files changed (94) hide show
  1. package/README.md +440 -0
  2. package/dist/cli/src/agents/implementations/CodeGenSubAgent.d.ts +43 -0
  3. package/dist/cli/src/agents/implementations/CodeGenSubAgent.d.ts.map +1 -0
  4. package/dist/cli/src/agents/implementations/CodeGenSubAgent.js +1440 -0
  5. package/dist/cli/src/agents/implementations/CodeGenSubAgent.js.map +1 -0
  6. package/dist/cli/src/agents/implementations/DocsSubAgent.d.ts +35 -0
  7. package/dist/cli/src/agents/implementations/DocsSubAgent.d.ts.map +1 -0
  8. package/dist/cli/src/agents/implementations/DocsSubAgent.js +351 -0
  9. package/dist/cli/src/agents/implementations/DocsSubAgent.js.map +1 -0
  10. package/dist/cli/src/agents/implementations/QASubAgent.d.ts +31 -0
  11. package/dist/cli/src/agents/implementations/QASubAgent.d.ts.map +1 -0
  12. package/dist/cli/src/agents/implementations/QASubAgent.js +190 -0
  13. package/dist/cli/src/agents/implementations/QASubAgent.js.map +1 -0
  14. package/dist/cli/src/agents/interfaces/SubAgent.d.ts +157 -0
  15. package/dist/cli/src/agents/interfaces/SubAgent.d.ts.map +1 -0
  16. package/dist/cli/src/agents/interfaces/SubAgent.js +7 -0
  17. package/dist/cli/src/agents/interfaces/SubAgent.js.map +1 -0
  18. package/dist/cli/src/agents/orchestrator/SubAgentOrchestrator.d.ts +59 -0
  19. package/dist/cli/src/agents/orchestrator/SubAgentOrchestrator.d.ts.map +1 -0
  20. package/dist/cli/src/agents/orchestrator/SubAgentOrchestrator.js +305 -0
  21. package/dist/cli/src/agents/orchestrator/SubAgentOrchestrator.js.map +1 -0
  22. package/dist/cli/src/agents/personalities/definitions.d.ts +34 -0
  23. package/dist/cli/src/agents/personalities/definitions.d.ts.map +1 -0
  24. package/dist/cli/src/agents/personalities/definitions.js +360 -0
  25. package/dist/cli/src/agents/personalities/definitions.js.map +1 -0
  26. package/dist/cli/src/cli.d.ts +3 -0
  27. package/dist/cli/src/cli.d.ts.map +1 -0
  28. package/dist/cli/src/cli.js +286 -0
  29. package/dist/cli/src/cli.js.map +1 -0
  30. package/dist/cli/src/commands/auth.d.ts +23 -0
  31. package/dist/cli/src/commands/auth.d.ts.map +1 -0
  32. package/dist/cli/src/commands/auth.js +212 -0
  33. package/dist/cli/src/commands/auth.js.map +1 -0
  34. package/dist/cli/src/commands/generate-components.d.ts +28 -0
  35. package/dist/cli/src/commands/generate-components.d.ts.map +1 -0
  36. package/dist/cli/src/commands/generate-components.js +680 -0
  37. package/dist/cli/src/commands/generate-components.js.map +1 -0
  38. package/dist/cli/src/commands/generate.d.ts +108 -0
  39. package/dist/cli/src/commands/generate.d.ts.map +1 -0
  40. package/dist/cli/src/commands/generate.js +1984 -0
  41. package/dist/cli/src/commands/generate.js.map +1 -0
  42. package/dist/cli/src/commands/init.d.ts +13 -0
  43. package/dist/cli/src/commands/init.d.ts.map +1 -0
  44. package/dist/cli/src/commands/init.js +91 -0
  45. package/dist/cli/src/commands/init.js.map +1 -0
  46. package/dist/cli/src/commands/list.d.ts +17 -0
  47. package/dist/cli/src/commands/list.d.ts.map +1 -0
  48. package/dist/cli/src/commands/list.js +209 -0
  49. package/dist/cli/src/commands/list.js.map +1 -0
  50. package/dist/cli/src/commands/preview.d.ts +23 -0
  51. package/dist/cli/src/commands/preview.d.ts.map +1 -0
  52. package/dist/cli/src/commands/preview.js +1200 -0
  53. package/dist/cli/src/commands/preview.js.map +1 -0
  54. package/dist/cli/src/commands/status.d.ts +21 -0
  55. package/dist/cli/src/commands/status.d.ts.map +1 -0
  56. package/dist/cli/src/commands/status.js +287 -0
  57. package/dist/cli/src/commands/status.js.map +1 -0
  58. package/dist/cli/src/commands/validate.d.ts +22 -0
  59. package/dist/cli/src/commands/validate.d.ts.map +1 -0
  60. package/dist/cli/src/commands/validate.js +259 -0
  61. package/dist/cli/src/commands/validate.js.map +1 -0
  62. package/dist/cli/src/types/index.d.ts +152 -0
  63. package/dist/cli/src/types/index.d.ts.map +1 -0
  64. package/dist/cli/src/types/index.js +3 -0
  65. package/dist/cli/src/types/index.js.map +1 -0
  66. package/dist/cli/src/utils/apiKeyManager.d.ts +137 -0
  67. package/dist/cli/src/utils/apiKeyManager.d.ts.map +1 -0
  68. package/dist/cli/src/utils/apiKeyManager.js +471 -0
  69. package/dist/cli/src/utils/apiKeyManager.js.map +1 -0
  70. package/dist/cli/src/utils/errorHandler.d.ts +105 -0
  71. package/dist/cli/src/utils/errorHandler.d.ts.map +1 -0
  72. package/dist/cli/src/utils/errorHandler.js +332 -0
  73. package/dist/cli/src/utils/errorHandler.js.map +1 -0
  74. package/dist/cli/src/utils/fileSystem.d.ts +58 -0
  75. package/dist/cli/src/utils/fileSystem.d.ts.map +1 -0
  76. package/dist/cli/src/utils/fileSystem.js +230 -0
  77. package/dist/cli/src/utils/fileSystem.js.map +1 -0
  78. package/dist/cli/src/utils/githubModels.d.ts +53 -0
  79. package/dist/cli/src/utils/githubModels.d.ts.map +1 -0
  80. package/dist/cli/src/utils/githubModels.js +239 -0
  81. package/dist/cli/src/utils/githubModels.js.map +1 -0
  82. package/dist/cli/src/utils/spinner.d.ts +28 -0
  83. package/dist/cli/src/utils/spinner.d.ts.map +1 -0
  84. package/dist/cli/src/utils/spinner.js +112 -0
  85. package/dist/cli/src/utils/spinner.js.map +1 -0
  86. package/dist/cli/src/utils/xaiClient.d.ts +59 -0
  87. package/dist/cli/src/utils/xaiClient.d.ts.map +1 -0
  88. package/dist/cli/src/utils/xaiClient.js +244 -0
  89. package/dist/cli/src/utils/xaiClient.js.map +1 -0
  90. package/dist/lib/analytics/usage-tracker.d.ts +125 -0
  91. package/dist/lib/analytics/usage-tracker.d.ts.map +1 -0
  92. package/dist/lib/analytics/usage-tracker.js +429 -0
  93. package/dist/lib/analytics/usage-tracker.js.map +1 -0
  94. package/package.json +64 -0
@@ -0,0 +1,1440 @@
1
+ "use strict";
2
+ /**
3
+ * CodeGenSubAgent Implementation
4
+ *
5
+ * Specialized sub-agent for generating production-ready React components and TypeScript code.
6
+ * Uses Claude Code for optimal code generation capabilities.
7
+ * Enhanced with shadcn/ui primitives and modern React patterns for Next.js 14+.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.CodeGenSubAgent = void 0;
44
+ const definitions_1 = require("../personalities/definitions");
45
+ const generate_components_1 = require("../../commands/generate-components");
46
+ // shadcn/ui component mapping for intelligent imports
47
+ const SHADCN_COMPONENTS = {
48
+ // Layout & Structure
49
+ layout: ["Card", "Separator", "AspectRatio"],
50
+ form: [
51
+ "Button",
52
+ "Input",
53
+ "Label",
54
+ "Form",
55
+ "Select",
56
+ "Checkbox",
57
+ "RadioGroup",
58
+ "Textarea",
59
+ "Switch",
60
+ ],
61
+ navigation: ["NavigationMenu", "Breadcrumb", "Pagination", "Tabs"],
62
+ feedback: ["Alert", "AlertDialog", "Dialog", "Toast", "Progress", "Skeleton"],
63
+ data: ["Table", "DataTable", "Command", "Combobox"],
64
+ overlay: ["Popover", "HoverCard", "Tooltip", "Sheet", "Drawer"],
65
+ media: ["Avatar", "Badge", "Calendar", "Carousel"],
66
+ utility: [
67
+ "ScrollArea",
68
+ "Resizable",
69
+ "Collapsible",
70
+ "Accordion",
71
+ "ContextMenu",
72
+ "Menubar",
73
+ "DropdownMenu",
74
+ "Toggle",
75
+ "ToggleGroup",
76
+ "Slider",
77
+ "Sonner",
78
+ ],
79
+ };
80
+ class CodeGenSubAgent {
81
+ constructor() {
82
+ this.name = "CodeGenSubAgent";
83
+ this.description = "Expert React/TypeScript developer specializing in production-ready Next.js 14+ components with shadcn/ui";
84
+ const personality = (0, definitions_1.getSubAgentPersonality)(this.name);
85
+ if (!personality) {
86
+ throw new Error(`Personality not found for ${this.name}`);
87
+ }
88
+ this.personality = personality.personality;
89
+ this.llmProvider = personality.llmProvider;
90
+ this.expertise = personality.expertise;
91
+ }
92
+ async run(input) {
93
+ const { component, group, options, context } = input;
94
+ // Use the existing GenerateComponentsCommand logic
95
+ const generateCommand = new generate_components_1.GenerateComponentsCommand();
96
+ // Handle both string and object inputs
97
+ let componentName;
98
+ if (typeof component === "string") {
99
+ componentName = component;
100
+ }
101
+ else {
102
+ componentName = component.name;
103
+ }
104
+ // Generate the component code using the enhanced method
105
+ const code = await this.generateProductionReadyComponent(component, group, options);
106
+ // Calculate metadata
107
+ const estimatedLines = code.split("\n").length;
108
+ const dependencies = this.extractDependencies(code);
109
+ const shadcnComponents = this.extractShadcnComponents(code);
110
+ return {
111
+ code,
112
+ metadata: {
113
+ componentName,
114
+ group,
115
+ dependencies,
116
+ estimatedLines,
117
+ shadcnComponents,
118
+ qualityScore: this.calculateQualityScore(code),
119
+ },
120
+ };
121
+ }
122
+ async validate(input) {
123
+ // Handle both structured component objects and simple string descriptions
124
+ if (typeof input.component === "string") {
125
+ // Simple string input - just need the string and group
126
+ return !!(input.component && input.group);
127
+ }
128
+ else {
129
+ // Structured component object - validate all required fields
130
+ if (!input.component || !input.component.name) {
131
+ return false;
132
+ }
133
+ if (!input.group) {
134
+ return false;
135
+ }
136
+ // For structured input, require type and userStories
137
+ if (!input.component.type || !input.component.userStories) {
138
+ return false;
139
+ }
140
+ }
141
+ return true;
142
+ }
143
+ async getStatus() {
144
+ return {
145
+ name: this.name,
146
+ status: "idle",
147
+ errorCount: 0,
148
+ successCount: 0,
149
+ };
150
+ }
151
+ async generateProductionReadyComponent(component, group, options) {
152
+ // Check if X.AI should be used for generation
153
+ if (options?.useXAI) {
154
+ return await this.generateWithXAI(component, group, options);
155
+ }
156
+ // Handle both string and object inputs
157
+ let name, description, type, userStories, actionFunctions, dependencies, tags;
158
+ if (typeof component === "string") {
159
+ // Simple string input - create a basic component structure
160
+ name = this.generateComponentName(component);
161
+ description = component;
162
+ type = "form"; // Default type
163
+ userStories = [
164
+ `As a user, I want to use ${name} to ${component.toLowerCase()}`,
165
+ ];
166
+ actionFunctions = ["handleSubmit", "handleChange"];
167
+ dependencies = ["react", "tailwindcss"];
168
+ tags = ["ui", "component"];
169
+ }
170
+ else {
171
+ // Structured component object
172
+ ({
173
+ name,
174
+ description,
175
+ type,
176
+ userStories,
177
+ actionFunctions,
178
+ dependencies,
179
+ tags,
180
+ } = component);
181
+ }
182
+ // Determine shadcn/ui components to import based on type
183
+ const shadcnImports = this.getShadcnImportsForType(type);
184
+ const customImports = this.getCustomImportsForType(type);
185
+ const reactImports = this.getReactImportsForType(type);
186
+ return `"use client";
187
+
188
+ import React${reactImports.length > 0 ? `, { ${reactImports.join(", ")} }` : ""} from "react";
189
+ import { cn } from "@/lib/utils";
190
+ ${shadcnImports
191
+ .map((imp) => `import { ${imp} } from "@/components/ui/${imp.toLowerCase()}";`)
192
+ .join("\n")}
193
+ ${customImports.length > 0 ? customImports.join("\n") : ""}
194
+
195
+ /**
196
+ * ${name} Component
197
+ *
198
+ * ${description}
199
+ *
200
+ * User Stories:
201
+ ${userStories.map((story) => ` * - ${story}`).join("\n")}
202
+ *
203
+ * @component
204
+ * @example
205
+ * \`\`\`tsx
206
+ * <${name}
207
+ * className="custom-styles"
208
+ * ${this.generateExampleProps(type)}
209
+ * />
210
+ * \`\`\`
211
+ */
212
+
213
+ ${this.generateTypeDefinitions(type, name)}
214
+
215
+ export interface ${name}Props {
216
+ /** Additional CSS classes */
217
+ className?: string;
218
+ ${this.generateDetailedPropsForType(type)}
219
+ }
220
+
221
+ /**
222
+ * ${name} - ${description}
223
+ *
224
+ * @param props - Component props
225
+ * @returns Production-ready ${type} component
226
+ */
227
+ export function ${name}({
228
+ className,
229
+ ${this.generateEnhancedPropsDestructuring(type)}
230
+ ...props
231
+ }: ${name}Props) {
232
+ ${this.generateProductionComponentLogic(type, actionFunctions, name)}
233
+
234
+ return (
235
+ ${this.generateAccessibleComponentJSX(type, name, shadcnImports)}
236
+ );
237
+ }
238
+
239
+ ${this.generateProductionActionFunctions(actionFunctions, name, type)}
240
+
241
+ export default ${name};
242
+ `;
243
+ }
244
+ getReactImportsForType(type) {
245
+ const imports = [];
246
+ switch (type) {
247
+ case "form":
248
+ imports.push("useState", "useCallback", "useMemo");
249
+ break;
250
+ case "layout":
251
+ imports.push("ReactNode", "FC");
252
+ break;
253
+ case "data":
254
+ imports.push("useState", "useEffect", "useMemo");
255
+ break;
256
+ case "navigation":
257
+ imports.push("useState", "useEffect");
258
+ break;
259
+ case "feedback":
260
+ imports.push("useState", "useEffect");
261
+ break;
262
+ default:
263
+ imports.push("useState");
264
+ }
265
+ return [...new Set(imports)];
266
+ }
267
+ getShadcnImportsForType(type) {
268
+ const imports = [];
269
+ switch (type) {
270
+ case "form":
271
+ imports.push("Button", "Input", "Label", "Form", "FormControl", "FormField", "FormItem", "FormLabel", "FormMessage", "Select", "SelectContent", "SelectItem", "SelectTrigger", "SelectValue", "Checkbox", "Alert", "AlertDescription");
272
+ break;
273
+ case "layout":
274
+ imports.push("Card", "CardContent", "CardDescription", "CardHeader", "CardTitle", "Separator");
275
+ break;
276
+ case "card":
277
+ imports.push("Card", "CardContent", "CardDescription", "CardHeader", "CardTitle", "CardFooter", "Button");
278
+ break;
279
+ case "button":
280
+ imports.push("Button");
281
+ break;
282
+ case "navigation":
283
+ imports.push("NavigationMenu", "NavigationMenuContent", "NavigationMenuItem", "NavigationMenuLink", "NavigationMenuList", "NavigationMenuTrigger", "Breadcrumb", "BreadcrumbItem", "BreadcrumbLink", "BreadcrumbList", "BreadcrumbSeparator", "Tabs", "TabsContent", "TabsList", "TabsTrigger");
284
+ break;
285
+ case "feedback":
286
+ imports.push("Alert", "AlertDescription", "AlertTitle", "Dialog", "DialogContent", "DialogDescription", "DialogHeader", "DialogTitle", "DialogTrigger", "Toast", "Progress");
287
+ break;
288
+ case "data":
289
+ imports.push("Table", "TableBody", "TableCell", "TableHead", "TableHeader", "TableRow", "Command", "CommandEmpty", "CommandGroup", "CommandInput", "CommandItem", "CommandList");
290
+ break;
291
+ case "overlay":
292
+ imports.push("Popover", "PopoverContent", "PopoverTrigger", "Tooltip", "TooltipContent", "TooltipProvider", "TooltipTrigger", "Sheet", "SheetContent", "SheetDescription", "SheetHeader", "SheetTitle", "SheetTrigger");
293
+ break;
294
+ case "media":
295
+ imports.push("Avatar", "AvatarFallback", "AvatarImage", "Badge");
296
+ break;
297
+ default:
298
+ imports.push("Card", "CardContent", "CardHeader", "CardTitle", "Button");
299
+ }
300
+ return [...new Set(imports)];
301
+ }
302
+ getCustomImportsForType(type) {
303
+ const imports = [];
304
+ if (type === "form") {
305
+ imports.push('import { useForm } from "react-hook-form";');
306
+ imports.push('import { zodResolver } from "@hookform/resolvers/zod";');
307
+ imports.push('import * as z from "zod";');
308
+ }
309
+ if (type === "navigation") {
310
+ imports.push('import Link from "next/link";');
311
+ imports.push('import { usePathname } from "next/navigation";');
312
+ }
313
+ if (type === "data") {
314
+ imports.push('import { useMemo } from "react";');
315
+ }
316
+ return imports;
317
+ }
318
+ generateTypeDefinitions(type, name) {
319
+ switch (type) {
320
+ case "form":
321
+ return `
322
+ /** Form data schema */
323
+ export const ${name.toLowerCase()}Schema = z.object({
324
+ email: z.string().email("Please enter a valid email address"),
325
+ password: z.string().min(8, "Password must be at least 8 characters long"),
326
+ confirmPassword: z.string().optional(),
327
+ }).refine((data) => {
328
+ if (data.confirmPassword !== undefined) {
329
+ return data.password === data.confirmPassword;
330
+ }
331
+ return true;
332
+ }, {
333
+ message: "Passwords don't match",
334
+ path: ["confirmPassword"],
335
+ });
336
+
337
+ /** Inferred form data type */
338
+ export type ${name}FormData = z.infer<typeof ${name.toLowerCase()}Schema>;
339
+
340
+ /** Form submission result */
341
+ export interface ${name}SubmissionResult {
342
+ success: boolean;
343
+ message?: string;
344
+ errors?: Record<string, string>;
345
+ }`;
346
+ case "navigation":
347
+ return `
348
+ /** Navigation item interface */
349
+ export interface NavigationItem {
350
+ /** Display label */
351
+ label: string;
352
+ /** Route path */
353
+ href: string;
354
+ /** Optional icon component */
355
+ icon?: React.ComponentType<{ className?: string }>;
356
+ /** Whether the item is disabled */
357
+ disabled?: boolean;
358
+ /** Nested items for dropdowns */
359
+ children?: NavigationItem[];
360
+ }`;
361
+ case "data":
362
+ return `
363
+ /** Generic data row interface */
364
+ export interface DataRow {
365
+ id: string | number;
366
+ [key: string]: any;
367
+ }
368
+
369
+ /** Column definition */
370
+ export interface ColumnDef<T = DataRow> {
371
+ /** Column key */
372
+ key: keyof T;
373
+ /** Display label */
374
+ label: string;
375
+ /** Custom render function */
376
+ render?: (value: any, row: T) => React.ReactNode;
377
+ /** Whether column is sortable */
378
+ sortable?: boolean;
379
+ /** Column width */
380
+ width?: string;
381
+ }
382
+
383
+ /** Sort configuration */
384
+ export interface SortConfig {
385
+ key: keyof DataRow;
386
+ direction: "asc" | "desc";
387
+ }`;
388
+ default:
389
+ return "";
390
+ }
391
+ }
392
+ generateDetailedPropsForType(type) {
393
+ switch (type) {
394
+ case "form":
395
+ return `
396
+ /** Form submission handler */
397
+ onSubmit?: (data: ${type}FormData) => Promise<${type}SubmissionResult> | ${type}SubmissionResult;
398
+ /** Loading state */
399
+ loading?: boolean;
400
+ /** Error message */
401
+ error?: string;
402
+ /** Form variant */
403
+ variant?: "default" | "login" | "signup" | "contact";
404
+ /** Initial form values */
405
+ defaultValues?: Partial<${type}FormData>;
406
+ /** Whether to show password confirmation field */
407
+ showConfirmPassword?: boolean;
408
+ /** Custom validation rules */
409
+ validationRules?: Partial<Record<keyof ${type}FormData, z.ZodSchema>>;`;
410
+ case "layout":
411
+ return `
412
+ /** Main content */
413
+ children: React.ReactNode;
414
+ /** Sidebar content */
415
+ sidebar?: React.ReactNode;
416
+ /** Header content */
417
+ header?: React.ReactNode;
418
+ /** Footer content */
419
+ footer?: React.ReactNode;
420
+ /** Layout variant */
421
+ variant?: "default" | "sidebar" | "centered" | "fullscreen";
422
+ /** Whether sidebar is collapsible */
423
+ collapsibleSidebar?: boolean;
424
+ /** Sidebar initial state */
425
+ sidebarDefaultOpen?: boolean;`;
426
+ case "card":
427
+ return `
428
+ /** Card title */
429
+ title?: string;
430
+ /** Card description */
431
+ description?: string;
432
+ /** Card content */
433
+ content?: React.ReactNode;
434
+ /** Card footer actions */
435
+ actions?: React.ReactNode;
436
+ /** Card variant */
437
+ variant?: "default" | "elevated" | "outlined" | "ghost";
438
+ /** Whether card is interactive */
439
+ interactive?: boolean;
440
+ /** Click handler for interactive cards */
441
+ onClick?: () => void;
442
+ /** Card size */
443
+ size?: "sm" | "default" | "lg";`;
444
+ case "button":
445
+ return `
446
+ /** Button variant */
447
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
448
+ /** Button size */
449
+ size?: "default" | "sm" | "lg" | "icon";
450
+ /** Whether button is disabled */
451
+ disabled?: boolean;
452
+ /** Loading state */
453
+ loading?: boolean;
454
+ /** Click handler */
455
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
456
+ /** Button content */
457
+ children: React.ReactNode;
458
+ /** Button type */
459
+ type?: "button" | "submit" | "reset";
460
+ /** ARIA label for accessibility */
461
+ "aria-label"?: string;`;
462
+ case "navigation":
463
+ return `
464
+ /** Navigation items */
465
+ items: NavigationItem[];
466
+ /** Currently active item path */
467
+ activeItem?: string;
468
+ /** Navigation orientation */
469
+ orientation?: "horizontal" | "vertical";
470
+ /** Whether to show icons */
471
+ showIcons?: boolean;
472
+ /** Custom item renderer */
473
+ renderItem?: (item: NavigationItem, isActive: boolean) => React.ReactNode;
474
+ /** Navigation variant */
475
+ variant?: "default" | "pills" | "underline";`;
476
+ case "feedback":
477
+ return `
478
+ /** Alert title */
479
+ title?: string;
480
+ /** Alert message */
481
+ message?: string;
482
+ /** Alert variant */
483
+ variant?: "default" | "destructive" | "success" | "warning";
484
+ /** Close handler */
485
+ onClose?: () => void;
486
+ /** Whether alert is dismissible */
487
+ dismissible?: boolean;
488
+ /** Auto-dismiss timeout in milliseconds */
489
+ autoDissmissAfter?: number;
490
+ /** Custom icon */
491
+ icon?: React.ReactNode;`;
492
+ case "data":
493
+ return `
494
+ /** Table data */
495
+ data: DataRow[];
496
+ /** Column definitions */
497
+ columns: ColumnDef[];
498
+ /** Whether table is loading */
499
+ loading?: boolean;
500
+ /** Whether to show pagination */
501
+ pagination?: boolean;
502
+ /** Items per page */
503
+ pageSize?: number;
504
+ /** Sort configuration */
505
+ sortable?: boolean;
506
+ /** Initial sort */
507
+ defaultSort?: SortConfig;
508
+ /** Row selection handler */
509
+ onRowSelect?: (selectedRows: DataRow[]) => void;
510
+ /** Empty state message */
511
+ emptyMessage?: string;
512
+ /** Custom row renderer */
513
+ renderRow?: (row: DataRow, index: number) => React.ReactNode;`;
514
+ default:
515
+ return `
516
+ /** Component children */
517
+ children?: React.ReactNode;
518
+ /** Component variant */
519
+ variant?: "default";`;
520
+ }
521
+ }
522
+ generateExampleProps(type) {
523
+ switch (type) {
524
+ case "form":
525
+ return `onSubmit={handleSubmit}\n * loading={false}\n * variant="default"`;
526
+ case "layout":
527
+ return `variant="sidebar"\n * header={<Header />}\n * sidebar={<Sidebar />}`;
528
+ case "card":
529
+ return `title="Card Title"\n * variant="elevated"\n * interactive`;
530
+ case "button":
531
+ return `variant="default"\n * size="lg"\n * onClick={handleClick}`;
532
+ case "navigation":
533
+ return `items={navigationItems}\n * variant="pills"\n * orientation="horizontal"`;
534
+ case "feedback":
535
+ return `variant="success"\n * title="Success"\n * dismissible`;
536
+ case "data":
537
+ return `data={tableData}\n * columns={columns}\n * pagination`;
538
+ default:
539
+ return `variant="default"`;
540
+ }
541
+ }
542
+ generateEnhancedPropsDestructuring(type) {
543
+ switch (type) {
544
+ case "form":
545
+ return `
546
+ onSubmit,
547
+ loading = false,
548
+ error,
549
+ variant = "default",
550
+ defaultValues,
551
+ showConfirmPassword = false,
552
+ validationRules,`;
553
+ case "layout":
554
+ return `
555
+ children,
556
+ sidebar,
557
+ header,
558
+ footer,
559
+ variant = "default",
560
+ collapsibleSidebar = false,
561
+ sidebarDefaultOpen = true,`;
562
+ case "card":
563
+ return `
564
+ title,
565
+ description,
566
+ content,
567
+ actions,
568
+ variant = "default",
569
+ interactive = false,
570
+ onClick,
571
+ size = "default",`;
572
+ case "button":
573
+ return `
574
+ variant = "default",
575
+ size = "default",
576
+ disabled = false,
577
+ loading = false,
578
+ onClick,
579
+ children,
580
+ type = "button",
581
+ "aria-label": ariaLabel,`;
582
+ case "navigation":
583
+ return `
584
+ items,
585
+ activeItem,
586
+ orientation = "horizontal",
587
+ showIcons = true,
588
+ renderItem,
589
+ variant = "default",`;
590
+ case "feedback":
591
+ return `
592
+ title,
593
+ message,
594
+ variant = "default",
595
+ onClose,
596
+ dismissible = false,
597
+ autoDissmissAfter,
598
+ icon,`;
599
+ case "data":
600
+ return `
601
+ data,
602
+ columns,
603
+ loading = false,
604
+ pagination = false,
605
+ pageSize = 10,
606
+ sortable = false,
607
+ defaultSort,
608
+ onRowSelect,
609
+ emptyMessage = "No data available",
610
+ renderRow,`;
611
+ default:
612
+ return `
613
+ children,
614
+ variant = "default",`;
615
+ }
616
+ }
617
+ generateProductionComponentLogic(type, actionFunctions, componentName) {
618
+ const logic = [];
619
+ if (type === "form") {
620
+ logic.push(`
621
+ const [isSubmitting, setIsSubmitting] = useState(false);
622
+
623
+ const form = useForm<${componentName}FormData>({
624
+ resolver: zodResolver(${componentName.toLowerCase()}Schema),
625
+ defaultValues: defaultValues || {
626
+ email: "",
627
+ password: "",
628
+ ...(showConfirmPassword && { confirmPassword: "" }),
629
+ },
630
+ });
631
+
632
+ const handleFormSubmit = useCallback(async (values: ${componentName}FormData) => {
633
+ if (!onSubmit) return;
634
+
635
+ setIsSubmitting(true);
636
+ try {
637
+ const result = await onSubmit(values);
638
+ if (result.success) {
639
+ form.reset();
640
+ } else if (result.errors) {
641
+ Object.entries(result.errors).forEach(([field, message]) => {
642
+ form.setError(field as keyof ${componentName}FormData, { message });
643
+ });
644
+ }
645
+ } catch (error) {
646
+ console.error("Form submission error:", error);
647
+ form.setError("root", { message: "An unexpected error occurred" });
648
+ } finally {
649
+ setIsSubmitting(false);
650
+ }
651
+ }, [onSubmit, form]);`);
652
+ }
653
+ if (type === "navigation") {
654
+ logic.push(`
655
+ const pathname = usePathname();
656
+ const [openDropdowns, setOpenDropdowns] = useState<Set<string>>(new Set());
657
+
658
+ const currentActiveItem = useMemo(() => {
659
+ return activeItem || pathname;
660
+ }, [activeItem, pathname]);
661
+
662
+ const toggleDropdown = useCallback((itemLabel: string) => {
663
+ setOpenDropdowns(prev => {
664
+ const newSet = new Set(prev);
665
+ if (newSet.has(itemLabel)) {
666
+ newSet.delete(itemLabel);
667
+ } else {
668
+ newSet.add(itemLabel);
669
+ }
670
+ return newSet;
671
+ });
672
+ }, []);`);
673
+ }
674
+ if (type === "data") {
675
+ logic.push(`
676
+ const [currentPage, setCurrentPage] = useState(1);
677
+ const [sortConfig, setSortConfig] = useState<SortConfig | null>(defaultSort || null);
678
+ const [selectedRows, setSelectedRows] = useState<Set<string | number>>(new Set());
679
+
680
+ const sortedData = useMemo(() => {
681
+ if (!sortConfig) return data;
682
+
683
+ return [...data].sort((a, b) => {
684
+ const aValue = a[sortConfig.key];
685
+ const bValue = b[sortConfig.key];
686
+
687
+ if (aValue < bValue) return sortConfig.direction === "asc" ? -1 : 1;
688
+ if (aValue > bValue) return sortConfig.direction === "asc" ? 1 : -1;
689
+ return 0;
690
+ });
691
+ }, [data, sortConfig]);
692
+
693
+ const paginatedData = useMemo(() => {
694
+ if (!pagination) return sortedData;
695
+
696
+ const startIndex = (currentPage - 1) * pageSize;
697
+ return sortedData.slice(startIndex, startIndex + pageSize);
698
+ }, [sortedData, pagination, currentPage, pageSize]);
699
+
700
+ const handleSort = useCallback((key: keyof DataRow) => {
701
+ if (!sortable) return;
702
+
703
+ setSortConfig(prevSort => {
704
+ if (prevSort?.key === key) {
705
+ return {
706
+ key,
707
+ direction: prevSort.direction === "asc" ? "desc" : "asc"
708
+ };
709
+ }
710
+ return { key, direction: "asc" };
711
+ });
712
+ }, [sortable]);
713
+
714
+ const handleRowSelection = useCallback((rowId: string | number) => {
715
+ setSelectedRows(prev => {
716
+ const newSet = new Set(prev);
717
+ if (newSet.has(rowId)) {
718
+ newSet.delete(rowId);
719
+ } else {
720
+ newSet.add(rowId);
721
+ }
722
+
723
+ if (onRowSelect) {
724
+ const selectedData = data.filter(row => newSet.has(row.id));
725
+ onRowSelect(selectedData);
726
+ }
727
+
728
+ return newSet;
729
+ });
730
+ }, [data, onRowSelect]);`);
731
+ }
732
+ if (type === "feedback" && logic.length === 0) {
733
+ logic.push(`
734
+ useEffect(() => {
735
+ if (autoDissmissAfter && onClose) {
736
+ const timer = setTimeout(onClose, autoDissmissAfter);
737
+ return () => clearTimeout(timer);
738
+ }
739
+ }, [autoDissmissAfter, onClose]);`);
740
+ }
741
+ return logic.join("\n");
742
+ }
743
+ generateAccessibleComponentJSX(type, name, shadcnImports) {
744
+ switch (type) {
745
+ case "form":
746
+ return `<Form {...form}>
747
+ <form
748
+ onSubmit={form.handleSubmit(handleFormSubmit)}
749
+ className={cn("space-y-6", className)}
750
+ noValidate
751
+ {...props}
752
+ >
753
+ <FormField
754
+ control={form.control}
755
+ name="email"
756
+ render={({ field }) => (
757
+ <FormItem>
758
+ <FormLabel>Email Address</FormLabel>
759
+ <FormControl>
760
+ <Input
761
+ type="email"
762
+ placeholder="Enter your email address"
763
+ autoComplete="email"
764
+ aria-describedby="email-error"
765
+ {...field}
766
+ />
767
+ </FormControl>
768
+ <FormMessage id="email-error" />
769
+ </FormItem>
770
+ )}
771
+ />
772
+
773
+ <FormField
774
+ control={form.control}
775
+ name="password"
776
+ render={({ field }) => (
777
+ <FormItem>
778
+ <FormLabel>Password</FormLabel>
779
+ <FormControl>
780
+ <Input
781
+ type="password"
782
+ placeholder="Enter your password"
783
+ autoComplete="current-password"
784
+ aria-describedby="password-error"
785
+ {...field}
786
+ />
787
+ </FormControl>
788
+ <FormMessage id="password-error" />
789
+ </FormItem>
790
+ )}
791
+ />
792
+
793
+ {showConfirmPassword && (
794
+ <FormField
795
+ control={form.control}
796
+ name="confirmPassword"
797
+ render={({ field }) => (
798
+ <FormItem>
799
+ <FormLabel>Confirm Password</FormLabel>
800
+ <FormControl>
801
+ <Input
802
+ type="password"
803
+ placeholder="Confirm your password"
804
+ autoComplete="new-password"
805
+ aria-describedby="confirm-password-error"
806
+ {...field}
807
+ />
808
+ </FormControl>
809
+ <FormMessage id="confirm-password-error" />
810
+ </FormItem>
811
+ )}
812
+ />
813
+ )}
814
+
815
+ {error && (
816
+ <Alert variant="destructive">
817
+ <AlertDescription>{error}</AlertDescription>
818
+ </Alert>
819
+ )}
820
+
821
+ {form.formState.errors.root && (
822
+ <Alert variant="destructive">
823
+ <AlertDescription>{form.formState.errors.root.message}</AlertDescription>
824
+ </Alert>
825
+ )}
826
+
827
+ <Button
828
+ type="submit"
829
+ disabled={loading || isSubmitting}
830
+ className="w-full"
831
+ aria-describedby={loading || isSubmitting ? "submit-loading" : undefined}
832
+ >
833
+ {loading || isSubmitting ? (
834
+ <>
835
+ <span className="sr-only" id="submit-loading">Loading...</span>
836
+ <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
837
+ Submitting...
838
+ </>
839
+ ) : (
840
+ "Submit"
841
+ )}
842
+ </Button>
843
+ </form>
844
+ </Form>`;
845
+ case "layout":
846
+ return `<div className={cn("min-h-screen flex flex-col", className)} {...props}>
847
+ {header && (
848
+ <header
849
+ className="border-b bg-background sticky top-0 z-40"
850
+ role="banner"
851
+ >
852
+ <div className="container mx-auto px-4 py-4">
853
+ {header}
854
+ </div>
855
+ </header>
856
+ )}
857
+
858
+ <div className="flex-1 flex">
859
+ {sidebar && (
860
+ <aside
861
+ className={cn(
862
+ "border-r bg-background",
863
+ variant === "sidebar" ? "w-64" : "w-auto"
864
+ )}
865
+ role="complementary"
866
+ aria-label="Sidebar navigation"
867
+ >
868
+ <div className="p-4">
869
+ {sidebar}
870
+ </div>
871
+ </aside>
872
+ )}
873
+
874
+ <main
875
+ className="flex-1 focus:outline-none"
876
+ role="main"
877
+ tabIndex={-1}
878
+ >
879
+ <div className={cn(
880
+ "container mx-auto px-4 py-8",
881
+ variant === "centered" && "max-w-4xl",
882
+ variant === "fullscreen" && "max-w-none px-0 py-0"
883
+ )}>
884
+ {children}
885
+ </div>
886
+ </main>
887
+ </div>
888
+
889
+ {footer && (
890
+ <footer
891
+ className="border-t bg-background"
892
+ role="contentinfo"
893
+ >
894
+ <div className="container mx-auto px-4 py-4 text-center text-sm text-muted-foreground">
895
+ {footer}
896
+ </div>
897
+ </footer>
898
+ )}
899
+ </div>`;
900
+ case "card":
901
+ return `<Card
902
+ className={cn(
903
+ "transition-all duration-200",
904
+ variant === "elevated" && "shadow-lg hover:shadow-xl",
905
+ variant === "outlined" && "border-2",
906
+ variant === "ghost" && "border-none shadow-none",
907
+ interactive && "cursor-pointer hover:bg-accent/50",
908
+ size === "sm" && "p-4",
909
+ size === "lg" && "p-8",
910
+ className
911
+ )}
912
+ onClick={interactive ? onClick : undefined}
913
+ role={interactive ? "button" : undefined}
914
+ tabIndex={interactive ? 0 : undefined}
915
+ onKeyDown={interactive ? (e) => {
916
+ if (e.key === "Enter" || e.key === " ") {
917
+ e.preventDefault();
918
+ onClick?.();
919
+ }
920
+ } : undefined}
921
+ {...props}
922
+ >
923
+ {(title || description) && (
924
+ <CardHeader className={size === "sm" ? "pb-3" : undefined}>
925
+ {title && (
926
+ <CardTitle className={size === "sm" ? "text-base" : "text-lg"}>
927
+ {title}
928
+ </CardTitle>
929
+ )}
930
+ {description && (
931
+ <CardDescription>{description}</CardDescription>
932
+ )}
933
+ </CardHeader>
934
+ )}
935
+
936
+ {content && (
937
+ <CardContent className={cn(
938
+ size === "sm" && "pt-0 pb-3",
939
+ !title && !description && "pt-6"
940
+ )}>
941
+ {content}
942
+ </CardContent>
943
+ )}
944
+
945
+ {actions && (
946
+ <CardFooter className={cn(
947
+ "flex justify-end space-x-2",
948
+ size === "sm" && "pt-0"
949
+ )}>
950
+ {actions}
951
+ </CardFooter>
952
+ )}
953
+ </Card>`;
954
+ case "button":
955
+ return `<Button
956
+ variant={variant}
957
+ size={size}
958
+ disabled={disabled || loading}
959
+ onClick={onClick}
960
+ type={type}
961
+ className={cn(loading && "cursor-wait", className)}
962
+ aria-label={ariaLabel}
963
+ aria-disabled={disabled || loading}
964
+ {...props}
965
+ >
966
+ {loading ? (
967
+ <>
968
+ <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-current mr-2" />
969
+ <span className="sr-only">Loading...</span>
970
+ Loading...
971
+ </>
972
+ ) : (
973
+ children
974
+ )}
975
+ </Button>`;
976
+ case "navigation":
977
+ return `<NavigationMenu
978
+ className={cn("", className)}
979
+ orientation={orientation}
980
+ {...props}
981
+ >
982
+ <NavigationMenuList className={cn(
983
+ orientation === "vertical" && "flex-col space-x-0 space-y-1"
984
+ )}>
985
+ {items.map((item, index) => (
986
+ <NavigationMenuItem key={item.href || index}>
987
+ {item.children ? (
988
+ <>
989
+ <NavigationMenuTrigger
990
+ className={cn(
991
+ variant === "pills" && "rounded-full",
992
+ variant === "underline" && "border-b-2 border-transparent data-[state=open]:border-primary"
993
+ )}
994
+ onClick={() => toggleDropdown(item.label)}
995
+ aria-expanded={openDropdowns.has(item.label)}
996
+ >
997
+ {showIcons && item.icon && (
998
+ <item.icon className="w-4 h-4 mr-2" />
999
+ )}
1000
+ {item.label}
1001
+ </NavigationMenuTrigger>
1002
+ <NavigationMenuContent>
1003
+ <div className="grid gap-3 p-4 w-[400px]">
1004
+ {item.children.map((child, childIndex) => (
1005
+ <NavigationMenuLink
1006
+ key={child.href || childIndex}
1007
+ asChild
1008
+ >
1009
+ <Link
1010
+ href={child.href}
1011
+ className={cn(
1012
+ "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
1013
+ child.disabled && "pointer-events-none opacity-50"
1014
+ )}
1015
+ >
1016
+ <div className="text-sm font-medium leading-none">
1017
+ {child.label}
1018
+ </div>
1019
+ </Link>
1020
+ </NavigationMenuLink>
1021
+ ))}
1022
+ </div>
1023
+ </NavigationMenuContent>
1024
+ </>
1025
+ ) : (
1026
+ <NavigationMenuLink
1027
+ asChild
1028
+ className={cn(
1029
+ currentActiveItem === item.href && "bg-accent text-accent-foreground",
1030
+ variant === "pills" && "rounded-full",
1031
+ variant === "underline" && currentActiveItem === item.href && "border-b-2 border-primary"
1032
+ )}
1033
+ >
1034
+ <Link
1035
+ href={item.href}
1036
+ className={cn(
1037
+ "block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
1038
+ item.disabled && "pointer-events-none opacity-50"
1039
+ )}
1040
+ >
1041
+ {showIcons && item.icon && (
1042
+ <item.icon className="w-4 h-4 mr-2 inline-block" />
1043
+ )}
1044
+ {item.label}
1045
+ </Link>
1046
+ </NavigationMenuLink>
1047
+ )}
1048
+ </NavigationMenuItem>
1049
+ ))}
1050
+ </NavigationMenuList>
1051
+ </NavigationMenu>`;
1052
+ case "feedback":
1053
+ return `<Alert
1054
+ variant={variant}
1055
+ className={cn("relative", className)}
1056
+ role={variant === "destructive" ? "alert" : "status"}
1057
+ aria-live={variant === "destructive" ? "assertive" : "polite"}
1058
+ {...props}
1059
+ >
1060
+ {icon || (
1061
+ <div className="w-4 h-4">
1062
+ {variant === "success" && "✓"}
1063
+ {variant === "destructive" && "⚠"}
1064
+ {variant === "warning" && "⚠"}
1065
+ </div>
1066
+ )}
1067
+
1068
+ <div className="flex-1">
1069
+ {title && <AlertTitle>{title}</AlertTitle>}
1070
+ {message && <AlertDescription>{message}</AlertDescription>}
1071
+ </div>
1072
+
1073
+ {dismissible && onClose && (
1074
+ <Button
1075
+ variant="ghost"
1076
+ size="sm"
1077
+ onClick={onClose}
1078
+ className="absolute top-2 right-2 h-6 w-6 p-0"
1079
+ aria-label="Close alert"
1080
+ >
1081
+ ×
1082
+ </Button>
1083
+ )}
1084
+ </Alert>`;
1085
+ case "data":
1086
+ return `<div className={cn("space-y-4", className)} {...props}>
1087
+ {loading ? (
1088
+ <div className="flex items-center justify-center p-8">
1089
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
1090
+ <span className="sr-only">Loading data...</span>
1091
+ </div>
1092
+ ) : (
1093
+ <>
1094
+ <div className="rounded-md border overflow-hidden">
1095
+ <Table>
1096
+ <TableHeader>
1097
+ <TableRow>
1098
+ {onRowSelect && (
1099
+ <TableHead className="w-12">
1100
+ <span className="sr-only">Select row</span>
1101
+ </TableHead>
1102
+ )}
1103
+ {columns.map((column) => (
1104
+ <TableHead
1105
+ key={String(column.key)}
1106
+ className={cn(
1107
+ sortable && column.sortable && "cursor-pointer hover:bg-muted",
1108
+ column.width && \`w-[\${column.width}]\`
1109
+ )}
1110
+ onClick={() => column.sortable && handleSort(column.key)}
1111
+ role={column.sortable ? "button" : undefined}
1112
+ tabIndex={column.sortable ? 0 : undefined}
1113
+ onKeyDown={column.sortable ? (e) => {
1114
+ if (e.key === "Enter" || e.key === " ") {
1115
+ e.preventDefault();
1116
+ handleSort(column.key);
1117
+ }
1118
+ } : undefined}
1119
+ >
1120
+ <div className="flex items-center space-x-2">
1121
+ <span>{column.label}</span>
1122
+ {sortable && column.sortable && sortConfig?.key === column.key && (
1123
+ <span className="text-xs">
1124
+ {sortConfig.direction === "asc" ? "↑" : "↓"}
1125
+ </span>
1126
+ )}
1127
+ </div>
1128
+ </TableHead>
1129
+ ))}
1130
+ </TableRow>
1131
+ </TableHeader>
1132
+ <TableBody>
1133
+ {paginatedData.length === 0 ? (
1134
+ <TableRow>
1135
+ <TableCell
1136
+ colSpan={columns.length + (onRowSelect ? 1 : 0)}
1137
+ className="text-center py-8 text-muted-foreground"
1138
+ >
1139
+ {emptyMessage}
1140
+ </TableCell>
1141
+ </TableRow>
1142
+ ) : (
1143
+ paginatedData.map((row, index) => (
1144
+ renderRow ? renderRow(row, index) : (
1145
+ <TableRow
1146
+ key={row.id}
1147
+ className={cn(
1148
+ onRowSelect && selectedRows.has(row.id) && "bg-muted"
1149
+ )}
1150
+ >
1151
+ {onRowSelect && (
1152
+ <TableCell>
1153
+ <Checkbox
1154
+ checked={selectedRows.has(row.id)}
1155
+ onCheckedChange={() => handleRowSelection(row.id)}
1156
+ aria-label={\`Select row \${index + 1}\`}
1157
+ />
1158
+ </TableCell>
1159
+ )}
1160
+ {columns.map((column) => (
1161
+ <TableCell key={String(column.key)}>
1162
+ {column.render
1163
+ ? column.render(row[column.key], row)
1164
+ : String(row[column.key] || "")
1165
+ }
1166
+ </TableCell>
1167
+ ))}
1168
+ </TableRow>
1169
+ )
1170
+ ))
1171
+ )}
1172
+ </TableBody>
1173
+ </Table>
1174
+ </div>
1175
+
1176
+ {pagination && data.length > pageSize && (
1177
+ <div className="flex items-center justify-between">
1178
+ <p className="text-sm text-muted-foreground">
1179
+ Showing {((currentPage - 1) * pageSize) + 1} to {Math.min(currentPage * pageSize, data.length)} of {data.length} results
1180
+ </p>
1181
+ <div className="flex items-center space-x-2">
1182
+ <Button
1183
+ variant="outline"
1184
+ size="sm"
1185
+ onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
1186
+ disabled={currentPage === 1}
1187
+ aria-label="Previous page"
1188
+ >
1189
+ Previous
1190
+ </Button>
1191
+ <Button
1192
+ variant="outline"
1193
+ size="sm"
1194
+ onClick={() => setCurrentPage(prev => prev + 1)}
1195
+ disabled={currentPage * pageSize >= data.length}
1196
+ aria-label="Next page"
1197
+ >
1198
+ Next
1199
+ </Button>
1200
+ </div>
1201
+ </div>
1202
+ )}
1203
+ </>
1204
+ )}
1205
+ </div>`;
1206
+ default:
1207
+ return `<Card className={cn("p-4", className)} {...props}>
1208
+ <CardHeader>
1209
+ <CardTitle>${name}</CardTitle>
1210
+ </CardHeader>
1211
+ <CardContent>
1212
+ <p className="text-sm text-muted-foreground">
1213
+ This is a production-ready ${type} component with accessibility features and TypeScript support.
1214
+ </p>
1215
+ {children}
1216
+ </CardContent>
1217
+ </Card>`;
1218
+ }
1219
+ }
1220
+ generateProductionActionFunctions(actionFunctions, componentName, type) {
1221
+ if (actionFunctions.length === 0)
1222
+ return "";
1223
+ const functions = actionFunctions.map((func) => {
1224
+ switch (func) {
1225
+ case "handleSubmit":
1226
+ return type === "form"
1227
+ ? `// Form submission is handled within the component`
1228
+ : `
1229
+ /**
1230
+ * Handles form submission with validation and error handling
1231
+ * @param data - Form data to submit
1232
+ * @returns Promise with submission result
1233
+ */
1234
+ export async function handleSubmit(data: Record<string, any>): Promise<{ success: boolean; message?: string }> {
1235
+ try {
1236
+ // TODO: Implement actual submission logic
1237
+ console.log("Submitting data:", data);
1238
+
1239
+ // Simulate API call
1240
+ await new Promise(resolve => setTimeout(resolve, 1000));
1241
+
1242
+ return { success: true, message: "Data submitted successfully" };
1243
+ } catch (error) {
1244
+ console.error("Submission error:", error);
1245
+ return { success: false, message: "Failed to submit data" };
1246
+ }
1247
+ }`;
1248
+ case "handleLogin":
1249
+ return `
1250
+ /**
1251
+ * Handles user authentication with proper validation
1252
+ * @param email - User email address
1253
+ * @param password - User password
1254
+ * @returns Promise with authentication result
1255
+ */
1256
+ export async function handleLogin(email: string, password: string): Promise<{
1257
+ success: boolean;
1258
+ user?: { id: string; email: string; name: string };
1259
+ error?: string
1260
+ }> {
1261
+ try {
1262
+ // TODO: Implement actual authentication logic
1263
+ const response = await fetch("/api/auth/login", {
1264
+ method: "POST",
1265
+ headers: { "Content-Type": "application/json" },
1266
+ body: JSON.stringify({ email, password }),
1267
+ });
1268
+
1269
+ if (!response.ok) {
1270
+ throw new Error("Authentication failed");
1271
+ }
1272
+
1273
+ const result = await response.json();
1274
+ return { success: true, user: result.user };
1275
+ } catch (error) {
1276
+ console.error("Login error:", error);
1277
+ return { success: false, error: "Invalid credentials" };
1278
+ }
1279
+ }`;
1280
+ case "validateEmail":
1281
+ return `
1282
+ /**
1283
+ * Validates email address format and availability
1284
+ * @param email - Email address to validate
1285
+ * @returns Validation result with detailed feedback
1286
+ */
1287
+ export async function validateEmail(email: string): Promise<{
1288
+ isValid: boolean;
1289
+ isAvailable?: boolean;
1290
+ message?: string;
1291
+ }> {
1292
+ const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
1293
+
1294
+ if (!emailRegex.test(email)) {
1295
+ return { isValid: false, message: "Please enter a valid email address" };
1296
+ }
1297
+
1298
+ try {
1299
+ // TODO: Check email availability
1300
+ const response = await fetch(\`/api/auth/check-email?email=\${encodeURIComponent(email)}\`);
1301
+ const { available } = await response.json();
1302
+
1303
+ return {
1304
+ isValid: true,
1305
+ isAvailable: available,
1306
+ message: available ? "Email is available" : "Email is already registered"
1307
+ };
1308
+ } catch (error) {
1309
+ console.error("Email validation error:", error);
1310
+ return { isValid: true, message: "Unable to verify email availability" };
1311
+ }
1312
+ }`;
1313
+ default:
1314
+ return `
1315
+ /**
1316
+ * ${func} - Custom action function
1317
+ * TODO: Implement ${func} logic with proper TypeScript types and error handling
1318
+ */
1319
+ export async function ${func}(...args: any[]): Promise<{ success: boolean; data?: any; error?: string }> {
1320
+ try {
1321
+ console.log("${func} called with args:", args);
1322
+
1323
+ // TODO: Implement actual logic
1324
+ await new Promise(resolve => setTimeout(resolve, 100));
1325
+
1326
+ return { success: true };
1327
+ } catch (error) {
1328
+ console.error("${func} error:", error);
1329
+ return { success: false, error: "Operation failed" };
1330
+ }
1331
+ }`;
1332
+ }
1333
+ });
1334
+ return functions.join("\n");
1335
+ }
1336
+ extractDependencies(code) {
1337
+ const dependencies = [];
1338
+ // Extract import statements
1339
+ const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
1340
+ let match;
1341
+ while ((match = importRegex.exec(code)) !== null) {
1342
+ const importPath = match[1];
1343
+ if (importPath.startsWith("@/") ||
1344
+ importPath.startsWith("./") ||
1345
+ importPath.startsWith("../")) {
1346
+ dependencies.push(importPath);
1347
+ }
1348
+ }
1349
+ // Extract shadcn/ui component dependencies
1350
+ const shadcnComponents = this.extractShadcnComponents(code);
1351
+ shadcnComponents.forEach((comp) => {
1352
+ dependencies.push(`@/components/ui/${comp.toLowerCase()}`);
1353
+ });
1354
+ // Remove duplicates
1355
+ return [...new Set(dependencies)];
1356
+ }
1357
+ extractShadcnComponents(code) {
1358
+ const components = [];
1359
+ // Check for shadcn/ui component usage
1360
+ Object.values(SHADCN_COMPONENTS)
1361
+ .flat()
1362
+ .forEach((comp) => {
1363
+ if (code.includes(comp)) {
1364
+ components.push(comp);
1365
+ }
1366
+ });
1367
+ return [...new Set(components)];
1368
+ }
1369
+ calculateQualityScore(code) {
1370
+ let score = 70; // Base score
1371
+ // Bonus for using shadcn/ui components
1372
+ const shadcnComponents = this.extractShadcnComponents(code);
1373
+ score += Math.min(shadcnComponents.length * 3, 15);
1374
+ // Bonus for proper TypeScript usage
1375
+ if (code.includes("interface") && code.includes("Props"))
1376
+ score += 10;
1377
+ if (code.includes("export type") || code.includes("export interface"))
1378
+ score += 5;
1379
+ // Bonus for React patterns and hooks
1380
+ if (code.includes("useState") || code.includes("useEffect"))
1381
+ score += 5;
1382
+ if (code.includes("useCallback") || code.includes("useMemo"))
1383
+ score += 5;
1384
+ // Bonus for accessibility features
1385
+ if (code.includes("aria-") || code.includes("role="))
1386
+ score += 10;
1387
+ if (code.includes("tabIndex") || code.includes("onKeyDown"))
1388
+ score += 5;
1389
+ // Bonus for error handling and validation
1390
+ if (code.includes("try") && code.includes("catch"))
1391
+ score += 5;
1392
+ if (code.includes("zodResolver") || code.includes("z.object"))
1393
+ score += 5;
1394
+ // Bonus for semantic HTML and proper structure
1395
+ if (code.includes("role=") && code.includes("aria-"))
1396
+ score += 5;
1397
+ if (code.includes("sr-only"))
1398
+ score += 3;
1399
+ // Bonus for production patterns
1400
+ if (code.includes("useCallback") && code.includes("useMemo"))
1401
+ score += 5;
1402
+ if (code.includes("React.memo") || code.includes("forwardRef"))
1403
+ score += 3;
1404
+ // Cap at 100
1405
+ return Math.min(score, 100);
1406
+ }
1407
+ generateComponentName(description) {
1408
+ // Convert description to PascalCase component name
1409
+ return description
1410
+ .split(" ")
1411
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
1412
+ .join("")
1413
+ .replace(/[^a-zA-Z0-9]/g, "");
1414
+ }
1415
+ async generateWithXAI(component, group, options) {
1416
+ try {
1417
+ const xaiApiKey = process.env.XAI_API_KEY;
1418
+ if (!xaiApiKey) {
1419
+ throw new Error("X.AI API key not found");
1420
+ }
1421
+ const { XAIClient } = await Promise.resolve().then(() => __importStar(require("../../utils/xaiClient")));
1422
+ const xaiClient = new XAIClient({
1423
+ apiKey: xaiApiKey,
1424
+ temperature: options.temperature || 0.6,
1425
+ maxTokens: options.maxTokens || 8000,
1426
+ });
1427
+ return await xaiClient.generateComponent(component, group?.name || "general");
1428
+ }
1429
+ catch (error) {
1430
+ console.warn("X.AI generation failed, falling back to local generation:", error);
1431
+ // Fallback to local generation
1432
+ return this.generateProductionReadyComponent(component, group, {
1433
+ ...options,
1434
+ useXAI: false,
1435
+ });
1436
+ }
1437
+ }
1438
+ }
1439
+ exports.CodeGenSubAgent = CodeGenSubAgent;
1440
+ //# sourceMappingURL=CodeGenSubAgent.js.map