natureco-cli 2.17.1 → 2.17.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/bin/natureco.js +35 -0
- package/package.json +2 -1
- package/src/commands/agents.js +141 -0
- package/src/commands/chat.js +339 -634
- package/src/commands/dashboard.js +2 -2
- package/src/commands/gateway-server.js +6 -3
- package/src/commands/help.js +4 -0
- package/src/commands/pairing.js +107 -0
- package/src/commands/plugins.js +172 -0
- package/src/commands/uninstall.js +92 -0
- package/src/utils/config.js +25 -9
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,451 @@ 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
|
-
prompt: chalk.gray('You '),
|
|
317
|
-
historySize: 100,
|
|
123
|
+
const screen = blessed.screen({
|
|
124
|
+
smartCSR: true,
|
|
125
|
+
title: `NatureCo · ${displayBotName}`,
|
|
126
|
+
fullUnicode: true,
|
|
318
127
|
});
|
|
319
128
|
|
|
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
|
-
}
|
|
129
|
+
// ── Logo kutusu (üst %30) ───────────────────────────────────────────────────
|
|
130
|
+
const rabbitLine = `{cyan-fg}(\\_{/}{cyan-fg}/) {/}{white-fg}Hoş geldin, ${userName}{/} {gray-fg}·{/} {cyan-fg}${displayBotName} hazır{/} {gray-fg}·{/} {gray-fg}v${version}{/}`;
|
|
131
|
+
const logoContent = ASCII_LOGO + '\n\n' + rabbitLine;
|
|
132
|
+
|
|
133
|
+
const logoBox = blessed.box({
|
|
134
|
+
top: 0,
|
|
135
|
+
left: 0,
|
|
136
|
+
width: '100%',
|
|
137
|
+
height: '28%',
|
|
138
|
+
content: logoContent,
|
|
139
|
+
align: 'center',
|
|
140
|
+
valign: 'middle',
|
|
141
|
+
tags: true,
|
|
142
|
+
style: { fg: 'green', bg: 'black' },
|
|
359
143
|
});
|
|
360
|
-
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
|
|
144
|
+
|
|
145
|
+
// ── Mesaj alanı (%58) ───────────────────────────────────────────────────────
|
|
146
|
+
const messageBox = blessed.log({
|
|
147
|
+
top: '28%',
|
|
148
|
+
left: 0,
|
|
149
|
+
width: '100%',
|
|
150
|
+
height: '58%',
|
|
151
|
+
scrollable: true,
|
|
152
|
+
alwaysScroll: true,
|
|
153
|
+
tags: true,
|
|
154
|
+
padding: { left: 2, right: 2, top: 1 },
|
|
155
|
+
scrollbar: { ch: '│', style: { fg: 'gray' } },
|
|
156
|
+
style: { bg: 'black' },
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ── Input kutusu (3 satır) ──────────────────────────────────────────────────
|
|
160
|
+
const inputBox = blessed.textbox({
|
|
161
|
+
bottom: 1,
|
|
162
|
+
left: 0,
|
|
163
|
+
width: '100%',
|
|
164
|
+
height: 3,
|
|
165
|
+
inputOnFocus: true,
|
|
166
|
+
padding: { left: 2 },
|
|
167
|
+
border: { type: 'line' },
|
|
168
|
+
style: {
|
|
169
|
+
border: { fg: 'green' },
|
|
170
|
+
fg: 'white',
|
|
171
|
+
bg: 'black',
|
|
172
|
+
focus: { border: { fg: 'cyan' } },
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// ── Status bar (en alt 1 satır) ─────────────────────────────────────────────
|
|
177
|
+
const cwd = process.cwd().replace(os.homedir(), '~');
|
|
178
|
+
const statusBar = blessed.box({
|
|
179
|
+
bottom: 0,
|
|
180
|
+
left: 0,
|
|
181
|
+
width: '100%',
|
|
182
|
+
height: 1,
|
|
183
|
+
content: ` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${shortModel}{/}{|}${cwd} `,
|
|
184
|
+
tags: true,
|
|
185
|
+
style: { bg: 'black', fg: 'gray' },
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
screen.append(logoBox);
|
|
189
|
+
screen.append(messageBox);
|
|
190
|
+
screen.append(inputBox);
|
|
191
|
+
screen.append(statusBar);
|
|
192
|
+
|
|
193
|
+
inputBox.focus();
|
|
194
|
+
screen.render();
|
|
195
|
+
|
|
196
|
+
// ── What's New ──────────────────────────────────────────────────────────────
|
|
197
|
+
if (isNewVersion) {
|
|
198
|
+
messageBox.log(`{yellow-fg}─── v${version} yenilikleri ───{/}`);
|
|
199
|
+
CHANGELOG.forEach(c => messageBox.log(` {gray-fg}·{/} ${c}`));
|
|
200
|
+
messageBox.log('');
|
|
201
|
+
try { fs.writeFileSync(lastVersionFile, version); } catch {}
|
|
364
202
|
}
|
|
365
|
-
readline.emitKeypressEvents(process.stdin);
|
|
366
203
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
204
|
+
// Önceki session mesajlarını göster
|
|
205
|
+
if (options.resume && session.messages?.length) {
|
|
206
|
+
const last = session.messages.slice(-5);
|
|
207
|
+
last.forEach(msg => {
|
|
208
|
+
messageBox.log(`{white-fg}You{/} ${msg.user}`);
|
|
209
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${msg.bot}`);
|
|
210
|
+
messageBox.log('');
|
|
211
|
+
});
|
|
212
|
+
}
|
|
370
213
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
214
|
+
// ── Yükleme animasyonu ──────────────────────────────────────────────────────
|
|
215
|
+
let loadingTimer = null;
|
|
216
|
+
let loadingFrame = 0;
|
|
217
|
+
const loadingFrames = ['●○○', '○●○', '○○●'];
|
|
218
|
+
|
|
219
|
+
function startLoading() {
|
|
220
|
+
loadingFrame = 0;
|
|
221
|
+
loadingTimer = setInterval(() => {
|
|
222
|
+
statusBar.setContent(` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${loadingFrames[loadingFrame]}{/}{|}${cwd} `);
|
|
223
|
+
loadingFrame = (loadingFrame + 1) % loadingFrames.length;
|
|
224
|
+
screen.render();
|
|
225
|
+
}, 300);
|
|
226
|
+
}
|
|
375
227
|
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
|
|
228
|
+
function stopLoading() {
|
|
229
|
+
if (loadingTimer) { clearInterval(loadingTimer); loadingTimer = null; }
|
|
230
|
+
statusBar.setContent(` {cyan-fg}${displayBotName}{/} {gray-fg}·{/} {gray-fg}${shortModel}{/}{|}${cwd} `);
|
|
231
|
+
screen.render();
|
|
232
|
+
}
|
|
379
233
|
|
|
380
|
-
|
|
234
|
+
// ── Mesaj gönderme ──────────────────────────────────────────────────────────
|
|
235
|
+
async function handleMessage(userMessage) {
|
|
236
|
+
userMessage = userMessage.trim();
|
|
237
|
+
if (!userMessage) { inputBox.focus(); screen.render(); return; }
|
|
238
|
+
|
|
239
|
+
// /komutlar
|
|
240
|
+
if (userMessage.startsWith('/')) {
|
|
241
|
+
const [cmd, ...args] = userMessage.slice(1).split(' ');
|
|
242
|
+
switch (cmd.toLowerCase()) {
|
|
381
243
|
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();
|
|
244
|
+
messageBox.setContent('');
|
|
245
|
+
screen.render();
|
|
399
246
|
return;
|
|
400
|
-
|
|
401
247
|
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:'));
|
|
248
|
+
if (!args.length) {
|
|
249
|
+
messageBox.log(`{yellow-fg}Aktif bot:{/} ${bot.name}`);
|
|
406
250
|
botList.bots.forEach(b => {
|
|
407
|
-
const
|
|
408
|
-
|
|
251
|
+
const mark = b.id === bot.id ? '{green-fg}✓{/} ' : ' ';
|
|
252
|
+
messageBox.log(`${mark}{cyan-fg}${b.name}{/}`);
|
|
409
253
|
});
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return;
|
|
254
|
+
} else {
|
|
255
|
+
const newName = args.join(' ');
|
|
256
|
+
const newBot = botList.bots.find(b => b.name.toLowerCase() === newName.toLowerCase());
|
|
257
|
+
if (newBot) {
|
|
258
|
+
bot = newBot;
|
|
259
|
+
conversationId = null;
|
|
260
|
+
session = createSession(bot.id, bot.name);
|
|
261
|
+
messageBox.log(`{green-fg}Bot değişti: ${newBot.name}{/}`);
|
|
262
|
+
} else {
|
|
263
|
+
messageBox.log(`{red-fg}Bot bulunamadı: ${newName}{/}`);
|
|
264
|
+
}
|
|
422
265
|
}
|
|
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();
|
|
266
|
+
screen.render();
|
|
435
267
|
return;
|
|
436
|
-
|
|
437
268
|
case 'skills':
|
|
438
269
|
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();
|
|
270
|
+
if (!skills.length) { messageBox.log('{gray-fg}Yüklü skill yok.{/}'); }
|
|
271
|
+
else skills.forEach(s => messageBox.log(`{cyan-fg}· ${s.name}{/} {gray-fg}${s.description}{/}`));
|
|
272
|
+
screen.render();
|
|
450
273
|
return;
|
|
451
|
-
|
|
452
274
|
case 'memory':
|
|
453
|
-
if (args
|
|
275
|
+
if (args[0] === 'clear') {
|
|
454
276
|
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'));
|
|
277
|
+
messageBox.log('{green-fg}✓ Hafıza temizlendi{/}');
|
|
494
278
|
} else {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
279
|
+
const m = loadMemory(bot.id);
|
|
280
|
+
if (m.botName) messageBox.log(`{cyan-fg}Bot:{/} ${m.botName}`);
|
|
281
|
+
if (m.name) messageBox.log(`{cyan-fg}İsim:{/} ${m.name}`);
|
|
282
|
+
(m.facts || []).slice(0, 8).forEach(f => {
|
|
283
|
+
const v = typeof f === 'string' ? f : f.value;
|
|
284
|
+
messageBox.log(`{gray-fg}· ${v}{/}`);
|
|
499
285
|
});
|
|
500
|
-
console.log('');
|
|
501
286
|
}
|
|
502
|
-
|
|
287
|
+
screen.render();
|
|
503
288
|
return;
|
|
504
|
-
|
|
505
289
|
case 'help':
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
rl.prompt();
|
|
290
|
+
[
|
|
291
|
+
'{yellow-fg}Chat Komutları:{/}',
|
|
292
|
+
'{cyan-fg}/clear{/} Ekranı temizle',
|
|
293
|
+
'{cyan-fg}/bot [ad]{/} Bot değiştir',
|
|
294
|
+
'{cyan-fg}/skills{/} Skill listesi',
|
|
295
|
+
'{cyan-fg}/memory{/} Hafızayı göster',
|
|
296
|
+
'{cyan-fg}/memory clear{/} Hafızayı temizle',
|
|
297
|
+
'{cyan-fg}/commands{/} Özel komutlar',
|
|
298
|
+
'{cyan-fg}/help{/} Bu yardım',
|
|
299
|
+
'{gray-fg}Ctrl+C Çıkış{/}',
|
|
300
|
+
].forEach(l => messageBox.log(l));
|
|
301
|
+
screen.render();
|
|
519
302
|
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();
|
|
303
|
+
case 'commands':
|
|
304
|
+
const cmds = getCommands();
|
|
305
|
+
if (!cmds.length) messageBox.log('{gray-fg}Özel komut yok.{/}');
|
|
306
|
+
else cmds.forEach(c => messageBox.log(`{cyan-fg}/${c.name}{/}`));
|
|
307
|
+
screen.render();
|
|
583
308
|
return;
|
|
584
|
-
|
|
585
309
|
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
|
-
|
|
310
|
+
const customCmd = getCommandContent(cmd);
|
|
311
|
+
if (customCmd) {
|
|
312
|
+
const customPrompt = systemPrompt + '\n\n## Custom Command\n' + customCmd;
|
|
313
|
+
const msg = args.length ? args.join(' ') : 'Execute the custom command instruction';
|
|
314
|
+
messageBox.log(`{white-fg}You{/} ${userMessage}`);
|
|
315
|
+
startLoading();
|
|
598
316
|
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;
|
|
317
|
+
const res = await sendMessage(apiKey || config.providerApiKey, bot.id, msg, conversationId, customPrompt);
|
|
318
|
+
stopLoading();
|
|
319
|
+
if (res.conversation_id) conversationId = res.conversation_id;
|
|
320
|
+
const reply = res.reply || res.message || '';
|
|
321
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${reply}`);
|
|
322
|
+
messageBox.log('');
|
|
323
|
+
addToHistory(bot.id, userMessage, reply, conversationId);
|
|
324
|
+
addMessageToSession(bot.id, session.id, userMessage, reply);
|
|
325
|
+
} catch (e) { stopLoading(); messageBox.log(`{red-fg}Error: ${e.message}{/}`); }
|
|
326
|
+
messageBox.setScrollPerc(100);
|
|
327
|
+
screen.render();
|
|
328
|
+
} else {
|
|
329
|
+
messageBox.log(`{red-fg}Bilinmeyen komut: /${cmd}{/}`);
|
|
330
|
+
screen.render();
|
|
621
331
|
}
|
|
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
332
|
return;
|
|
627
333
|
}
|
|
628
334
|
}
|
|
629
335
|
|
|
630
|
-
//
|
|
631
|
-
if (userMessage
|
|
336
|
+
// exit/quit
|
|
337
|
+
if (userMessage === 'exit' || userMessage === 'quit') {
|
|
632
338
|
await runHooks('on-exit', null, { botId: bot.id, botName: bot.name });
|
|
633
|
-
|
|
634
|
-
rl.close();
|
|
339
|
+
screen.destroy();
|
|
635
340
|
process.exit(0);
|
|
636
341
|
}
|
|
637
342
|
|
|
638
|
-
//
|
|
343
|
+
// Normal mesaj
|
|
639
344
|
userMessage = await runHooks('pre-message', userMessage, { botId: bot.id, botName: bot.name });
|
|
345
|
+
messageBox.log(`{white-fg}You{/} ${userMessage}`);
|
|
346
|
+
messageBox.setScrollPerc(100);
|
|
347
|
+
screen.render();
|
|
640
348
|
|
|
641
|
-
|
|
642
|
-
const loadingInterval = startLoadingAnimation();
|
|
349
|
+
startLoading();
|
|
643
350
|
|
|
644
351
|
try {
|
|
645
|
-
// Get tool definitions
|
|
646
352
|
const toolDefinitions = getToolDefinitions();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
stopLoadingAnimation(loadingInterval);
|
|
652
|
-
|
|
653
|
-
if (response.conversation_id) {
|
|
654
|
-
conversationId = response.conversation_id;
|
|
655
|
-
}
|
|
353
|
+
let response = await _sendMessage(apiKey || config.providerApiKey, bot.id, userMessage, conversationId, systemPrompt, toolDefinitions);
|
|
354
|
+
stopLoading();
|
|
355
|
+
|
|
356
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
656
357
|
|
|
657
|
-
// Tool
|
|
658
|
-
let
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
while (iteration < maxIterations) {
|
|
662
|
-
// Check for tool calls
|
|
358
|
+
// Tool loop
|
|
359
|
+
let iter = 0;
|
|
360
|
+
while (iter < 5) {
|
|
663
361
|
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
|
|
362
|
+
if (!toolCalls?.length) break;
|
|
363
|
+
messageBox.log(`{yellow-fg}🔧 ${toolCalls.length} tool çalıştırılıyor...{/}`);
|
|
364
|
+
screen.render();
|
|
673
365
|
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'));
|
|
366
|
+
const toolMsg = toolResults.map(tr => `Tool: ${tr.name}\nResult: ${tr.result.success ? (tr.result.output || '') : tr.result.error}`).join('\n\n');
|
|
367
|
+
startLoading();
|
|
368
|
+
response = await _sendMessage(apiKey || config.providerApiKey, bot.id, toolMsg, conversationId, systemPrompt, toolDefinitions);
|
|
369
|
+
stopLoading();
|
|
370
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
371
|
+
iter++;
|
|
699
372
|
}
|
|
700
373
|
|
|
701
374
|
let botReply = response.reply || response.message || 'No response';
|
|
702
|
-
|
|
703
|
-
// Run post-message hooks
|
|
704
375
|
botReply = await runHooks('post-message', botReply, { botId: bot.id, botName: bot.name });
|
|
705
|
-
|
|
706
|
-
console.log(chalk.cyan(`${displayBotName} `) + botReply + '\n');
|
|
707
376
|
|
|
708
|
-
|
|
377
|
+
messageBox.log(`{cyan-fg}${displayBotName}{/} ${botReply}`);
|
|
378
|
+
messageBox.log('');
|
|
379
|
+
messageBox.setScrollPerc(100);
|
|
380
|
+
screen.render();
|
|
381
|
+
|
|
709
382
|
addToHistory(bot.id, userMessage, botReply, conversationId);
|
|
710
383
|
addMessageToSession(bot.id, session.id, userMessage, botReply);
|
|
711
384
|
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
const { addMemoryEntry } = require('../utils/memory');
|
|
716
|
-
addMemoryEntry(bot.id, entry.key, entry.value);
|
|
717
|
-
}
|
|
385
|
+
const memEntries = extractMemoryFromMessage(userMessage);
|
|
386
|
+
for (const e of memEntries) addMemoryEntry(bot.id, e.key, e.value);
|
|
387
|
+
|
|
718
388
|
} catch (err) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
389
|
+
stopLoading();
|
|
390
|
+
const errMsg = err.message.split('"message":"')[1]?.split('"')[0] || err.message;
|
|
391
|
+
messageBox.log(`{red-fg}Error: ${errMsg}{/}`);
|
|
392
|
+
messageBox.setScrollPerc(100);
|
|
393
|
+
screen.render();
|
|
723
394
|
}
|
|
724
395
|
|
|
725
|
-
|
|
726
|
-
rl.prompt();
|
|
396
|
+
inputBox.focus();
|
|
727
397
|
}
|
|
728
398
|
|
|
729
|
-
|
|
730
|
-
|
|
399
|
+
// ── Enter tuşu ──────────────────────────────────────────────────────────────
|
|
400
|
+
inputBox.key('enter', async () => {
|
|
401
|
+
const msg = inputBox.getValue();
|
|
402
|
+
inputBox.clearValue();
|
|
403
|
+
screen.render();
|
|
404
|
+
await handleMessage(msg);
|
|
405
|
+
inputBox.focus();
|
|
406
|
+
screen.render();
|
|
731
407
|
});
|
|
732
408
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
409
|
+
// ── Ctrl+C çıkış ────────────────────────────────────────────────────────────
|
|
410
|
+
screen.key(['C-c'], async () => {
|
|
411
|
+
await runHooks('on-exit', null, { botId: bot.id, botName: bot.name });
|
|
412
|
+
screen.destroy();
|
|
413
|
+
process.exit(0);
|
|
738
414
|
});
|
|
739
415
|
|
|
740
|
-
|
|
741
|
-
}
|
|
416
|
+
// ── on-start hooks ──────────────────────────────────────────────────────────
|
|
417
|
+
await runHooks('on-start', null, { botId: bot.id, botName: bot.name });
|
|
742
418
|
|
|
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);
|
|
419
|
+
screen.render();
|
|
754
420
|
}
|
|
755
421
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
422
|
+
// ── Fallback: blessed yoksa eski readline tabanlı chat ────────────────────────
|
|
423
|
+
async function chatFallback(bot, botList, displayBotName, userName, shortModel, apiKey, config, systemPrompt, session, conversationId, options) {
|
|
424
|
+
const readline = require('readline');
|
|
425
|
+
const chalk = require('chalk');
|
|
426
|
+
|
|
427
|
+
console.clear();
|
|
428
|
+
console.log(chalk.green.bold(' (\\_/)'));
|
|
429
|
+
console.log(chalk.green.bold(' (•ᴥ•)'));
|
|
430
|
+
console.log(chalk.green(' />🌿'));
|
|
431
|
+
console.log('');
|
|
432
|
+
const sep = chalk.gray('─'.repeat(process.stdout.columns || 80));
|
|
433
|
+
console.log(sep);
|
|
434
|
+
console.log(chalk.white.bold('NatureCo') + chalk.gray(' · ') + chalk.cyan(displayBotName) + chalk.gray(' · ') + chalk.gray(shortModel));
|
|
435
|
+
console.log(sep);
|
|
436
|
+
console.log('');
|
|
437
|
+
|
|
438
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: chalk.gray('You ') });
|
|
439
|
+
rl.prompt();
|
|
440
|
+
|
|
441
|
+
rl.on('line', async (line) => {
|
|
442
|
+
const msg = line.trim();
|
|
443
|
+
if (!msg) { rl.prompt(); return; }
|
|
444
|
+
if (msg === 'exit' || msg === 'quit') { console.log(chalk.gray('\n👋 Goodbye!\n')); process.exit(0); }
|
|
445
|
+
|
|
446
|
+
process.stdout.write(chalk.cyan('... '));
|
|
447
|
+
try {
|
|
448
|
+
const toolDefinitions = getToolDefinitions();
|
|
449
|
+
const response = await _sendMessage(apiKey || config.providerApiKey, bot.id, msg, conversationId, systemPrompt, toolDefinitions);
|
|
450
|
+
process.stdout.write('\r');
|
|
451
|
+
if (response.conversation_id) conversationId = response.conversation_id;
|
|
452
|
+
const reply = response.reply || response.message || '';
|
|
453
|
+
console.log(chalk.cyan(`${displayBotName} `) + reply + '\n');
|
|
454
|
+
addToHistory(bot.id, msg, reply, conversationId);
|
|
455
|
+
addMessageToSession(bot.id, session.id, msg, reply);
|
|
456
|
+
} catch (e) {
|
|
457
|
+
process.stdout.write('\r');
|
|
458
|
+
console.log(chalk.red(`Error: ${e.message}\n`));
|
|
459
|
+
}
|
|
460
|
+
rl.prompt();
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
rl.on('close', () => process.exit(0));
|
|
759
464
|
}
|
|
760
465
|
|
|
761
466
|
module.exports = chat;
|