@feardread/fear 1.0.1
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/FEAR.js +459 -0
- package/FEARServer.js +280 -0
- package/controllers/agent.js +438 -0
- package/controllers/auth/index.js +345 -0
- package/controllers/auth/token.js +50 -0
- package/controllers/blog.js +105 -0
- package/controllers/brand.js +10 -0
- package/controllers/cart.js +425 -0
- package/controllers/category.js +9 -0
- package/controllers/coupon.js +63 -0
- package/controllers/crud/crud.js +508 -0
- package/controllers/crud/index.js +36 -0
- package/controllers/email.js +34 -0
- package/controllers/enquiry.js +65 -0
- package/controllers/events.js +9 -0
- package/controllers/order.js +125 -0
- package/controllers/payment.js +31 -0
- package/controllers/product.js +147 -0
- package/controllers/review.js +247 -0
- package/controllers/tag.js +10 -0
- package/controllers/task.js +10 -0
- package/controllers/upload.js +41 -0
- package/controllers/user.js +401 -0
- package/index.js +7 -0
- package/libs/agent/index.js +561 -0
- package/libs/agent/modules/ai/ai.js +285 -0
- package/libs/agent/modules/ai/chat.js +518 -0
- package/libs/agent/modules/ai/config.js +688 -0
- package/libs/agent/modules/ai/operations.js +787 -0
- package/libs/agent/modules/analyze/api.js +546 -0
- package/libs/agent/modules/analyze/dorks.js +395 -0
- package/libs/agent/modules/ccard/README.md +454 -0
- package/libs/agent/modules/ccard/audit.js +479 -0
- package/libs/agent/modules/ccard/checker.js +674 -0
- package/libs/agent/modules/ccard/payment-processors.json +16 -0
- package/libs/agent/modules/ccard/validator.js +629 -0
- package/libs/agent/modules/code/analyzer.js +303 -0
- package/libs/agent/modules/code/jquery.js +1093 -0
- package/libs/agent/modules/code/react.js +1536 -0
- package/libs/agent/modules/code/refactor.js +499 -0
- package/libs/agent/modules/crypto/exchange.js +564 -0
- package/libs/agent/modules/net/proxy.js +409 -0
- package/libs/agent/modules/security/cve.js +442 -0
- package/libs/agent/modules/security/monitor.js +360 -0
- package/libs/agent/modules/security/scanner.js +300 -0
- package/libs/agent/modules/security/vulnerability.js +506 -0
- package/libs/agent/modules/security/web.js +465 -0
- package/libs/agent/modules/utils/browser.js +492 -0
- package/libs/agent/modules/utils/colorizer.js +285 -0
- package/libs/agent/modules/utils/manager.js +478 -0
- package/libs/cloud/index.js +228 -0
- package/libs/config/db.js +21 -0
- package/libs/config/validator.js +82 -0
- package/libs/db/index.js +318 -0
- package/libs/emailer/imap.js +126 -0
- package/libs/emailer/info.js +41 -0
- package/libs/emailer/smtp.js +77 -0
- package/libs/handler/async.js +3 -0
- package/libs/handler/error.js +66 -0
- package/libs/handler/index.js +161 -0
- package/libs/logger/index.js +49 -0
- package/libs/logger/morgan.js +24 -0
- package/libs/passport/passport.js +109 -0
- package/libs/search/api.js +384 -0
- package/libs/search/features.js +219 -0
- package/libs/search/service.js +64 -0
- package/libs/swagger/config.js +18 -0
- package/libs/swagger/index.js +35 -0
- package/libs/validator/index.js +254 -0
- package/models/blog.js +31 -0
- package/models/brand.js +12 -0
- package/models/cart.js +14 -0
- package/models/category.js +11 -0
- package/models/coupon.js +9 -0
- package/models/customer.js +0 -0
- package/models/enquiry.js +29 -0
- package/models/events.js +13 -0
- package/models/order.js +94 -0
- package/models/product.js +32 -0
- package/models/review.js +14 -0
- package/models/tag.js +10 -0
- package/models/task.js +11 -0
- package/models/user.js +68 -0
- package/package.json +12 -0
- package/routes/agent.js +615 -0
- package/routes/auth.js +13 -0
- package/routes/blog.js +19 -0
- package/routes/brand.js +15 -0
- package/routes/cart.js +105 -0
- package/routes/category.js +16 -0
- package/routes/coupon.js +15 -0
- package/routes/enquiry.js +14 -0
- package/routes/events.js +16 -0
- package/routes/mail.js +170 -0
- package/routes/order.js +19 -0
- package/routes/product.js +22 -0
- package/routes/review.js +11 -0
- package/routes/task.js +12 -0
- package/routes/user.js +17 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
// modules/ai/chat.js - Separate AI Chat Session Module
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const colorizer = require('../utils/colorizer');
|
|
6
|
+
|
|
7
|
+
const AiChat = function(agent) {
|
|
8
|
+
this.agent = agent;
|
|
9
|
+
this.conversationHistory = [];
|
|
10
|
+
this.maxHistoryLength = 50;
|
|
11
|
+
this.sessionName = null;
|
|
12
|
+
this.streamMode = false;
|
|
13
|
+
|
|
14
|
+
// Get AI config from main AI module
|
|
15
|
+
this.getConfig = () => {
|
|
16
|
+
if (this.agent && this.agent.modules && this.agent.modules.aiAnalyzer) {
|
|
17
|
+
return this.agent.modules.aiAnalyzer.config;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
this.chatSystemPrompt = `You are a helpful, conversational AI assistant. You can:
|
|
23
|
+
- Answer questions on any topic
|
|
24
|
+
- Help with coding and debugging
|
|
25
|
+
- Provide explanations and tutorials
|
|
26
|
+
- Assist with creative writing
|
|
27
|
+
- Have casual conversations
|
|
28
|
+
- Remember context from earlier in the conversation
|
|
29
|
+
|
|
30
|
+
Be friendly, helpful, and conversational. Adapt your tone to match the user's style.`;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
AiChat.prototype = {
|
|
34
|
+
|
|
35
|
+
isConfigured() {
|
|
36
|
+
const config = this.getConfig();
|
|
37
|
+
return config && config.isConfigured();
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
startSession(args) {
|
|
41
|
+
if (!this.isConfigured()) {
|
|
42
|
+
console.log(colorizer.error('AI not configured. Use "ai-setup <provider> <key>" first.\n'));
|
|
43
|
+
console.log(colorizer.info('Example: ai-setup anthropic sk-ant-...\n'));
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const config = this.getConfig();
|
|
48
|
+
|
|
49
|
+
console.log(colorizer.header('🤖 AI Chat Session'));
|
|
50
|
+
console.log(colorizer.separator());
|
|
51
|
+
console.log(colorizer.cyan('Provider: ') + colorizer.bright(config.getProviderName()));
|
|
52
|
+
console.log(colorizer.cyan('Model: ') + colorizer.dim(config.getModel()));
|
|
53
|
+
console.log(colorizer.cyan('Session: ') + (this.sessionName || 'Unnamed'));
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(colorizer.info('Chat Commands:'));
|
|
56
|
+
console.log(colorizer.dim(' /exit, /quit - Exit chat session'));
|
|
57
|
+
console.log(colorizer.dim(' /clear - Clear conversation history'));
|
|
58
|
+
console.log(colorizer.dim(' /history - Show conversation history'));
|
|
59
|
+
console.log(colorizer.dim(' /save <file> - Save conversation to file'));
|
|
60
|
+
console.log(colorizer.dim(' /load <file> - Load previous conversation'));
|
|
61
|
+
console.log(colorizer.dim(' /stream - Toggle streaming mode'));
|
|
62
|
+
console.log(colorizer.dim(' /session <name> - Name current session'));
|
|
63
|
+
console.log(colorizer.dim(' /export <format> - Export chat (txt/json/md)'));
|
|
64
|
+
console.log(colorizer.dim(' /help - Show this help'));
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(colorizer.success('Chat started! Ask me anything...\n'));
|
|
67
|
+
|
|
68
|
+
const rl = readline.createInterface({
|
|
69
|
+
input: process.stdin,
|
|
70
|
+
output: process.stdout,
|
|
71
|
+
prompt: this.getPrompt()
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const handleInput = (input) => {
|
|
75
|
+
const trimmedInput = input.trim();
|
|
76
|
+
|
|
77
|
+
if (!trimmedInput) {
|
|
78
|
+
rl.prompt();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle chat commands
|
|
83
|
+
if (trimmedInput.startsWith('/')) {
|
|
84
|
+
return this.handleChatCommand(trimmedInput, rl)
|
|
85
|
+
.then(result => {
|
|
86
|
+
if (result && result.exit) {
|
|
87
|
+
rl.close();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (result && result.streamMode !== undefined) {
|
|
91
|
+
this.streamMode = result.streamMode;
|
|
92
|
+
}
|
|
93
|
+
rl.prompt();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Add user message to history
|
|
98
|
+
this.addToHistory('user', trimmedInput);
|
|
99
|
+
|
|
100
|
+
// Build prompt with context
|
|
101
|
+
const prompt = this.buildPromptWithHistory(trimmedInput);
|
|
102
|
+
|
|
103
|
+
console.log(colorizer.dim('AI: '));
|
|
104
|
+
|
|
105
|
+
// Use streaming if enabled and supported
|
|
106
|
+
if (this.streamMode && (config.provider === 'google' || config.provider === 'ollama')) {
|
|
107
|
+
let response = '';
|
|
108
|
+
config.callStream(prompt, 4096, (chunk) => {
|
|
109
|
+
process.stdout.write(chunk);
|
|
110
|
+
response += chunk;
|
|
111
|
+
})
|
|
112
|
+
.then(() => {
|
|
113
|
+
console.log('\n');
|
|
114
|
+
this.addToHistory('assistant', response);
|
|
115
|
+
rl.prompt();
|
|
116
|
+
})
|
|
117
|
+
.catch(err => {
|
|
118
|
+
console.log(colorizer.error('\n\nError: ' + err.message + '\n'));
|
|
119
|
+
rl.prompt();
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
// Regular non-streaming response
|
|
123
|
+
config.call(prompt, 4096)
|
|
124
|
+
.then(response => {
|
|
125
|
+
console.log(response + '\n');
|
|
126
|
+
this.addToHistory('assistant', response);
|
|
127
|
+
rl.prompt();
|
|
128
|
+
})
|
|
129
|
+
.catch(err => {
|
|
130
|
+
console.log(colorizer.error('\nError: ' + err.message + '\n'));
|
|
131
|
+
rl.prompt();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
rl.prompt();
|
|
137
|
+
rl.on('line', handleInput);
|
|
138
|
+
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
rl.on('close', () => {
|
|
141
|
+
console.log(colorizer.info('\n👋 Chat session ended.\n'));
|
|
142
|
+
resolve();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
quickQuery(args) {
|
|
148
|
+
if (!this.isConfigured()) {
|
|
149
|
+
console.log(colorizer.error('AI not configured. Use "ai-setup <provider> <key>" first.\n'));
|
|
150
|
+
return Promise.resolve();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const query = args.join(' ');
|
|
154
|
+
if (!query) {
|
|
155
|
+
console.log(colorizer.error('Usage: chat-quick <your question>'));
|
|
156
|
+
console.log(colorizer.info('Example: chat-quick What is Node.js?\n'));
|
|
157
|
+
return Promise.resolve();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const config = this.getConfig();
|
|
161
|
+
|
|
162
|
+
console.log(colorizer.header('🤖 Quick Chat'));
|
|
163
|
+
console.log(colorizer.separator());
|
|
164
|
+
console.log(colorizer.cyan('Query: ') + colorizer.bright(query));
|
|
165
|
+
console.log(colorizer.cyan('Provider: ') + colorizer.bright(config.getProviderName()));
|
|
166
|
+
console.log();
|
|
167
|
+
|
|
168
|
+
const prompt = this.buildPromptWithHistory(query);
|
|
169
|
+
|
|
170
|
+
return config.call(prompt, 3000)
|
|
171
|
+
.then(response => {
|
|
172
|
+
console.log(response);
|
|
173
|
+
console.log('\n' + colorizer.separator());
|
|
174
|
+
console.log(colorizer.info('💡 Tip: Use "chat" for interactive conversation\n'));
|
|
175
|
+
|
|
176
|
+
// Add to history for context
|
|
177
|
+
this.addToHistory('user', query);
|
|
178
|
+
this.addToHistory('assistant', response);
|
|
179
|
+
})
|
|
180
|
+
.catch(err => {
|
|
181
|
+
console.log(colorizer.error('Chat failed: ' + err.message + '\n'));
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
handleChatCommand(command, rl) {
|
|
186
|
+
const parts = command.split(' ');
|
|
187
|
+
const cmd = parts[0].toLowerCase();
|
|
188
|
+
const args = parts.slice(1);
|
|
189
|
+
|
|
190
|
+
switch (cmd) {
|
|
191
|
+
case '/exit':
|
|
192
|
+
case '/quit':
|
|
193
|
+
return Promise.resolve({ exit: true });
|
|
194
|
+
|
|
195
|
+
case '/clear':
|
|
196
|
+
this.conversationHistory = [];
|
|
197
|
+
console.log(colorizer.success('Conversation history cleared.\n'));
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
|
|
200
|
+
case '/history':
|
|
201
|
+
return this.showHistory();
|
|
202
|
+
|
|
203
|
+
case '/save':
|
|
204
|
+
const saveFile = args[0] || `chat_${Date.now()}.txt`;
|
|
205
|
+
return this.saveToFile(saveFile);
|
|
206
|
+
|
|
207
|
+
case '/load':
|
|
208
|
+
const loadFile = args[0];
|
|
209
|
+
if (!loadFile) {
|
|
210
|
+
console.log(colorizer.error('Usage: /load <filename>\n'));
|
|
211
|
+
return Promise.resolve();
|
|
212
|
+
}
|
|
213
|
+
return this.loadFromFile(loadFile);
|
|
214
|
+
|
|
215
|
+
case '/stream':
|
|
216
|
+
const config = this.getConfig();
|
|
217
|
+
if (config.provider === 'google' || config.provider === 'ollama') {
|
|
218
|
+
this.streamMode = !this.streamMode;
|
|
219
|
+
console.log(colorizer.success(`Streaming mode ${this.streamMode ? 'enabled' : 'disabled'}.\n`));
|
|
220
|
+
return Promise.resolve({ streamMode: this.streamMode });
|
|
221
|
+
} else {
|
|
222
|
+
console.log(colorizer.warning('Streaming only available with Google Gemini or Ollama.\n'));
|
|
223
|
+
return Promise.resolve();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
case '/session':
|
|
227
|
+
this.sessionName = args.join(' ') || null;
|
|
228
|
+
console.log(colorizer.success(`Session named: ${this.sessionName || 'Unnamed'}\n`));
|
|
229
|
+
return Promise.resolve();
|
|
230
|
+
|
|
231
|
+
case '/export':
|
|
232
|
+
const format = args[0] || 'txt';
|
|
233
|
+
const exportFile = args[1] || `chat_export_${Date.now()}.${format}`;
|
|
234
|
+
return this.exportChat(format, exportFile);
|
|
235
|
+
|
|
236
|
+
case '/help':
|
|
237
|
+
console.log(colorizer.info('Available chat commands:'));
|
|
238
|
+
console.log(colorizer.dim(' /exit, /quit - Exit chat session'));
|
|
239
|
+
console.log(colorizer.dim(' /clear - Clear conversation history'));
|
|
240
|
+
console.log(colorizer.dim(' /history - Show conversation history'));
|
|
241
|
+
console.log(colorizer.dim(' /save <file> - Save conversation'));
|
|
242
|
+
console.log(colorizer.dim(' /load <file> - Load conversation'));
|
|
243
|
+
console.log(colorizer.dim(' /stream - Toggle streaming'));
|
|
244
|
+
console.log(colorizer.dim(' /session <name> - Name session'));
|
|
245
|
+
console.log(colorizer.dim(' /export <format> - Export (txt/json/md)'));
|
|
246
|
+
console.log(colorizer.dim(' /help - Show this help\n'));
|
|
247
|
+
return Promise.resolve();
|
|
248
|
+
|
|
249
|
+
default:
|
|
250
|
+
console.log(colorizer.warning('Unknown command. Type /help for available commands.\n'));
|
|
251
|
+
return Promise.resolve();
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
buildPromptWithHistory(currentQuery) {
|
|
256
|
+
let prompt = this.chatSystemPrompt + '\n\n';
|
|
257
|
+
|
|
258
|
+
// Add recent conversation history
|
|
259
|
+
if (this.conversationHistory.length > 0) {
|
|
260
|
+
prompt += 'Previous conversation:\n';
|
|
261
|
+
// Only include last 10 exchanges for context
|
|
262
|
+
const recentHistory = this.conversationHistory.slice(-20);
|
|
263
|
+
recentHistory.forEach(msg => {
|
|
264
|
+
prompt += `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}\n`;
|
|
265
|
+
});
|
|
266
|
+
prompt += '\n';
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
prompt += `Current user message: ${currentQuery}\n\n`;
|
|
270
|
+
prompt += 'Provide a helpful, conversational response.';
|
|
271
|
+
|
|
272
|
+
return prompt;
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
addToHistory(role, content) {
|
|
276
|
+
this.conversationHistory.push({
|
|
277
|
+
role,
|
|
278
|
+
content,
|
|
279
|
+
timestamp: new Date().toISOString()
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Trim history if too long
|
|
283
|
+
if (this.conversationHistory.length > this.maxHistoryLength) {
|
|
284
|
+
this.conversationHistory = this.conversationHistory.slice(-this.maxHistoryLength);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
showHistory() {
|
|
289
|
+
if (this.conversationHistory.length === 0) {
|
|
290
|
+
console.log(colorizer.info('No conversation history yet.\n'));
|
|
291
|
+
return Promise.resolve();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
console.log(colorizer.header('Conversation History'));
|
|
295
|
+
console.log(colorizer.separator());
|
|
296
|
+
console.log(colorizer.cyan('Session: ') + (this.sessionName || 'Unnamed'));
|
|
297
|
+
console.log(colorizer.cyan('Messages: ') + this.conversationHistory.length);
|
|
298
|
+
console.log();
|
|
299
|
+
|
|
300
|
+
this.conversationHistory.forEach((msg, index) => {
|
|
301
|
+
const role = msg.role === 'user' ?
|
|
302
|
+
colorizer.cyan('You') :
|
|
303
|
+
colorizer.green('AI');
|
|
304
|
+
const time = new Date(msg.timestamp).toLocaleTimeString();
|
|
305
|
+
const preview = msg.content.substring(0, 80) +
|
|
306
|
+
(msg.content.length > 80 ? '...' : '');
|
|
307
|
+
|
|
308
|
+
console.log(`${colorizer.dim(`[${time}]`)} ${role}: ${preview}`);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
console.log();
|
|
312
|
+
return Promise.resolve();
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
saveToFile(filename) {
|
|
316
|
+
if (this.conversationHistory.length === 0) {
|
|
317
|
+
console.log(colorizer.warning('No conversation to save.\n'));
|
|
318
|
+
return Promise.resolve();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const config = this.getConfig();
|
|
322
|
+
let content = '# AI Chat Session\n\n';
|
|
323
|
+
content += `**Date:** ${new Date().toISOString()}\n`;
|
|
324
|
+
content += `**Session:** ${this.sessionName || 'Unnamed'}\n`;
|
|
325
|
+
content += `**Provider:** ${config.getProviderName()}\n`;
|
|
326
|
+
content += `**Model:** ${config.getModel()}\n`;
|
|
327
|
+
content += `**Messages:** ${this.conversationHistory.length}\n\n`;
|
|
328
|
+
content += '---\n\n';
|
|
329
|
+
|
|
330
|
+
this.conversationHistory.forEach((msg, index) => {
|
|
331
|
+
const time = new Date(msg.timestamp).toLocaleTimeString();
|
|
332
|
+
content += `### ${msg.role === 'user' ? '👤 You' : '🤖 AI'} - ${time}\n\n`;
|
|
333
|
+
content += msg.content + '\n\n';
|
|
334
|
+
content += '---\n\n';
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return fs.writeFile(filename, content)
|
|
338
|
+
.then(() => {
|
|
339
|
+
console.log(colorizer.success(`💾 Conversation saved to ${filename}\n`));
|
|
340
|
+
})
|
|
341
|
+
.catch(err => {
|
|
342
|
+
console.log(colorizer.error(`Failed to save: ${err.message}\n`));
|
|
343
|
+
});
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
loadFromFile(filename) {
|
|
347
|
+
return fs.readFile(filename, 'utf8')
|
|
348
|
+
.then(content => {
|
|
349
|
+
// Parse the saved conversation
|
|
350
|
+
// This is a simple implementation - could be enhanced
|
|
351
|
+
const messages = content.split('---\n\n');
|
|
352
|
+
let loaded = 0;
|
|
353
|
+
|
|
354
|
+
messages.forEach(msg => {
|
|
355
|
+
if (msg.includes('### 👤 You')) {
|
|
356
|
+
const content = msg.split('\n\n')[1];
|
|
357
|
+
if (content) {
|
|
358
|
+
this.addToHistory('user', content.trim());
|
|
359
|
+
loaded++;
|
|
360
|
+
}
|
|
361
|
+
} else if (msg.includes('### 🤖 AI')) {
|
|
362
|
+
const content = msg.split('\n\n')[1];
|
|
363
|
+
if (content) {
|
|
364
|
+
this.addToHistory('assistant', content.trim());
|
|
365
|
+
loaded++;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
console.log(colorizer.success(`📂 Loaded ${loaded} messages from ${filename}\n`));
|
|
371
|
+
})
|
|
372
|
+
.catch(err => {
|
|
373
|
+
console.log(colorizer.error(`Failed to load: ${err.message}\n`));
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
exportChat(format, filename) {
|
|
378
|
+
if (this.conversationHistory.length === 0) {
|
|
379
|
+
console.log(colorizer.warning('No conversation to export.\n'));
|
|
380
|
+
return Promise.resolve();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const config = this.getConfig();
|
|
384
|
+
let content = '';
|
|
385
|
+
|
|
386
|
+
switch (format.toLowerCase()) {
|
|
387
|
+
case 'json':
|
|
388
|
+
content = JSON.stringify({
|
|
389
|
+
session: this.sessionName,
|
|
390
|
+
date: new Date().toISOString(),
|
|
391
|
+
provider: config.getProviderName(),
|
|
392
|
+
model: config.getModel(),
|
|
393
|
+
messages: this.conversationHistory
|
|
394
|
+
}, null, 2);
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
case 'md':
|
|
398
|
+
case 'markdown':
|
|
399
|
+
content = this.formatAsMarkdown(config);
|
|
400
|
+
break;
|
|
401
|
+
|
|
402
|
+
case 'txt':
|
|
403
|
+
default:
|
|
404
|
+
content = this.formatAsText(config);
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return fs.writeFile(filename, content)
|
|
409
|
+
.then(() => {
|
|
410
|
+
console.log(colorizer.success(`📤 Chat exported to ${filename}\n`));
|
|
411
|
+
})
|
|
412
|
+
.catch(err => {
|
|
413
|
+
console.log(colorizer.error(`Export failed: ${err.message}\n`));
|
|
414
|
+
});
|
|
415
|
+
},
|
|
416
|
+
|
|
417
|
+
formatAsMarkdown(config) {
|
|
418
|
+
let md = `# Chat Session: ${this.sessionName || 'Unnamed'}\n\n`;
|
|
419
|
+
md += `- **Date:** ${new Date().toISOString()}\n`;
|
|
420
|
+
md += `- **Provider:** ${config.getProviderName()}\n`;
|
|
421
|
+
md += `- **Model:** ${config.getModel()}\n`;
|
|
422
|
+
md += `- **Messages:** ${this.conversationHistory.length}\n\n`;
|
|
423
|
+
md += '---\n\n';
|
|
424
|
+
|
|
425
|
+
this.conversationHistory.forEach(msg => {
|
|
426
|
+
const time = new Date(msg.timestamp).toLocaleTimeString();
|
|
427
|
+
md += `## ${msg.role === 'user' ? '👤 User' : '🤖 AI'} (${time})\n\n`;
|
|
428
|
+
md += msg.content + '\n\n';
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
return md;
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
formatAsText(config) {
|
|
435
|
+
let txt = `AI CHAT SESSION\n`;
|
|
436
|
+
txt += `===============\n\n`;
|
|
437
|
+
txt += `Session: ${this.sessionName || 'Unnamed'}\n`;
|
|
438
|
+
txt += `Date: ${new Date().toISOString()}\n`;
|
|
439
|
+
txt += `Provider: ${config.getProviderName()}\n`;
|
|
440
|
+
txt += `Model: ${config.getModel()}\n`;
|
|
441
|
+
txt += `Messages: ${this.conversationHistory.length}\n\n`;
|
|
442
|
+
txt += `${'='.repeat(60)}\n\n`;
|
|
443
|
+
|
|
444
|
+
this.conversationHistory.forEach((msg, index) => {
|
|
445
|
+
const time = new Date(msg.timestamp).toLocaleTimeString();
|
|
446
|
+
txt += `[${index + 1}] ${msg.role === 'user' ? 'YOU' : 'AI'} (${time})\n`;
|
|
447
|
+
txt += `${'-'.repeat(60)}\n`;
|
|
448
|
+
txt += `${msg.content}\n\n`;
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
return txt;
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
clearHistory() {
|
|
455
|
+
this.conversationHistory = [];
|
|
456
|
+
console.log(colorizer.success('Chat history cleared.\n'));
|
|
457
|
+
return Promise.resolve();
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
saveSession(args) {
|
|
461
|
+
const filename = args[0] || `session_${Date.now()}.json`;
|
|
462
|
+
|
|
463
|
+
const sessionData = {
|
|
464
|
+
name: this.sessionName,
|
|
465
|
+
created: new Date().toISOString(),
|
|
466
|
+
provider: this.getConfig()?.getProviderName(),
|
|
467
|
+
model: this.getConfig()?.getModel(),
|
|
468
|
+
history: this.conversationHistory
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
return fs.writeFile(filename, JSON.stringify(sessionData, null, 2))
|
|
472
|
+
.then(() => {
|
|
473
|
+
console.log(colorizer.success(`Session saved to ${filename}\n`));
|
|
474
|
+
})
|
|
475
|
+
.catch(err => {
|
|
476
|
+
console.log(colorizer.error(`Failed to save session: ${err.message}\n`));
|
|
477
|
+
});
|
|
478
|
+
},
|
|
479
|
+
|
|
480
|
+
loadSession(args) {
|
|
481
|
+
const filename = args[0];
|
|
482
|
+
if (!filename) {
|
|
483
|
+
console.log(colorizer.error('Usage: chat-load <filename>\n'));
|
|
484
|
+
return Promise.resolve();
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return fs.readFile(filename, 'utf8')
|
|
488
|
+
.then(data => {
|
|
489
|
+
const sessionData = JSON.parse(data);
|
|
490
|
+
this.sessionName = sessionData.name;
|
|
491
|
+
this.conversationHistory = sessionData.history || [];
|
|
492
|
+
|
|
493
|
+
console.log(colorizer.success(`Session loaded: ${this.sessionName || 'Unnamed'}`));
|
|
494
|
+
console.log(colorizer.cyan(`Messages: ${this.conversationHistory.length}\n`));
|
|
495
|
+
})
|
|
496
|
+
.catch(err => {
|
|
497
|
+
console.log(colorizer.error(`Failed to load session: ${err.message}\n`));
|
|
498
|
+
});
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
getPrompt() {
|
|
502
|
+
const config = this.getConfig();
|
|
503
|
+
let prompt = colorizer.cyan('>> ');
|
|
504
|
+
|
|
505
|
+
if (this.sessionName) {
|
|
506
|
+
prompt += colorizer.dim(`[${this.sessionName}] `);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (this.streamMode) {
|
|
510
|
+
prompt += colorizer.yellow('FEAR AI: ');
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
prompt += colorizer.bright('You: ');
|
|
514
|
+
return prompt;
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
module.exports = AiChat;
|