natureco-cli 2.17.2 → 2.17.6
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/package.json +2 -1
- package/src/commands/chat.js +340 -634
- package/src/commands/dashboard.js +2 -2
- package/src/commands/gateway-server.js +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.6",
|
|
4
4
|
"description": "NatureCo AI Bot Terminal Interface",
|
|
5
5
|
"main": "bin/natureco.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@whiskeysockets/baileys": "^7.0.0-rc10",
|
|
28
|
+
"blessed": "^0.1.81",
|
|
28
29
|
"boxen": "^5.1.2",
|
|
29
30
|
"chalk": "^4.1.2",
|
|
30
31
|
"commander": "^11.1.0",
|
package/src/commands/chat.js
CHANGED
|
@@ -3,13 +3,12 @@ const os = require('os');
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
5
|
const chalk = require('chalk');
|
|
6
|
-
const
|
|
7
|
-
const { getApiKey } = require('../utils/config');
|
|
6
|
+
const { getApiKey, getConfig } = require('../utils/config');
|
|
8
7
|
const { getBots, sendMessage, _sendMessage } = require('../utils/api');
|
|
9
8
|
const { getSkillPrompts, getSkills } = require('../utils/skills');
|
|
10
9
|
const { getAgentsPrompt } = require('../utils/agents');
|
|
11
|
-
const { addToHistory, getCommandHistory
|
|
12
|
-
const { getMemoryPrompt, extractMemoryFromMessage, loadMemory, clearMemory } = require('../utils/memory');
|
|
10
|
+
const { addToHistory, getCommandHistory } = require('../utils/history');
|
|
11
|
+
const { getMemoryPrompt, extractMemoryFromMessage, loadMemory, clearMemory, addMemoryEntry } = require('../utils/memory');
|
|
13
12
|
const { getCommands, getCommandContent } = require('../utils/commands');
|
|
14
13
|
const { runHooks } = require('../utils/hooks');
|
|
15
14
|
const { createSession, loadSession, getLatestSession, addMessageToSession } = require('../utils/sessions');
|
|
@@ -17,745 +16,452 @@ const { addBackgroundTask, updateBackgroundTask } = require('../utils/background
|
|
|
17
16
|
const { getToolDefinitions, executeToolCalls } = require('../utils/tool-runner');
|
|
18
17
|
const { extractToolCalls } = require('../utils/tool-adapter');
|
|
19
18
|
|
|
19
|
+
// ── ASCII Logo ────────────────────────────────────────────────────────────────
|
|
20
|
+
const ASCII_LOGO = [
|
|
21
|
+
'{green-fg}███╗ ██╗ █████╗ ████████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗{/}',
|
|
22
|
+
'{green-fg}████╗ ██║██╔══██╗╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔════╝ ██╔═══██╗{/}',
|
|
23
|
+
'{green-fg}██╔██╗ ██║███████║ ██║ ██║ ██║██████╔╝█████╗ ██║ ██║ ██║{/}',
|
|
24
|
+
'{green-fg}██║╚██╗██║██╔══██║ ██║ ██║ ██║██╔══██╗██╔══╝ ██║ ██║ ██║{/}',
|
|
25
|
+
'{green-fg}██║ ╚████║██║ ██║ ██║ ╚██████╔╝██║ ██║███████╗╚██████╗ ╚██████╔╝{/}',
|
|
26
|
+
'{gray-fg}╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝{/}',
|
|
27
|
+
].join('\n');
|
|
28
|
+
|
|
29
|
+
// ── What's New ────────────────────────────────────────────────────────────────
|
|
30
|
+
const CHANGELOG = [
|
|
31
|
+
'Eklendi: Blessed TUI — 4 bölgeli tam ekran arayüz',
|
|
32
|
+
'Eklendi: agents, plugins, pairing, uninstall komutları',
|
|
33
|
+
'Eklendi: channels, models, memory, logs, status, security, reset',
|
|
34
|
+
'Düzeltildi: Telegram/WhatsApp cevap vermeme sorunu',
|
|
35
|
+
'Düzeltildi: Token optimizasyonu — sistem prompt sıkıştırıldı',
|
|
36
|
+
];
|
|
37
|
+
|
|
20
38
|
async function chat(botName, options = {}) {
|
|
21
39
|
const apiKey = getApiKey();
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
const version = require('../../package.json').version;
|
|
22
42
|
|
|
23
|
-
|
|
24
|
-
console.log(chalk.red('\n❌ Not logged in. Run "natureco login" first.\n'));
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
console.log(chalk.yellow('\n⏳ Loading bots...\n'));
|
|
29
|
-
|
|
43
|
+
// ── Bot seçimi ──────────────────────────────────────────────────────────────
|
|
30
44
|
let botList;
|
|
31
45
|
try {
|
|
32
|
-
botList = await getBots(apiKey);
|
|
46
|
+
botList = await getBots(apiKey || config.providerApiKey || '');
|
|
33
47
|
} catch (err) {
|
|
34
48
|
console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
|
|
35
49
|
process.exit(1);
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
if (!botList
|
|
52
|
+
if (!botList?.bots?.length) {
|
|
39
53
|
console.log(chalk.gray('No bots found. Create one at https://developers.natureco.me\n'));
|
|
40
54
|
process.exit(1);
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
// Bot adı verilmediyse config'den defaultBot'u kullan veya interaktif seçim sun
|
|
44
57
|
let bot;
|
|
45
58
|
if (!botName) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (config.defaultBot) {
|
|
50
|
-
bot = botList.bots.find(b => b.name.toLowerCase() === config.defaultBot.toLowerCase());
|
|
51
|
-
if (!bot && config.defaultBotId) {
|
|
52
|
-
bot = botList.bots.find(b => b.id === config.defaultBotId);
|
|
53
|
-
}
|
|
59
|
+
if (config.botName) {
|
|
60
|
+
bot = botList.bots.find(b => b.name && b.name.toLowerCase() === config.botName.toLowerCase());
|
|
54
61
|
}
|
|
55
|
-
|
|
56
62
|
if (!bot) {
|
|
57
|
-
// Interaktif bot seçimi
|
|
58
|
-
console.log(chalk.yellow('Varsayılan bot bulunamadı. Lütfen bir bot seçin:\n'));
|
|
59
|
-
botList.bots.forEach((b, i) => {
|
|
60
|
-
console.log(chalk.cyan(` ${i + 1}. ${b.name}`));
|
|
61
|
-
});
|
|
62
|
-
console.log('');
|
|
63
|
-
|
|
64
63
|
process.stdin.resume();
|
|
65
|
-
const { selectedBot } = await inquirer.prompt([
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
]);
|
|
73
|
-
|
|
64
|
+
const { selectedBot } = await inquirer.prompt([{
|
|
65
|
+
type: 'list',
|
|
66
|
+
name: 'selectedBot',
|
|
67
|
+
message: 'Bot seçin:',
|
|
68
|
+
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
69
|
+
}]);
|
|
74
70
|
bot = botList.bots.find(b => b.id === selectedBot);
|
|
75
71
|
}
|
|
76
72
|
} else {
|
|
77
|
-
// Bot adı ile eşleşen botu bul
|
|
78
73
|
bot = botList.bots.find(b => b.name && botName && b.name.toLowerCase() === botName.toLowerCase());
|
|
79
|
-
|
|
80
74
|
if (!bot) {
|
|
81
75
|
console.log(chalk.red(`\n❌ Bot "${botName}" not found.\n`));
|
|
82
|
-
console.log(chalk.gray('Available bots:'));
|
|
83
|
-
botList.bots.forEach(b => console.log(chalk.cyan(` - ${b.name}`)));
|
|
84
|
-
console.log('');
|
|
85
76
|
process.exit(1);
|
|
86
77
|
}
|
|
87
78
|
}
|
|
88
79
|
|
|
89
|
-
//
|
|
90
|
-
console.clear();
|
|
91
|
-
|
|
92
|
-
// ASCII art rabbit
|
|
93
|
-
console.log('');
|
|
94
|
-
console.log(chalk.cyan(' (\\\_/)'));
|
|
95
|
-
console.log(chalk.cyan(' (•ᴥ•)'));
|
|
96
|
-
console.log(chalk.cyan(' />🌿'));
|
|
97
|
-
console.log('');
|
|
98
|
-
|
|
99
|
-
// Helper function for progress bar
|
|
100
|
-
function progressBar(percent, width = 20) {
|
|
101
|
-
const filled = Math.round(width * percent);
|
|
102
|
-
return chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(width - filled));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Helper function to check gateway status
|
|
106
|
-
function checkGateway() {
|
|
107
|
-
try {
|
|
108
|
-
const fs2 = require('fs');
|
|
109
|
-
const gatewayPidFile = path.join(os.homedir(), '.natureco', 'gateway.pid');
|
|
110
|
-
if (fs2.existsSync(gatewayPidFile)) {
|
|
111
|
-
const pid = parseInt(fs2.readFileSync(gatewayPidFile, 'utf8'));
|
|
112
|
-
process.kill(pid, 0);
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
} catch {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Startup steps with animation
|
|
122
|
-
const steps = [
|
|
123
|
-
{ label: 'Memory', fn: () => loadMemory(bot.id) },
|
|
124
|
-
{ label: 'Skills', fn: () => getSkillPrompts() },
|
|
125
|
-
{ label: 'Gateway', fn: () => checkGateway() },
|
|
126
|
-
];
|
|
127
|
-
|
|
128
|
-
// Execute steps with progress animation
|
|
129
|
-
const results = {};
|
|
130
|
-
for (let i = 0; i < steps.length; i++) {
|
|
131
|
-
const step = steps[i];
|
|
132
|
-
const percent = (i + 1) / steps.length;
|
|
133
|
-
|
|
134
|
-
process.stdout.write(`[${progressBar(percent)}] ${step.label}...`);
|
|
135
|
-
|
|
136
|
-
// Execute step
|
|
137
|
-
const result = step.fn();
|
|
138
|
-
results[step.label.toLowerCase()] = result;
|
|
139
|
-
|
|
140
|
-
// Show result
|
|
141
|
-
let info = '';
|
|
142
|
-
if (step.label === 'Memory' && result) {
|
|
143
|
-
const factCount = (result.facts || []).length;
|
|
144
|
-
info = factCount > 0 ? ` · ${factCount} facts` : '';
|
|
145
|
-
} else if (step.label === 'Skills' && result) {
|
|
146
|
-
const skillCount = getSkills().length;
|
|
147
|
-
info = skillCount > 0 ? ` · ${skillCount} skills` : '';
|
|
148
|
-
} else if (step.label === 'Gateway') {
|
|
149
|
-
info = result ? ' · running' : ' · offline';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
process.stdout.write(`\r[${progressBar(percent)}] ${step.label} loaded${info}\n`);
|
|
153
|
-
|
|
154
|
-
// Wait 300ms
|
|
155
|
-
await new Promise(resolve => setTimeout(resolve, 300));
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
console.log('');
|
|
159
|
-
|
|
160
|
-
// Wait a bit before clearing
|
|
161
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
162
|
-
|
|
163
|
-
// Chat başlat
|
|
164
|
-
console.clear();
|
|
165
|
-
|
|
166
|
-
// Get botName from memory and bot
|
|
80
|
+
// ── Hafıza & sistem prompt ──────────────────────────────────────────────────
|
|
167
81
|
const mem = loadMemory(bot.id);
|
|
168
82
|
const displayBotName = mem.botName || bot.name || 'NatureCo';
|
|
169
|
-
|
|
170
|
-
// Get provider model (short name)
|
|
171
|
-
const { getConfig } = require('../utils/config');
|
|
172
|
-
const config = getConfig();
|
|
83
|
+
const userName = mem.name || config.userName || 'User';
|
|
173
84
|
const providerModel = config.providerModel || 'unknown';
|
|
174
|
-
const shortModel = providerModel.split('/').pop().split('-').slice(0,
|
|
175
|
-
|
|
176
|
-
// Get terminal width
|
|
177
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
178
|
-
const separator = '─'.repeat(terminalWidth);
|
|
179
|
-
|
|
180
|
-
// Rabbit ASCII art with fixed unicode
|
|
181
|
-
const rabbit = chalk.cyan(' (\\\_/)') + '\n' +
|
|
182
|
-
chalk.cyan(' (•ᴥ•)') + '\n' +
|
|
183
|
-
chalk.cyan(' />') + chalk.green('🌿');
|
|
184
|
-
|
|
185
|
-
// Full UI header with rabbit
|
|
186
|
-
console.log(rabbit);
|
|
187
|
-
console.log('');
|
|
188
|
-
console.log(chalk.gray(separator));
|
|
189
|
-
|
|
190
|
-
// Line 1: NatureCo · botName · model · timezone
|
|
191
|
-
const timezone = mem.facts?.find(f => {
|
|
192
|
-
const val = typeof f === 'string' ? f : f.value;
|
|
193
|
-
return val?.includes('Timezone:');
|
|
194
|
-
});
|
|
195
|
-
const tzStr = timezone ? (typeof timezone === 'string' ? timezone : timezone.value).replace('Timezone:', '').trim() : '';
|
|
196
|
-
const line1 = chalk.white.bold('NatureCo') +
|
|
197
|
-
chalk.gray(' · ') +
|
|
198
|
-
chalk.cyan(displayBotName) +
|
|
199
|
-
chalk.gray(' · ') +
|
|
200
|
-
chalk.gray(shortModel) +
|
|
201
|
-
(tzStr ? chalk.gray(' · ') + chalk.gray(tzStr) : '');
|
|
202
|
-
console.log(line1);
|
|
203
|
-
|
|
204
|
-
console.log(chalk.gray(separator));
|
|
205
|
-
|
|
206
|
-
// Line 2: Session · Commands · Ctrl+C
|
|
207
|
-
const line2 = chalk.gray('Session') +
|
|
208
|
-
chalk.gray(' · ') +
|
|
209
|
-
chalk.gray('/clear /bot /skills /memory /help') +
|
|
210
|
-
chalk.gray(' · ') +
|
|
211
|
-
chalk.gray('Ctrl+C to exit');
|
|
212
|
-
console.log(line2);
|
|
213
|
-
|
|
214
|
-
console.log(chalk.gray(separator));
|
|
215
|
-
|
|
216
|
-
// Line 3: Memory info · Skills · Crons
|
|
217
|
-
const userName = mem.name || 'User';
|
|
218
|
-
const factCount = (mem.facts || []).length;
|
|
219
|
-
const skillCount = getSkills().length;
|
|
220
|
-
|
|
221
|
-
// Get active cron count with correct path
|
|
222
|
-
let cronCount = 0;
|
|
223
|
-
try {
|
|
224
|
-
const fs2 = require('fs');
|
|
225
|
-
const cronsFile = path.join(os.homedir(), '.natureco', 'crons.json');
|
|
226
|
-
if (fs2.existsSync(cronsFile)) {
|
|
227
|
-
const crons = JSON.parse(fs2.readFileSync(cronsFile, 'utf8'));
|
|
228
|
-
cronCount = crons.filter(c => c.enabled !== false).length;
|
|
229
|
-
}
|
|
230
|
-
} catch (e) {
|
|
231
|
-
cronCount = 0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const memoryInfo = `Memory: ${userName}`;
|
|
235
|
-
const line3 = chalk.gray(memoryInfo + (factCount > 0 ? ` · ${factCount} facts` : '')) +
|
|
236
|
-
chalk.gray(' ') +
|
|
237
|
-
chalk.gray(`Skills: ${skillCount}`) +
|
|
238
|
-
chalk.gray(' ') +
|
|
239
|
-
chalk.gray(`Crons: ${cronCount} active`);
|
|
240
|
-
console.log(line3);
|
|
241
|
-
|
|
242
|
-
console.log(chalk.gray(separator));
|
|
243
|
-
console.log('');
|
|
244
|
-
|
|
245
|
-
// Session management
|
|
246
|
-
let session;
|
|
247
|
-
if (options.resume) {
|
|
248
|
-
if (options.resume === true) {
|
|
249
|
-
// Resume latest session
|
|
250
|
-
session = getLatestSession(bot.id);
|
|
251
|
-
if (session) {
|
|
252
|
-
console.log(chalk.blue(`Resumed: ${session.id}\n`));
|
|
253
|
-
// Display last few messages
|
|
254
|
-
const lastMessages = (session.messages || []).slice(-3);
|
|
255
|
-
lastMessages.forEach(msg => {
|
|
256
|
-
console.log(chalk.gray('You ') + msg.user);
|
|
257
|
-
console.log(chalk.cyan(displayBotName + ' ') + msg.bot);
|
|
258
|
-
console.log('');
|
|
259
|
-
});
|
|
260
|
-
} else {
|
|
261
|
-
console.log(chalk.gray('No previous session. Starting new.\n'));
|
|
262
|
-
session = createSession(bot.id, bot.name);
|
|
263
|
-
}
|
|
264
|
-
} else {
|
|
265
|
-
// Resume specific session
|
|
266
|
-
session = loadSession(bot.id, options.resume);
|
|
267
|
-
if (session) {
|
|
268
|
-
console.log(chalk.blue(`Resumed: ${session.id}\n`));
|
|
269
|
-
// Display last few messages
|
|
270
|
-
const lastMessages = (session.messages || []).slice(-3);
|
|
271
|
-
lastMessages.forEach(msg => {
|
|
272
|
-
console.log(chalk.gray('You ') + msg.user);
|
|
273
|
-
console.log(chalk.cyan(displayBotName + ' ') + msg.bot);
|
|
274
|
-
console.log('');
|
|
275
|
-
});
|
|
276
|
-
} else {
|
|
277
|
-
console.log(chalk.red(`Session not found: ${options.resume}\n`));
|
|
278
|
-
process.exit(1);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
} else {
|
|
282
|
-
// Create new session
|
|
283
|
-
session = createSession(bot.id, bot.name);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Run on-start hooks
|
|
287
|
-
await runHooks('on-start', null, { botId: bot.id, botName: bot.name });
|
|
85
|
+
const shortModel = providerModel.split('/').pop().split('-').slice(0, 3).join('-');
|
|
288
86
|
|
|
289
|
-
// Skill prompts, AGENTS.md ve hafızayı yükle
|
|
290
87
|
const skillPrompts = getSkillPrompts();
|
|
291
88
|
const agentsPrompt = getAgentsPrompt();
|
|
292
89
|
const memoryPrompt = getMemoryPrompt(bot.id);
|
|
293
|
-
|
|
294
|
-
// Sistem promptunu birleştir
|
|
90
|
+
|
|
295
91
|
let systemPrompt = '';
|
|
296
92
|
if (skillPrompts) systemPrompt += skillPrompts;
|
|
297
|
-
if (agentsPrompt) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
93
|
+
if (agentsPrompt) systemPrompt += `\n\n## Project Instructions\n${agentsPrompt}`;
|
|
94
|
+
if (memoryPrompt) systemPrompt += '\n\n' + memoryPrompt;
|
|
95
|
+
|
|
96
|
+
// ── Session ─────────────────────────────────────────────────────────────────
|
|
97
|
+
let session;
|
|
98
|
+
if (options.resume) {
|
|
99
|
+
session = options.resume === true
|
|
100
|
+
? getLatestSession(bot.id) || createSession(bot.id, bot.name)
|
|
101
|
+
: loadSession(bot.id, options.resume) || createSession(bot.id, bot.name);
|
|
102
|
+
} else {
|
|
103
|
+
session = createSession(bot.id, bot.name);
|
|
304
104
|
}
|
|
305
105
|
|
|
306
106
|
let conversationId = null;
|
|
307
107
|
|
|
308
|
-
//
|
|
309
|
-
const
|
|
310
|
-
let
|
|
108
|
+
// ── What's New kontrolü ─────────────────────────────────────────────────────
|
|
109
|
+
const lastVersionFile = path.join(os.homedir(), '.natureco', 'lastVersion');
|
|
110
|
+
let lastVersion = '';
|
|
111
|
+
try { lastVersion = fs.readFileSync(lastVersionFile, 'utf8').trim(); } catch {}
|
|
112
|
+
const isNewVersion = lastVersion !== version;
|
|
113
|
+
|
|
114
|
+
// ── Blessed TUI ─────────────────────────────────────────────────────────────
|
|
115
|
+
let blessed;
|
|
116
|
+
try {
|
|
117
|
+
blessed = require('blessed');
|
|
118
|
+
} catch {
|
|
119
|
+
// blessed yüklü değilse fallback
|
|
120
|
+
return chatFallback(bot, botList, displayBotName, userName, shortModel, apiKey, config, systemPrompt, session, conversationId, options);
|
|
121
|
+
}
|
|
311
122
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
historySize: 100,
|
|
123
|
+
const screen = blessed.screen({
|
|
124
|
+
smartCSR: true,
|
|
125
|
+
title: `NatureCo · ${displayBotName}`,
|
|
126
|
+
terminal: 'xterm-256color',
|
|
127
|
+
fullUnicode: true,
|
|
318
128
|
});
|
|
319
129
|
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
console.log(chalk.yellow(`\n📦 Task moved to background: ${task.id}`));
|
|
335
|
-
console.log(chalk.gray('View with: natureco tasks show ' + task.id + '\n'));
|
|
336
|
-
|
|
337
|
-
// Run task in background
|
|
338
|
-
sendMessage(apiKey, bot.id, currentMessage, conversationId, systemPrompt)
|
|
339
|
-
.then(response => {
|
|
340
|
-
const reply = response.reply || response.message || 'No response';
|
|
341
|
-
updateBackgroundTask(task.id, {
|
|
342
|
-
status: 'completed',
|
|
343
|
-
result: reply,
|
|
344
|
-
completedAt: new Date().toISOString(),
|
|
345
|
-
});
|
|
346
|
-
})
|
|
347
|
-
.catch(err => {
|
|
348
|
-
updateBackgroundTask(task.id, {
|
|
349
|
-
status: 'failed',
|
|
350
|
-
error: err.message,
|
|
351
|
-
completedAt: new Date().toISOString(),
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
currentMessage = '';
|
|
356
|
-
rl.prompt();
|
|
357
|
-
}
|
|
358
|
-
}
|
|
130
|
+
// ── Logo kutusu (üst %30) ───────────────────────────────────────────────────
|
|
131
|
+
const rabbitLine = `{cyan-fg}(\\_{/}{cyan-fg}/) {/}{white-fg}Hoş geldin, ${userName}{/} {gray-fg}·{/} {cyan-fg}${displayBotName} hazır{/} {gray-fg}·{/} {gray-fg}v${version}{/}`;
|
|
132
|
+
const logoContent = ASCII_LOGO + '\n\n' + rabbitLine;
|
|
133
|
+
|
|
134
|
+
const logoBox = blessed.box({
|
|
135
|
+
top: 0,
|
|
136
|
+
left: 0,
|
|
137
|
+
width: '100%',
|
|
138
|
+
height: '28%',
|
|
139
|
+
content: logoContent,
|
|
140
|
+
align: 'center',
|
|
141
|
+
valign: 'middle',
|
|
142
|
+
tags: true,
|
|
143
|
+
style: { fg: 'green', bg: 'default' },
|
|
359
144
|
});
|
|
360
|
-
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
|
|
145
|
+
|
|
146
|
+
// ── Mesaj alanı (%58) ───────────────────────────────────────────────────────
|
|
147
|
+
const messageBox = blessed.log({
|
|
148
|
+
top: '28%',
|
|
149
|
+
left: 0,
|
|
150
|
+
width: '100%',
|
|
151
|
+
height: '58%',
|
|
152
|
+
scrollable: true,
|
|
153
|
+
alwaysScroll: true,
|
|
154
|
+
tags: true,
|
|
155
|
+
padding: { left: 2, right: 2, top: 1 },
|
|
156
|
+
scrollbar: { ch: '│', style: { fg: 'gray' } },
|
|
157
|
+
style: { bg: 'default' },
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ── Input kutusu (3 satır) ──────────────────────────────────────────────────
|
|
161
|
+
const inputBox = blessed.textbox({
|
|
162
|
+
bottom: 1,
|
|
163
|
+
left: 0,
|
|
164
|
+
width: '100%',
|
|
165
|
+
height: 3,
|
|
166
|
+
inputOnFocus: true,
|
|
167
|
+
padding: { left: 2 },
|
|
168
|
+
border: { type: 'line' },
|
|
169
|
+
style: {
|
|
170
|
+
border: { fg: 'green' },
|
|
171
|
+
fg: 'white',
|
|
172
|
+
bg: 'default',
|
|
173
|
+
focus: { border: { fg: 'cyan' } },
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ── Status bar (en alt 1 satır) ─────────────────────────────────────────────
|
|
178
|
+
const cwd = process.cwd().replace(os.homedir(), '~');
|
|
179
|
+
const statusBar = blessed.box({
|
|
180
|
+
bottom: 0,
|
|
181
|
+
left: 0,
|
|
182
|
+
width: '100%',
|
|
183
|
+
height: 1,
|
|
184
|
+
content: ` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${shortModel}{/}{|}${cwd} `,
|
|
185
|
+
tags: true,
|
|
186
|
+
style: { bg: 'default', fg: 'gray' },
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
screen.append(logoBox);
|
|
190
|
+
screen.append(messageBox);
|
|
191
|
+
screen.append(inputBox);
|
|
192
|
+
screen.append(statusBar);
|
|
193
|
+
|
|
194
|
+
inputBox.focus();
|
|
195
|
+
screen.render();
|
|
196
|
+
|
|
197
|
+
// ── What's New ──────────────────────────────────────────────────────────────
|
|
198
|
+
if (isNewVersion) {
|
|
199
|
+
messageBox.log(`{yellow-fg}─── v${version} yenilikleri ───{/}`);
|
|
200
|
+
CHANGELOG.forEach(c => messageBox.log(` {gray-fg}·{/} ${c}`));
|
|
201
|
+
messageBox.log('');
|
|
202
|
+
try { fs.writeFileSync(lastVersionFile, version); } catch {}
|
|
364
203
|
}
|
|
365
|
-
readline.emitKeypressEvents(process.stdin);
|
|
366
204
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
205
|
+
// Önceki session mesajlarını göster
|
|
206
|
+
if (options.resume && session.messages?.length) {
|
|
207
|
+
const last = session.messages.slice(-5);
|
|
208
|
+
last.forEach(msg => {
|
|
209
|
+
messageBox.log(`{white-fg}You{/} ${msg.user}`);
|
|
210
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${msg.bot}`);
|
|
211
|
+
messageBox.log('');
|
|
212
|
+
});
|
|
213
|
+
}
|
|
370
214
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
215
|
+
// ── Yükleme animasyonu ──────────────────────────────────────────────────────
|
|
216
|
+
let loadingTimer = null;
|
|
217
|
+
let loadingFrame = 0;
|
|
218
|
+
const loadingFrames = ['●○○', '○●○', '○○●'];
|
|
219
|
+
|
|
220
|
+
function startLoading() {
|
|
221
|
+
loadingFrame = 0;
|
|
222
|
+
loadingTimer = setInterval(() => {
|
|
223
|
+
statusBar.setContent(` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${loadingFrames[loadingFrame]}{/}{|}${cwd} `);
|
|
224
|
+
loadingFrame = (loadingFrame + 1) % loadingFrames.length;
|
|
225
|
+
screen.render();
|
|
226
|
+
}, 300);
|
|
227
|
+
}
|
|
375
228
|
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
|
|
229
|
+
function stopLoading() {
|
|
230
|
+
if (loadingTimer) { clearInterval(loadingTimer); loadingTimer = null; }
|
|
231
|
+
statusBar.setContent(` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${shortModel}{/}{|}${cwd} `);
|
|
232
|
+
screen.render();
|
|
233
|
+
}
|
|
379
234
|
|
|
380
|
-
|
|
235
|
+
// ── Mesaj gönderme ──────────────────────────────────────────────────────────
|
|
236
|
+
async function handleMessage(userMessage) {
|
|
237
|
+
userMessage = userMessage.trim();
|
|
238
|
+
if (!userMessage) { inputBox.focus(); screen.render(); return; }
|
|
239
|
+
|
|
240
|
+
// /komutlar
|
|
241
|
+
if (userMessage.startsWith('/')) {
|
|
242
|
+
const [cmd, ...args] = userMessage.slice(1).split(' ');
|
|
243
|
+
switch (cmd.toLowerCase()) {
|
|
381
244
|
case 'clear':
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// Rabbit with fixed unicode
|
|
385
|
-
const rabbitClear = chalk.cyan(' (\\\_/)') + '\n' +
|
|
386
|
-
chalk.cyan(' (•ᴥ•)') + '\n' +
|
|
387
|
-
chalk.cyan(' />') + chalk.green('🌿');
|
|
388
|
-
console.log(rabbitClear);
|
|
389
|
-
console.log('');
|
|
390
|
-
|
|
391
|
-
const terminalWidth2 = process.stdout.columns || 80;
|
|
392
|
-
const separator2 = '─'.repeat(terminalWidth2);
|
|
393
|
-
|
|
394
|
-
console.log(chalk.gray(separator2));
|
|
395
|
-
console.log(chalk.white.bold('NatureCo') + chalk.gray(' · ') + chalk.cyan(displayBotName) + chalk.gray(' · ') + chalk.gray(shortModel));
|
|
396
|
-
console.log(chalk.gray(separator2));
|
|
397
|
-
console.log('');
|
|
398
|
-
rl.prompt();
|
|
245
|
+
messageBox.setContent('');
|
|
246
|
+
screen.render();
|
|
399
247
|
return;
|
|
400
|
-
|
|
401
248
|
case 'bot':
|
|
402
|
-
if (args.length
|
|
403
|
-
|
|
404
|
-
console.log(chalk.gray('\nBot değiştirmek için: /bot <bot-adı>'));
|
|
405
|
-
console.log(chalk.gray('Mevcut botlar:'));
|
|
249
|
+
if (!args.length) {
|
|
250
|
+
messageBox.log(`{yellow-fg}Aktif bot:{/} ${bot.name}`);
|
|
406
251
|
botList.bots.forEach(b => {
|
|
407
|
-
const
|
|
408
|
-
|
|
252
|
+
const mark = b.id === bot.id ? '{green-fg}✓{/} ' : ' ';
|
|
253
|
+
messageBox.log(`${mark}{cyan-fg}${b.name}{/}`);
|
|
409
254
|
});
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return;
|
|
255
|
+
} else {
|
|
256
|
+
const newName = args.join(' ');
|
|
257
|
+
const newBot = botList.bots.find(b => b.name.toLowerCase() === newName.toLowerCase());
|
|
258
|
+
if (newBot) {
|
|
259
|
+
bot = newBot;
|
|
260
|
+
conversationId = null;
|
|
261
|
+
session = createSession(bot.id, bot.name);
|
|
262
|
+
messageBox.log(`{green-fg}Bot değişti: ${newBot.name}{/}`);
|
|
263
|
+
} else {
|
|
264
|
+
messageBox.log(`{red-fg}Bot bulunamadı: ${newName}{/}`);
|
|
265
|
+
}
|
|
422
266
|
}
|
|
423
|
-
|
|
424
|
-
bot = newBot;
|
|
425
|
-
conversationId = null;
|
|
426
|
-
session = createSession(bot.id, bot.name);
|
|
427
|
-
|
|
428
|
-
// Update displayBotName
|
|
429
|
-
const newMemory = loadMemory(bot.id);
|
|
430
|
-
const newDisplayBotName = newMemory.botName || bot.name;
|
|
431
|
-
|
|
432
|
-
console.log(chalk.green(`\nBot changed: ${newDisplayBotName}\n`));
|
|
433
|
-
console.log(chalk.gray(`Session: ${session.id}\n`));
|
|
434
|
-
rl.prompt();
|
|
267
|
+
screen.render();
|
|
435
268
|
return;
|
|
436
|
-
|
|
437
269
|
case 'skills':
|
|
438
270
|
const skills = getSkills();
|
|
439
|
-
if (skills.length
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
console.log(chalk.yellow('\nAktif skill\'ler:\n'));
|
|
443
|
-
skills.forEach(skill => {
|
|
444
|
-
console.log(chalk.cyan(` • ${skill.name}`) + chalk.gray(` (${skill.source})`));
|
|
445
|
-
console.log(chalk.gray(` ${skill.description}`));
|
|
446
|
-
});
|
|
447
|
-
console.log('');
|
|
448
|
-
}
|
|
449
|
-
rl.prompt();
|
|
271
|
+
if (!skills.length) { messageBox.log('{gray-fg}Yüklü skill yok.{/}'); }
|
|
272
|
+
else skills.forEach(s => messageBox.log(`{cyan-fg}· ${s.name}{/} {gray-fg}${s.description}{/}`));
|
|
273
|
+
screen.render();
|
|
450
274
|
return;
|
|
451
|
-
|
|
452
275
|
case 'memory':
|
|
453
|
-
if (args
|
|
276
|
+
if (args[0] === 'clear') {
|
|
454
277
|
clearMemory(bot.id);
|
|
455
|
-
|
|
456
|
-
rl.prompt();
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const memory = loadMemory(bot.id);
|
|
461
|
-
console.log(chalk.yellow('\nHafıza:\n'));
|
|
462
|
-
if (memory.botName) {
|
|
463
|
-
console.log(chalk.cyan(' Bot Adı:'), chalk.white(memory.botName));
|
|
464
|
-
}
|
|
465
|
-
if (memory.name) {
|
|
466
|
-
console.log(chalk.cyan(' İsim:'), chalk.white(memory.name));
|
|
467
|
-
}
|
|
468
|
-
if (memory.preferences.length > 0) {
|
|
469
|
-
const sortedPrefs = memory.preferences.sort((a, b) => b.score - a.score);
|
|
470
|
-
console.log(chalk.cyan(' Tercihler:'));
|
|
471
|
-
sortedPrefs.forEach(p => {
|
|
472
|
-
console.log(chalk.white(` • ${p.value}`) + chalk.gray(` (skor: ${p.score})`));
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
if (memory.facts.length > 0) {
|
|
476
|
-
const sortedFacts = memory.facts.sort((a, b) => b.score - a.score);
|
|
477
|
-
console.log(chalk.cyan(' Bilgiler:'));
|
|
478
|
-
sortedFacts.forEach(f => {
|
|
479
|
-
console.log(chalk.white(` • ${f.value}`) + chalk.gray(` (skor: ${f.score})`));
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
if (!memory.botName && !memory.name && memory.preferences.length === 0 && memory.facts.length === 0) {
|
|
483
|
-
console.log(chalk.gray(' Henüz hafıza yok'));
|
|
484
|
-
}
|
|
485
|
-
console.log('');
|
|
486
|
-
rl.prompt();
|
|
487
|
-
return;
|
|
488
|
-
|
|
489
|
-
case 'commands':
|
|
490
|
-
const commands = getCommands();
|
|
491
|
-
if (commands.length === 0) {
|
|
492
|
-
console.log(chalk.gray('\nÖzel komut yok.\n'));
|
|
493
|
-
console.log(chalk.gray('Oluşturmak için: natureco commands create <ad>\n'));
|
|
278
|
+
messageBox.log('{green-fg}✓ Hafıza temizlendi{/}');
|
|
494
279
|
} else {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
280
|
+
const m = loadMemory(bot.id);
|
|
281
|
+
if (m.botName) messageBox.log(`{cyan-fg}Bot:{/} ${m.botName}`);
|
|
282
|
+
if (m.name) messageBox.log(`{cyan-fg}İsim:{/} ${m.name}`);
|
|
283
|
+
(m.facts || []).slice(0, 8).forEach(f => {
|
|
284
|
+
const v = typeof f === 'string' ? f : f.value;
|
|
285
|
+
messageBox.log(`{gray-fg}· ${v}{/}`);
|
|
499
286
|
});
|
|
500
|
-
console.log('');
|
|
501
287
|
}
|
|
502
|
-
|
|
288
|
+
screen.render();
|
|
503
289
|
return;
|
|
504
|
-
|
|
505
290
|
case 'help':
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
rl.prompt();
|
|
291
|
+
[
|
|
292
|
+
'{yellow-fg}Chat Komutları:{/}',
|
|
293
|
+
'{cyan-fg}/clear{/} Ekranı temizle',
|
|
294
|
+
'{cyan-fg}/bot [ad]{/} Bot değiştir',
|
|
295
|
+
'{cyan-fg}/skills{/} Skill listesi',
|
|
296
|
+
'{cyan-fg}/memory{/} Hafızayı göster',
|
|
297
|
+
'{cyan-fg}/memory clear{/} Hafızayı temizle',
|
|
298
|
+
'{cyan-fg}/commands{/} Özel komutlar',
|
|
299
|
+
'{cyan-fg}/help{/} Bu yardım',
|
|
300
|
+
'{gray-fg}Ctrl+C Çıkış{/}',
|
|
301
|
+
].forEach(l => messageBox.log(l));
|
|
302
|
+
screen.render();
|
|
519
303
|
return;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
let lastCodeBlock = null;
|
|
527
|
-
for (let i = chatHistory.length - 1; i >= 0; i--) {
|
|
528
|
-
const msg = chatHistory[i];
|
|
529
|
-
const codeMatch = (msg.bot || '').match(/```[\s\S]*?\n([\s\S]*?)```/);
|
|
530
|
-
if (codeMatch) {
|
|
531
|
-
lastCodeBlock = codeMatch[1];
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
if (!lastCodeBlock) {
|
|
537
|
-
console.log(chalk.yellow('\n⚠️ Konuşmada kod bloğu bulunamadı\n'));
|
|
538
|
-
rl.prompt();
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
console.log(chalk.yellow('\n⏳ Kod inceleniyor...\n'));
|
|
543
|
-
|
|
544
|
-
const reviewPrompt = `Aşağıdaki kodu çok detaylı incele ve şu kategorilerde analiz et:
|
|
545
|
-
|
|
546
|
-
1. **Güvenlik Açıkları** (1-10 puan)
|
|
547
|
-
2. **Performans Sorunları** (1-10 puan)
|
|
548
|
-
3. **Kod Kalitesi** (1-10 puan)
|
|
549
|
-
4. **Hata Yönetimi** (1-10 puan)
|
|
550
|
-
5. **Best Practices** (1-10 puan)
|
|
551
|
-
6. **Potansiyel Bug'lar**
|
|
552
|
-
|
|
553
|
-
Her kategori için puan ver ve sorunları listele.
|
|
554
|
-
|
|
555
|
-
\`\`\`
|
|
556
|
-
${lastCodeBlock}
|
|
557
|
-
\`\`\``;
|
|
558
|
-
|
|
559
|
-
const loadingInterval = startLoadingAnimation();
|
|
560
|
-
|
|
561
|
-
try {
|
|
562
|
-
const response = await sendMessage(apiKey, bot.id, reviewPrompt, conversationId, systemPrompt);
|
|
563
|
-
|
|
564
|
-
stopLoadingAnimation(loadingInterval);
|
|
565
|
-
|
|
566
|
-
if (response.conversation_id) {
|
|
567
|
-
conversationId = response.conversation_id;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const botReply = response.reply || response.message || 'No response';
|
|
571
|
-
console.log(chalk.cyan(`${displayBotName} `) + botReply + '\n');
|
|
572
|
-
|
|
573
|
-
addToHistory(bot.id, '/ultrareview', botReply, conversationId);
|
|
574
|
-
addMessageToSession(bot.id, session.id, '/ultrareview', botReply);
|
|
575
|
-
} catch (err) {
|
|
576
|
-
stopLoadingAnimation(loadingInterval);
|
|
577
|
-
// Extract clean error message
|
|
578
|
-
const errorMsg = err.message.split('"message":"')[1]?.split('"')[0] || err.message;
|
|
579
|
-
console.log(chalk.red(`Error: ${errorMsg}\n`));
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
rl.prompt();
|
|
304
|
+
case 'commands':
|
|
305
|
+
const cmds = getCommands();
|
|
306
|
+
if (!cmds.length) messageBox.log('{gray-fg}Özel komut yok.{/}');
|
|
307
|
+
else cmds.forEach(c => messageBox.log(`{cyan-fg}/${c.name}{/}`));
|
|
308
|
+
screen.render();
|
|
583
309
|
return;
|
|
584
|
-
|
|
585
310
|
default:
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
// If there are args, use them as the message
|
|
594
|
-
const message = args.length > 0 ? args.join(' ') : 'Execute the custom command instruction';
|
|
595
|
-
|
|
596
|
-
const loadingInterval = startLoadingAnimation();
|
|
597
|
-
|
|
311
|
+
const customCmd = getCommandContent(cmd);
|
|
312
|
+
if (customCmd) {
|
|
313
|
+
const customPrompt = systemPrompt + '\n\n## Custom Command\n' + customCmd;
|
|
314
|
+
const msg = args.length ? args.join(' ') : 'Execute the custom command instruction';
|
|
315
|
+
messageBox.log(`{white-fg}You{/} ${userMessage}`);
|
|
316
|
+
startLoading();
|
|
598
317
|
try {
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
stopLoadingAnimation(loadingInterval);
|
|
614
|
-
// Extract clean error message
|
|
615
|
-
const errorMsg = err.message.split('"message":"')[1]?.split('"')[0] || err.message;
|
|
616
|
-
console.log(chalk.red(`Error: ${errorMsg}\n`));
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
rl.prompt();
|
|
620
|
-
return;
|
|
318
|
+
const res = await sendMessage(apiKey || config.providerApiKey, bot.id, msg, conversationId, customPrompt);
|
|
319
|
+
stopLoading();
|
|
320
|
+
if (res.conversation_id) conversationId = res.conversation_id;
|
|
321
|
+
const reply = res.reply || res.message || '';
|
|
322
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${reply}`);
|
|
323
|
+
messageBox.log('');
|
|
324
|
+
addToHistory(bot.id, userMessage, reply, conversationId);
|
|
325
|
+
addMessageToSession(bot.id, session.id, userMessage, reply);
|
|
326
|
+
} catch (e) { stopLoading(); messageBox.log(`{red-fg}Error: ${e.message}{/}`); }
|
|
327
|
+
messageBox.setScrollPerc(100);
|
|
328
|
+
screen.render();
|
|
329
|
+
} else {
|
|
330
|
+
messageBox.log(`{red-fg}Bilinmeyen komut: /${cmd}{/}`);
|
|
331
|
+
screen.render();
|
|
621
332
|
}
|
|
622
|
-
|
|
623
|
-
console.log(chalk.red(`\n❌ Bilinmeyen komut: /${command}`));
|
|
624
|
-
console.log(chalk.gray('Yardım için: /help\n'));
|
|
625
|
-
rl.prompt();
|
|
626
333
|
return;
|
|
627
334
|
}
|
|
628
335
|
}
|
|
629
336
|
|
|
630
|
-
//
|
|
631
|
-
if (userMessage
|
|
337
|
+
// exit/quit
|
|
338
|
+
if (userMessage === 'exit' || userMessage === 'quit') {
|
|
632
339
|
await runHooks('on-exit', null, { botId: bot.id, botName: bot.name });
|
|
633
|
-
|
|
634
|
-
rl.close();
|
|
340
|
+
screen.destroy();
|
|
635
341
|
process.exit(0);
|
|
636
342
|
}
|
|
637
343
|
|
|
638
|
-
//
|
|
344
|
+
// Normal mesaj
|
|
639
345
|
userMessage = await runHooks('pre-message', userMessage, { botId: bot.id, botName: bot.name });
|
|
346
|
+
messageBox.log(`{white-fg}You{/} ${userMessage}`);
|
|
347
|
+
messageBox.setScrollPerc(100);
|
|
348
|
+
screen.render();
|
|
640
349
|
|
|
641
|
-
|
|
642
|
-
const loadingInterval = startLoadingAnimation();
|
|
350
|
+
startLoading();
|
|
643
351
|
|
|
644
352
|
try {
|
|
645
|
-
// Get tool definitions
|
|
646
353
|
const toolDefinitions = getToolDefinitions();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
stopLoadingAnimation(loadingInterval);
|
|
652
|
-
|
|
653
|
-
if (response.conversation_id) {
|
|
654
|
-
conversationId = response.conversation_id;
|
|
655
|
-
}
|
|
354
|
+
let response = await _sendMessage(apiKey || config.providerApiKey, bot.id, userMessage, conversationId, systemPrompt, toolDefinitions);
|
|
355
|
+
stopLoading();
|
|
356
|
+
|
|
357
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
656
358
|
|
|
657
|
-
// Tool
|
|
658
|
-
let
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
while (iteration < maxIterations) {
|
|
662
|
-
// Check for tool calls
|
|
359
|
+
// Tool loop
|
|
360
|
+
let iter = 0;
|
|
361
|
+
while (iter < 5) {
|
|
663
362
|
const toolCalls = extractToolCalls(response);
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
break;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
console.log(chalk.yellow(`\n🔧 Executing ${toolCalls.length} tool(s)...\n`));
|
|
671
|
-
|
|
672
|
-
// Execute tools
|
|
363
|
+
if (!toolCalls?.length) break;
|
|
364
|
+
messageBox.log(`{yellow-fg}🔧 ${toolCalls.length} tool çalıştırılıyor...{/}`);
|
|
365
|
+
screen.render();
|
|
673
366
|
const toolResults = await executeToolCalls(toolCalls);
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
return `Tool: ${tr.name}\nResult: ${resultStr}`;
|
|
681
|
-
}).join('\n\n');
|
|
682
|
-
|
|
683
|
-
console.log(chalk.blue('\n📤 Sending tool results back to bot...\n'));
|
|
684
|
-
|
|
685
|
-
// Send tool results back to API
|
|
686
|
-
const loadingInterval2 = startLoadingAnimation();
|
|
687
|
-
response = await _sendMessage(apiKey, bot.id, toolResultMessage, conversationId, systemPrompt, toolDefinitions);
|
|
688
|
-
stopLoadingAnimation(loadingInterval2);
|
|
689
|
-
|
|
690
|
-
if (response.conversation_id) {
|
|
691
|
-
conversationId = response.conversation_id;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
iteration++;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
if (iteration >= maxIterations) {
|
|
698
|
-
console.log(chalk.yellow('\n⚠️ Max tool iterations reached\n'));
|
|
367
|
+
const toolMsg = toolResults.map(tr => `Tool: ${tr.name}\nResult: ${tr.result.success ? (tr.result.output || '') : tr.result.error}`).join('\n\n');
|
|
368
|
+
startLoading();
|
|
369
|
+
response = await _sendMessage(apiKey || config.providerApiKey, bot.id, toolMsg, conversationId, systemPrompt, toolDefinitions);
|
|
370
|
+
stopLoading();
|
|
371
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
372
|
+
iter++;
|
|
699
373
|
}
|
|
700
374
|
|
|
701
375
|
let botReply = response.reply || response.message || 'No response';
|
|
702
|
-
|
|
703
|
-
// Run post-message hooks
|
|
704
376
|
botReply = await runHooks('post-message', botReply, { botId: bot.id, botName: bot.name });
|
|
705
|
-
|
|
706
|
-
console.log(chalk.cyan(`${displayBotName} `) + botReply + '\n');
|
|
707
377
|
|
|
708
|
-
|
|
378
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${botReply}`);
|
|
379
|
+
messageBox.log('');
|
|
380
|
+
messageBox.setScrollPerc(100);
|
|
381
|
+
screen.render();
|
|
382
|
+
|
|
709
383
|
addToHistory(bot.id, userMessage, botReply, conversationId);
|
|
710
384
|
addMessageToSession(bot.id, session.id, userMessage, botReply);
|
|
711
385
|
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
const { addMemoryEntry } = require('../utils/memory');
|
|
716
|
-
addMemoryEntry(bot.id, entry.key, entry.value);
|
|
717
|
-
}
|
|
386
|
+
const memEntries = extractMemoryFromMessage(userMessage);
|
|
387
|
+
for (const e of memEntries) addMemoryEntry(bot.id, e.key, e.value);
|
|
388
|
+
|
|
718
389
|
} catch (err) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
390
|
+
stopLoading();
|
|
391
|
+
const errMsg = err.message.split('"message":"')[1]?.split('"')[0] || err.message;
|
|
392
|
+
messageBox.log(`{red-fg}Error: ${errMsg}{/}`);
|
|
393
|
+
messageBox.setScrollPerc(100);
|
|
394
|
+
screen.render();
|
|
723
395
|
}
|
|
724
396
|
|
|
725
|
-
|
|
726
|
-
rl.prompt();
|
|
397
|
+
inputBox.focus();
|
|
727
398
|
}
|
|
728
399
|
|
|
729
|
-
|
|
730
|
-
|
|
400
|
+
// ── Enter tuşu ──────────────────────────────────────────────────────────────
|
|
401
|
+
inputBox.key('enter', async () => {
|
|
402
|
+
const msg = inputBox.getValue();
|
|
403
|
+
inputBox.clearValue();
|
|
404
|
+
screen.render();
|
|
405
|
+
await handleMessage(msg);
|
|
406
|
+
inputBox.focus();
|
|
407
|
+
screen.render();
|
|
731
408
|
});
|
|
732
409
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
410
|
+
// ── Ctrl+C çıkış ────────────────────────────────────────────────────────────
|
|
411
|
+
screen.key(['C-c'], async () => {
|
|
412
|
+
await runHooks('on-exit', null, { botId: bot.id, botName: bot.name });
|
|
413
|
+
screen.destroy();
|
|
414
|
+
process.exit(0);
|
|
738
415
|
});
|
|
739
416
|
|
|
740
|
-
|
|
741
|
-
}
|
|
417
|
+
// ── on-start hooks ──────────────────────────────────────────────────────────
|
|
418
|
+
await runHooks('on-start', null, { botId: bot.id, botName: bot.name });
|
|
742
419
|
|
|
743
|
-
|
|
744
|
-
const frames = ['●○○', '○●○', '○○●'];
|
|
745
|
-
let i = 0;
|
|
746
|
-
|
|
747
|
-
// Get displayBotName from current context (will be passed as parameter)
|
|
748
|
-
process.stdout.write(chalk.cyan('... '));
|
|
749
|
-
|
|
750
|
-
return setInterval(() => {
|
|
751
|
-
process.stdout.write(`\r${chalk.cyan(frames[i] + ' ')}`);
|
|
752
|
-
i = (i + 1) % frames.length;
|
|
753
|
-
}, 300);
|
|
420
|
+
screen.render();
|
|
754
421
|
}
|
|
755
422
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
423
|
+
// ── Fallback: blessed yoksa eski readline tabanlı chat ────────────────────────
|
|
424
|
+
async function chatFallback(bot, botList, displayBotName, userName, shortModel, apiKey, config, systemPrompt, session, conversationId, options) {
|
|
425
|
+
const readline = require('readline');
|
|
426
|
+
const chalk = require('chalk');
|
|
427
|
+
|
|
428
|
+
console.clear();
|
|
429
|
+
console.log(chalk.green.bold(' (\\_/)'));
|
|
430
|
+
console.log(chalk.green.bold(' (•ᴥ•)'));
|
|
431
|
+
console.log(chalk.green(' />🌿'));
|
|
432
|
+
console.log('');
|
|
433
|
+
const sep = chalk.gray('─'.repeat(process.stdout.columns || 80));
|
|
434
|
+
console.log(sep);
|
|
435
|
+
console.log(chalk.white.bold('NatureCo') + chalk.gray(' · ') + chalk.cyan(displayBotName) + chalk.gray(' · ') + chalk.gray(shortModel));
|
|
436
|
+
console.log(sep);
|
|
437
|
+
console.log('');
|
|
438
|
+
|
|
439
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: chalk.gray('You ') });
|
|
440
|
+
rl.prompt();
|
|
441
|
+
|
|
442
|
+
rl.on('line', async (line) => {
|
|
443
|
+
const msg = line.trim();
|
|
444
|
+
if (!msg) { rl.prompt(); return; }
|
|
445
|
+
if (msg === 'exit' || msg === 'quit') { console.log(chalk.gray('\n👋 Goodbye!\n')); process.exit(0); }
|
|
446
|
+
|
|
447
|
+
process.stdout.write(chalk.cyan('... '));
|
|
448
|
+
try {
|
|
449
|
+
const toolDefinitions = getToolDefinitions();
|
|
450
|
+
const response = await _sendMessage(apiKey || config.providerApiKey, bot.id, msg, conversationId, systemPrompt, toolDefinitions);
|
|
451
|
+
process.stdout.write('\r');
|
|
452
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
453
|
+
const reply = response.reply || response.message || '';
|
|
454
|
+
console.log(chalk.cyan(`${displayBotName} `) + reply + '\n');
|
|
455
|
+
addToHistory(bot.id, msg, reply, conversationId);
|
|
456
|
+
addMessageToSession(bot.id, session.id, msg, reply);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
process.stdout.write('\r');
|
|
459
|
+
console.log(chalk.red(`Error: ${e.message}\n`));
|
|
460
|
+
}
|
|
461
|
+
rl.prompt();
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
rl.on('close', () => process.exit(0));
|
|
759
465
|
}
|
|
760
466
|
|
|
761
467
|
module.exports = chat;
|
|
@@ -211,7 +211,7 @@ body::before{
|
|
|
211
211
|
<div class="header-bot-name" id="header-bot-name">Nature Bot</div>
|
|
212
212
|
<div class="header-bot-model" id="header-bot-model">NatureCo</div>
|
|
213
213
|
</div>
|
|
214
|
-
<div class="version-badge" id="version-badge">v2.17.
|
|
214
|
+
<div class="version-badge" id="version-badge">v2.17.6</div>
|
|
215
215
|
</div>
|
|
216
216
|
<div class="messages" id="messages"></div>
|
|
217
217
|
<div class="input-area">
|
|
@@ -341,7 +341,7 @@ function dashboard(action) {
|
|
|
341
341
|
apiKey: cfg.apiKey,
|
|
342
342
|
defaultBot: cfg.defaultBot,
|
|
343
343
|
defaultBotId: cfg.defaultBotId,
|
|
344
|
-
version: 'v2.17.
|
|
344
|
+
version: 'v2.17.6',
|
|
345
345
|
bots: cfg.bots || [],
|
|
346
346
|
telegramToken: cfg.telegramToken || null,
|
|
347
347
|
whatsappConnected: cfg.whatsappConnected || false,
|
|
@@ -322,9 +322,10 @@ async function startWhatsAppProvider(sessionDir, config) {
|
|
|
322
322
|
log('whatsapp', `Inbound message +${sender} -> +${ownNumber} (${messageText.length} chars)`, 'cyan');
|
|
323
323
|
|
|
324
324
|
try {
|
|
325
|
-
// v2.x: Send to universal provider (Groq/OpenAI/Anthropic)
|
|
326
325
|
const { sendMessage } = require('../utils/api');
|
|
327
326
|
const { getMemoryPrompt, extractMemoryFromMessage, addMemoryEntry } = require('../utils/memory');
|
|
327
|
+
const { getConfig } = require('../utils/config');
|
|
328
|
+
const cfg = getConfig();
|
|
328
329
|
|
|
329
330
|
log('whatsapp', 'Sending to AI provider...', 'cyan');
|
|
330
331
|
|
|
@@ -342,7 +343,7 @@ async function startWhatsAppProvider(sessionDir, config) {
|
|
|
342
343
|
systemPrompt += '\n\n' + memoryPrompt;
|
|
343
344
|
}
|
|
344
345
|
|
|
345
|
-
const response = await sendMessage(
|
|
346
|
+
const response = await sendMessage(cfg.providerApiKey || cfg.apiKey || '', botId, messageText, conversationId, systemPrompt);
|
|
346
347
|
const reply = response?.reply || response?.message || '';
|
|
347
348
|
|
|
348
349
|
if (reply) {
|
|
@@ -417,6 +418,8 @@ async function startTelegramProvider(config) {
|
|
|
417
418
|
try {
|
|
418
419
|
const { sendMessage } = require('../utils/api');
|
|
419
420
|
const { getMemoryPrompt, extractMemoryFromMessage, addMemoryEntry } = require('../utils/memory');
|
|
421
|
+
const { getConfig } = require('../utils/config');
|
|
422
|
+
const cfg = getConfig();
|
|
420
423
|
|
|
421
424
|
log('telegram', 'Sending to AI provider...', 'cyan');
|
|
422
425
|
|
|
@@ -434,7 +437,7 @@ async function startTelegramProvider(config) {
|
|
|
434
437
|
systemPrompt += '\n\n' + memoryPrompt;
|
|
435
438
|
}
|
|
436
439
|
|
|
437
|
-
const response = await sendMessage(
|
|
440
|
+
const response = await sendMessage(cfg.providerApiKey || cfg.apiKey || '', botId, messageText, conversationId, systemPrompt);
|
|
438
441
|
const reply = response?.reply || response?.message || '';
|
|
439
442
|
|
|
440
443
|
if (reply) {
|