@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.
- package/INSTALL.md +221 -221
- package/LICENSE +21 -21
- package/README.md +412 -412
- package/dist/cli.js +29 -29
- package/dist/cli.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/analyze-mockups.js +37 -37
- package/dist/tools/autonomous-build.d.ts +18 -18
- package/dist/tools/autonomous-build.js +286 -286
- package/dist/tools/check-gate.js +6 -6
- package/dist/tools/check-scope.js +10 -10
- package/dist/tools/enforce-feature.js +15 -15
- package/dist/tools/fix-commit.js +18 -18
- package/dist/tools/fix-mockups.js +191 -191
- package/dist/tools/generate-api-route.js +155 -155
- package/dist/tools/generate-chatbot.js +306 -306
- package/dist/tools/generate-component.js +117 -117
- package/dist/tools/generate-docs.js +525 -525
- package/dist/tools/generate-e2e-tests.js +19 -19
- package/dist/tools/generate-migration.js +22 -22
- package/dist/tools/generate-schema.js +37 -37
- package/dist/tools/generate-spec.js +38 -38
- package/dist/tools/generate-store-contracts.js +42 -42
- package/dist/tools/generate-store.js +109 -109
- package/dist/tools/generate-unit-tests.js +57 -57
- package/dist/tools/map-dependencies.js +45 -45
- package/dist/tools/run-interview.js +142 -142
- package/dist/tools/setup-github.js +8 -8
- package/dist/tools/setup-supabase.js +8 -8
- package/dist/tools/setup-vercel.js +8 -8
- package/dist/tools/start.d.ts +12 -0
- package/dist/tools/start.d.ts.map +1 -0
- package/dist/tools/start.js +252 -0
- package/dist/tools/start.js.map +1 -0
- package/dist/tools/validate-mockups.js +19 -19
- 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 });
|