@codebakers/mcp 5.4.3 → 5.4.4

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 (37) hide show
  1. package/INSTALL.md +221 -221
  2. package/LICENSE +21 -21
  3. package/README.md +412 -412
  4. package/dist/cli.js +29 -29
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +11 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/tools/analyze-mockups.js +37 -37
  9. package/dist/tools/autonomous-build.d.ts +18 -18
  10. package/dist/tools/autonomous-build.js +286 -286
  11. package/dist/tools/check-gate.js +6 -6
  12. package/dist/tools/check-scope.js +10 -10
  13. package/dist/tools/enforce-feature.js +15 -15
  14. package/dist/tools/fix-commit.js +18 -18
  15. package/dist/tools/fix-mockups.js +191 -191
  16. package/dist/tools/generate-api-route.js +155 -155
  17. package/dist/tools/generate-chatbot.js +306 -306
  18. package/dist/tools/generate-component.js +117 -117
  19. package/dist/tools/generate-docs.js +525 -525
  20. package/dist/tools/generate-e2e-tests.js +19 -19
  21. package/dist/tools/generate-migration.js +22 -22
  22. package/dist/tools/generate-schema.js +37 -37
  23. package/dist/tools/generate-spec.js +38 -38
  24. package/dist/tools/generate-store-contracts.js +42 -42
  25. package/dist/tools/generate-store.js +109 -109
  26. package/dist/tools/generate-unit-tests.js +57 -57
  27. package/dist/tools/map-dependencies.js +45 -45
  28. package/dist/tools/run-interview.js +142 -142
  29. package/dist/tools/setup-github.js +8 -8
  30. package/dist/tools/setup-supabase.js +8 -8
  31. package/dist/tools/setup-vercel.js +8 -8
  32. package/dist/tools/start.d.ts +12 -0
  33. package/dist/tools/start.d.ts.map +1 -0
  34. package/dist/tools/start.js +252 -0
  35. package/dist/tools/start.js.map +1 -0
  36. package/dist/tools/validate-mockups.js +19 -19
  37. package/package.json +50 -50
@@ -173,324 +173,324 @@ async function indexPages(dir, routePath, pages) {
173
173
  }
174
174
  }
