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