175
175
  async function generateChatbotComponent(cwd, knowledge, position) {
176
- const component = `'use client';
177
-
178
- import { useState, useRef, useEffect } from 'react';
179
-
180
- interface Message {
181
- role: 'user' | 'assistant';
182
- content: string;
183
- }
184
-
185
- export default function HelpChatbot() {
186
- const [isOpen, setIsOpen] = useState(false);
187
- const [messages, setMessages] = useState<Message[]>([
188
- {
189
- role: 'assistant',
190
- content: 'Hi! I\\'m your AI assistant. I know everything about this app and can help you navigate features, answer questions, or troubleshoot issues. What can I help you with?'
191
- }
192
- ]);
193
- const [input, setInput] = useState('');
194
- const [isLoading, setIsLoading] = useState(false);
195
- const messagesEndRef = useRef<HTMLDivElement>(null);
196
-
197
- useEffect(() => {
198
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
199
- }, [messages]);
200
-
201
- const sendMessage = async () => {
202
- if (!input.trim() || isLoading) return;
203
-
204
- const userMessage: Message = { role: 'user', content: input };
205
- setMessages(prev => [...prev, userMessage]);
206
- setInput('');
207
- setIsLoading(true);
208
-
209
- try {
210
- const response = await fetch('/api/chatbot', {
211
- method: 'POST',
212
- headers: { 'Content-Type': 'application/json' },
213
- body: JSON.stringify({ message: input })
214
- });
215
-
216
- const data = await response.json();
217
-
218
- const assistantMessage: Message = {
219
- role: 'assistant',
220
- content: data.response || 'Sorry, I couldn\\'t process that request.'
221
- };
222
-
223
- setMessages(prev => [...prev, assistantMessage]);
224
- } catch (error) {
225
- const errorMessage: Message = {
226
- role: 'assistant',
227
- content: 'Sorry, I encountered an error. Please try again.'
228
- };
229
- setMessages(prev => [...prev, errorMessage]);
230
- } finally {
231
- setIsLoading(false);
232
- }
233
- };
234
-
235
- const handleKeyPress = (e: React.KeyboardEvent) => {
236
- if (e.key === 'Enter' && !e.shiftKey) {
237
- e.preventDefault();
238
- sendMessage();
239
- }
240
- };
241
-
242
- const positionClasses = {
243
- 'bottom-right': 'bottom-4 right-4',
244
- 'bottom-left': 'bottom-4 left-4',
245
- 'sidebar': 'top-20 right-4'
246
- };
247
-
248
- return (
249
- <>
250
- {/* Chat Button */}
251
- {!isOpen && (
252
- <button
253
- onClick={() => setIsOpen(true)}
254
- className={\`fixed \${positionClasses['${position}']} z-50 bg-blue-600 text-white rounded-full p-4 shadow-lg hover:bg-blue-700 transition-all\`}
255
- aria-label="Open help chat"
256
- >
257
- <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
258
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
259
- </svg>
260
- </button>
261
- )}
262
-
263
- {/* Chat Window */}
264
- {isOpen && (
265
- <div className={\`fixed \${positionClasses['${position}']} z-50 w-96 h-[500px] bg-white border border-gray-200 rounded-lg shadow-xl flex flex-col\`}>
266
- {/* Header */}
267
- <div className="flex items-center justify-between p-4 border-b bg-blue-600 text-white rounded-t-lg">
268
- <div className="flex items-center gap-2">
269
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
270
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
271
- </svg>
272
- <h3 className="font-semibold">Help Assistant</h3>
273
- </div>
274
- <button
275
- onClick={() => setIsOpen(false)}
276
- className="hover:bg-blue-700 rounded p-1 transition-colors"
277
- aria-label="Close chat"
278
- >
279
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
280
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
281
- </svg>
282
- </button>
283
- </div>
284
-
285
- {/* Messages */}
286
- <div className="flex-1 overflow-y-auto p-4 space-y-4">
287
- {messages.map((message, index) => (
288
- <div
289
- key={index}
290
- className={\`flex \${message.role === 'user' ? 'justify-end' : 'justify-start'}\`}
291
- >
292
- <div
293
- className={\`max-w-[80%] rounded-lg px-4 py-2 \${
294
- message.role === 'user'
295
- ? 'bg-blue-600 text-white'
296
- : 'bg-gray-100 text-gray-900'
297
- }\`}
298
- >
299
- <p className="text-sm whitespace-pre-wrap">{message.content}</p>
300
- </div>
301
- </div>
302
- ))}
303
- {isLoading && (
304
- <div className="flex justify-start">
305
- <div className="bg-gray-100 rounded-lg px-4 py-2">
306
- <div className="flex gap-1">
307
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></div>
308
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></div>
309
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></div>
310
- </div>
311
- </div>
312
- </div>
313
- )}
314
- <div ref={messagesEndRef} />
315
- </div>
316
-
317
- {/* Input */}
318
- <div className="p-4 border-t">
319
- <div className="flex gap-2">
320
- <input
321
- type="text"
322
- value={input}
323
- onChange={(e) => setInput(e.target.value)}
324
- onKeyPress={handleKeyPress}
325
- placeholder="Ask me anything..."
326
- className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
327
- disabled={isLoading}
328
- />
329
- <button
330
- onClick={sendMessage}
331
- disabled={!input.trim() || isLoading}
332
- className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
333
- >
334
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
335
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
336
- </svg>
337
- </button>
338
- </div>
339
- </div>
340
- </div>
341
- )}
342
- </>
343
- );
344
- }
176
+ const component = `'use client';
177
+
178
+ import { useState, useRef, useEffect } from 'react';
179
+
180
+ interface Message {
181
+ role: 'user' | 'assistant';
182
+ content: string;
183
+ }
184
+
185
+ export default function HelpChatbot() {
186
+ const [isOpen, setIsOpen] = useState(false);
187
+ const [messages, setMessages] = useState<Message[]>([
188
+ {
189
+ role: 'assistant',
190
+ content: 'Hi! I\\'m your AI assistant. I know everything about this app and can help you navigate features, answer questions, or troubleshoot issues. What can I help you with?'
191
+ }
192
+ ]);
193
+ const [input, setInput] = useState('');
194
+ const [isLoading, setIsLoading] = useState(false);
195
+ const messagesEndRef = useRef<HTMLDivElement>(null);
196
+
197
+ useEffect(() => {
198
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
199
+ }, [messages]);
200
+
201
+ const sendMessage = async () => {
202
+ if (!input.trim() || isLoading) return;
203
+
204
+ const userMessage: Message = { role: 'user', content: input };
205
+ setMessages(prev => [...prev, userMessage]);
206
+ setInput('');
207
+ setIsLoading(true);
208
+
209
+ try {
210
+ const response = await fetch('/api/chatbot', {
211
+ method: 'POST',
212
+ headers: { 'Content-Type': 'application/json' },
213
+ body: JSON.stringify({ message: input })
214
+ });
215
+
216
+ const data = await response.json();
217
+
218
+ const assistantMessage: Message = {
219
+ role: 'assistant',
220
+ content: data.response || 'Sorry, I couldn\\'t process that request.'
221
+ };
222
+
223
+ setMessages(prev => [...prev, assistantMessage]);
224
+ } catch (error) {
225
+ const errorMessage: Message = {
226
+ role: 'assistant',
227
+ content: 'Sorry, I encountered an error. Please try again.'
228
+ };
229
+ setMessages(prev => [...prev, errorMessage]);
230
+ } finally {
231
+ setIsLoading(false);
232
+ }
233
+ };
234
+
235
+ const handleKeyPress = (e: React.KeyboardEvent) => {
236
+ if (e.key === 'Enter' && !e.shiftKey) {
237
+ e.preventDefault();
238
+ sendMessage();
239
+ }
240
+ };
241
+
242
+ const positionClasses = {
243
+ 'bottom-right': 'bottom-4 right-4',
244
+ 'bottom-left': 'bottom-4 left-4',
245
+ 'sidebar': 'top-20 right-4'
246
+ };
247
+
248
+ return (
249
+ <>
250
+ {/* Chat Button */}
251
+ {!isOpen && (
252
+ <button
253
+ onClick={() => setIsOpen(true)}
254
+ className={\`fixed \${positionClasses['${position}']} z-50 bg-blue-600 text-white rounded-full p-4 shadow-lg hover:bg-blue-700 transition-all\`}
255
+ aria-label="Open help chat"
256
+ >
257
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
258
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
259
+ </svg>
260
+ </button>
261
+ )}
262
+
263
+ {/* Chat Window */}
264
+ {isOpen && (
265
+ <div className={\`fixed \${positionClasses['${position}']} z-50 w-96 h-[500px] bg-white border border-gray-200 rounded-lg shadow-xl flex flex-col\`}>
266
+ {/* Header */}
267
+ <div className="flex items-center justify-between p-4 border-b bg-blue-600 text-white rounded-t-lg">
268
+ <div className="flex items-center gap-2">
269
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
270
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
271
+ </svg>
272
+ <h3 className="font-semibold">Help Assistant</h3>
273
+ </div>
274
+ <button
275
+ onClick={() => setIsOpen(false)}
276
+ className="hover:bg-blue-700 rounded p-1 transition-colors"
277
+ aria-label="Close chat"
278
+ >
279
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
280
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
281
+ </svg>
282
+ </button>
283
+ </div>
284
+
285
+ {/* Messages */}
286
+ <div className="flex-1 overflow-y-auto p-4 space-y-4">
287
+ {messages.map((message, index) => (
288
+ <div
289
+ key={index}
290
+ className={\`flex \${message.role === 'user' ? 'justify-end' : 'justify-start'}\`}
291
+ >
292
+ <div
293
+ className={\`max-w-[80%] rounded-lg px-4 py-2 \${
294
+ message.role === 'user'
295
+ ? 'bg-blue-600 text-white'
296
+ : 'bg-gray-100 text-gray-900'
297
+ }\`}
298
+ >
299
+ <p className="text-sm whitespace-pre-wrap">{message.content}</p>
300
+ </div>
301
+ </div>
302
+ ))}
303
+ {isLoading && (
304
+ <div className="flex justify-start">
305
+ <div className="bg-gray-100 rounded-lg px-4 py-2">
306
+ <div className="flex gap-1">
307
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></div>
308
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></div>
309
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></div>
310
+ </div>
311
+ </div>
312
+ </div>
313
+ )}
314
+ <div ref={messagesEndRef} />
315
+ </div>
316
+
317
+ {/* Input */}
318
+ <div className="p-4 border-t">
319
+ <div className="flex gap-2">
320
+ <input
321
+ type="text"
322
+ value={input}
323
+ onChange={(e) => setInput(e.target.value)}
324
+ onKeyPress={handleKeyPress}
325
+ placeholder="Ask me anything..."
326
+ className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
327
+ disabled={isLoading}
328
+ />
329
+ <button
330
+ onClick={sendMessage}
331
+ disabled={!input.trim() || isLoading}
332
+ className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
333
+ >
334
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
335
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
336
+ </svg>
337
+ </button>
338
+ </div>
339
+ </div>
340
+ </div>
341
+ )}
342
+ </>
343
+ );
344
+ }
345
345
  `;
346
346
  const componentPath = path.join(cwd, 'src', 'components', 'HelpChatbot.tsx');
347
347
  await fs.mkdir(path.dirname(componentPath), { recursive: true });
348
348
  await fs.writeFile(componentPath, component, 'utf-8');
349
349
  }
350
350
  async function generateKnowledgeBase(cwd, knowledge) {
351
- const knowledgeFile = `// Auto-generated knowledge base for AI chatbot
352
- // This file contains indexed information about the app
353
-
354
- export const appKnowledge = ${JSON.stringify(knowledge, null, 2)};
355
-
356
- export function searchKnowledge(query: string): any[] {
357
- const results: any[] = [];
358
- const lowerQuery = query.toLowerCase();
359
-
360
- // Search features
361
- for (const feature of appKnowledge.features) {
362
- if (feature.name.toLowerCase().includes(lowerQuery)) {
363
- results.push({
364
- type: 'feature',
365
- relevance: 0.9,
366
- data: feature
367
- });
368
- }
369
- }
370
-
371
- // Search API routes
372
- for (const route of appKnowledge.api_routes) {
373
- if (route.path.toLowerCase().includes(lowerQuery)) {
374
- results.push({
375
- type: 'api',
376
- relevance: 0.8,
377
- data: route
378
- });
379
- }
380
- }
381
-
382
- // Search components
383
- for (const component of appKnowledge.components) {
384
- if (component.name.toLowerCase().includes(lowerQuery)) {
385
- results.push({
386
- type: 'component',
387
- relevance: 0.7,
388
- data: component
389
- });
390
- }
391
- }
392
-
393
- // Search common tasks
394
- for (const task of appKnowledge.common_tasks) {
395
- if (task.task.toLowerCase().includes(lowerQuery) || task.answer.toLowerCase().includes(lowerQuery)) {
396
- results.push({
397
- type: 'task',
398
- relevance: 1.0,
399
- data: task
400
- });
401
- }
402
- }
403
-
404
- return results.sort((a, b) => b.relevance - a.relevance).slice(0, 5);
405
- }
351
+ const knowledgeFile = `// Auto-generated knowledge base for AI chatbot
352
+ // This file contains indexed information about the app
353
+
354
+ export const appKnowledge = ${JSON.stringify(knowledge, null, 2)};
355
+
356
+ export function searchKnowledge(query: string): any[] {
357
+ const results: any[] = [];
358
+ const lowerQuery = query.toLowerCase();
359
+
360
+ // Search features
361
+ for (const feature of appKnowledge.features) {
362
+ if (feature.name.toLowerCase().includes(lowerQuery)) {
363
+ results.push({
364
+ type: 'feature',
365
+ relevance: 0.9,
366
+ data: feature
367
+ });
368
+ }
369
+ }
370
+
371
+ // Search API routes
372
+ for (const route of appKnowledge.api_routes) {
373
+ if (route.path.toLowerCase().includes(lowerQuery)) {
374
+ results.push({
375
+ type: 'api',
376
+ relevance: 0.8,
377
+ data: route
378
+ });
379
+ }
380
+ }
381
+
382
+ // Search components
383
+ for (const component of appKnowledge.components) {
384
+ if (component.name.toLowerCase().includes(lowerQuery)) {
385
+ results.push({
386
+ type: 'component',
387
+ relevance: 0.7,
388
+ data: component
389
+ });
390
+ }
391
+ }
392
+
393
+ // Search common tasks
394
+ for (const task of appKnowledge.common_tasks) {
395
+ if (task.task.toLowerCase().includes(lowerQuery) || task.answer.toLowerCase().includes(lowerQuery)) {
396
+ results.push({
397
+ type: 'task',
398
+ relevance: 1.0,
399
+ data: task
400
+ });
401
+ }
402
+ }
403
+
404
+ return results.sort((a, b) => b.relevance - a.relevance).slice(0, 5);
405
+ }
406
406
  `;
407
407
  const knowledgePath = path.join(cwd, 'src', 'lib', 'chatbot-knowledge.ts');
408
408
  await fs.mkdir(path.dirname(knowledgePath), { recursive: true });
409
409
  await fs.writeFile(knowledgePath, knowledgeFile, 'utf-8');
410
410
  }
411
411
  async function generateChatbotAPI(cwd) {
412
- const apiRoute = `import { NextRequest, NextResponse } from 'next/server';
413
- import { searchKnowledge, appKnowledge } from '@/lib/chatbot-knowledge';
414
-
415
- export async function POST(request: NextRequest) {
416
- try {
417
- const { message } = await request.json();
418
-
419
- if (!message) {
420
- return NextResponse.json({ error: 'Message is required' }, { status: 400 });
421
- }
422
-
423
- // Search knowledge base
424
- const relevantInfo = searchKnowledge(message);
425
-
426
- // Generate response based on relevant information
427
- let response = generateResponse(message, relevantInfo);
428
-
429
- return NextResponse.json({ response });
430
- } catch (error) {
431
- console.error('Chatbot API error:', error);
432
- return NextResponse.json(
433
- { error: 'Internal server error' },
434
- { status: 500 }
435
- );
436
- }
437
- }
438
-
439
- function generateResponse(message: string, relevantInfo: any[]): string {
440
- const lowerMessage = message.toLowerCase();
441
-
442
- // Handle common greetings
443
- if (lowerMessage.match(/^(hi|hello|hey)/)) {
444
- return "Hello! I'm your AI assistant. I know everything about this app. What would you like to know?";
445
- }
446
-
447
- // Handle feature questions
448
- if (lowerMessage.includes('feature') || lowerMessage.includes('can i')) {
449
- const features = relevantInfo.filter(i => i.type === 'feature');
450
- if (features.length > 0) {
451
- return \`Yes! We have that feature. Available features include: \${features.map(f => f.data.name).join(', ')}. Would you like to know more about any of these?\`;
452
- }
453
- }
454
-
455
- // Handle navigation questions
456
- if (lowerMessage.includes('how do i') || lowerMessage.includes('where')) {
457
- const tasks = relevantInfo.filter(i => i.type === 'task');
458
- if (tasks.length > 0) {
459
- return tasks[0].data.answer;
460
- }
461
- }
462
-
463
- // Handle API questions
464
- if (lowerMessage.includes('api') || lowerMessage.includes('endpoint')) {
465
- const apis = relevantInfo.filter(i => i.type === 'api');
466
- if (apis.length > 0) {
467
- return \`We have these API endpoints: \${apis.map(a => \`\${a.data.path} (\${a.data.methods.join(', ')})\`).join(', ')}.\`;
468
- }
469
- }
470
-
471
- // Generic response with relevant info
472
- if (relevantInfo.length > 0) {
473
- const topResult = relevantInfo[0];
474
-
475
- switch (topResult.type) {
476
- case 'feature':
477
- return \`I found information about "\${topResult.data.name}". This is a \${topResult.data.priority} priority feature. Is this what you're looking for?\`;
478
- case 'component':
479
- return \`I found the \${topResult.data.name} component. It's located in \${topResult.data.file}. What would you like to know about it?\`;
480
- case 'api':
481
- return \`The API endpoint \${topResult.data.path} supports these methods: \${topResult.data.methods.join(', ')}.\`;
482
- case 'task':
483
- return topResult.data.answer;
484
- }
485
- }
486
-
487
- // Fallback response
488
- return \`I'm not sure about that. Could you rephrase your question? I can help with:
489
- - App features and capabilities
490
- - How to use specific functions
491
- - Navigation and settings
492
- - General questions about the app\`;
493
- }
412
+ const apiRoute = `import { NextRequest, NextResponse } from 'next/server';
413
+ import { searchKnowledge, appKnowledge } from '@/lib/chatbot-knowledge';
414
+
415
+ export async function POST(request: NextRequest) {
416
+ try {
417
+ const { message } = await request.json();
418
+
419
+ if (!message) {
420
+ return NextResponse.json({ error: 'Message is required' }, { status: 400 });
421
+ }
422
+
423
+ // Search knowledge base
424
+ const relevantInfo = searchKnowledge(message);
425
+
426
+ // Generate response based on relevant information
427
+ let response = generateResponse(message, relevantInfo);
428
+
429
+ return NextResponse.json({ response });
430
+ } catch (error) {
431
+ console.error('Chatbot API error:', error);
432
+ return NextResponse.json(
433
+ { error: 'Internal server error' },
434
+ { status: 500 }
435
+ );
436
+ }
437
+ }
438
+
439
+ function generateResponse(message: string, relevantInfo: any[]): string {
440
+ const lowerMessage = message.toLowerCase();
441
+
442
+ // Handle common greetings
443
+ if (lowerMessage.match(/^(hi|hello|hey)/)) {
444
+ return "Hello! I'm your AI assistant. I know everything about this app. What would you like to know?";
445
+ }
446
+
447
+ // Handle feature questions
448
+ if (lowerMessage.includes('feature') || lowerMessage.includes('can i')) {
449
+ const features = relevantInfo.filter(i => i.type === 'feature');
450
+ if (features.length > 0) {
451
+ return \`Yes! We have that feature. Available features include: \${features.map(f => f.data.name).join(', ')}. Would you like to know more about any of these?\`;
452
+ }
453
+ }
454
+
455
+ // Handle navigation questions
456
+ if (lowerMessage.includes('how do i') || lowerMessage.includes('where')) {
457
+ const tasks = relevantInfo.filter(i => i.type === 'task');
458
+ if (tasks.length > 0) {
459
+ return tasks[0].data.answer;
460
+ }
461
+ }
462
+
463
+ // Handle API questions
464
+ if (lowerMessage.includes('api') || lowerMessage.includes('endpoint')) {
465
+ const apis = relevantInfo.filter(i => i.type === 'api');
466
+ if (apis.length > 0) {
467
+ return \`We have these API endpoints: \${apis.map(a => \`\${a.data.path} (\${a.data.methods.join(', ')})\`).join(', ')}.\`;
468
+ }
469
+ }
470
+
471
+ // Generic response with relevant info
472
+ if (relevantInfo.length > 0) {
473
+ const topResult = relevantInfo[0];
474
+
475
+ switch (topResult.type) {
476
+ case 'feature':
477
+ return \`I found information about "\${topResult.data.name}". This is a \${topResult.data.priority} priority feature. Is this what you're looking for?\`;
478
+ case 'component':
479
+ return \`I found the \${topResult.data.name} component. It's located in \${topResult.data.file}. What would you like to know about it?\`;
480
+ case 'api':
481
+ return \`The API endpoint \${topResult.data.path} supports these methods: \${topResult.data.methods.join(', ')}.\`;
482
+ case 'task':
483
+ return topResult.data.answer;
484
+ }
485
+ }
486
+
487
+ // Fallback response
488
+ return \`I'm not sure about that. Could you rephrase your question? I can help with:
489
+ - App features and capabilities
490
+ - How to use specific functions
491
+ - Navigation and settings
492
+ - General questions about the app\`;
493
+ }
494
494
  `;
495
495
  const apiPath = path.join(cwd, 'src', 'app', 'api', 'chatbot', 'route.ts');
496
496
  await fs.mkdir(path.dirname(apiPath), { recursive: true });