natureco-cli 2.5.0 → 2.6.0
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 +9 -1
- package/package.json +2 -1
- package/src/commands/dashboard.js +2 -2
- package/src/commands/gateway-server.js +97 -1
- package/src/commands/telegram.js +126 -0
- package/src/tools/web_search.js +35 -29
- package/src/utils/api.js +1 -1
package/bin/natureco.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { Command } = require('commander');
|
|
4
4
|
const chalk = require('chalk');
|
|
@@ -185,6 +185,14 @@ program
|
|
|
185
185
|
whatsappCmd(action);
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
program
|
|
189
|
+
.command('telegram <action>')
|
|
190
|
+
.description('Telegram integration (connect|disconnect|status)')
|
|
191
|
+
.action((action) => {
|
|
192
|
+
const telegramCmd = require('../src/commands/telegram');
|
|
193
|
+
telegramCmd(action);
|
|
194
|
+
});
|
|
195
|
+
|
|
188
196
|
program
|
|
189
197
|
.command('dashboard [action]')
|
|
190
198
|
.description('Web Control UI (start|stop|status)')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "NatureCo AI Bot Terminal Interface",
|
|
5
5
|
"main": "bin/natureco.js",
|
|
6
6
|
"bin": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"eventsource": "^2.0.2",
|
|
33
33
|
"inquirer": "^8.2.7",
|
|
34
34
|
"node-cron": "^2.0.3",
|
|
35
|
+
"node-telegram-bot-api": "^0.65.1",
|
|
35
36
|
"ora": "^5.4.1",
|
|
36
37
|
"pino": "^8.21.0",
|
|
37
38
|
"qrcode-terminal": "^0.12.0",
|
|
@@ -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.
|
|
214
|
+
<div class="version-badge" id="version-badge">v2.6.0</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.
|
|
344
|
+
version: 'v2.6.0',
|
|
345
345
|
bots: cfg.bots || [],
|
|
346
346
|
telegramToken: cfg.telegramToken || null,
|
|
347
347
|
whatsappConnected: cfg.whatsappConnected || false,
|
|
@@ -128,7 +128,7 @@ async function startGateway() {
|
|
|
128
128
|
|
|
129
129
|
async function runGatewayWorker() {
|
|
130
130
|
// This runs in the background
|
|
131
|
-
log('gateway', 'Starting NatureCo Gateway v2.
|
|
131
|
+
log('gateway', 'Starting NatureCo Gateway v2.6.0...', 'green');
|
|
132
132
|
|
|
133
133
|
// Load config
|
|
134
134
|
const { getConfig } = require('../utils/config');
|
|
@@ -154,6 +154,14 @@ async function runGatewayWorker() {
|
|
|
154
154
|
log('whatsapp', 'not configured, skipping', 'gray');
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
// Start Telegram if configured
|
|
158
|
+
if (config.telegramToken && config.telegramBotId) {
|
|
159
|
+
log('telegram', 'starting bot...', 'cyan');
|
|
160
|
+
startTelegramProvider(config);
|
|
161
|
+
} else {
|
|
162
|
+
log('telegram', 'not configured, skipping', 'gray');
|
|
163
|
+
}
|
|
164
|
+
|
|
157
165
|
// Health check every 60 seconds
|
|
158
166
|
setInterval(() => {
|
|
159
167
|
log('gateway', 'health check: OK', 'gray');
|
|
@@ -348,6 +356,94 @@ async function startWhatsAppProvider(sessionDir, config) {
|
|
|
348
356
|
}
|
|
349
357
|
}
|
|
350
358
|
|
|
359
|
+
async function startTelegramProvider(config) {
|
|
360
|
+
try {
|
|
361
|
+
// Lazy load node-telegram-bot-api
|
|
362
|
+
let TelegramBot;
|
|
363
|
+
try {
|
|
364
|
+
TelegramBot = require('node-telegram-bot-api');
|
|
365
|
+
} catch (err) {
|
|
366
|
+
log('telegram', 'node-telegram-bot-api not installed', 'red');
|
|
367
|
+
log('telegram', 'Install with: npm install -g node-telegram-bot-api', 'yellow');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const bot = new TelegramBot(config.telegramToken, { polling: true });
|
|
372
|
+
|
|
373
|
+
log('telegram', 'Bot started successfully', 'green');
|
|
374
|
+
log('telegram', 'Listening for messages...', 'cyan');
|
|
375
|
+
|
|
376
|
+
bot.on('message', async (msg) => {
|
|
377
|
+
const chatId = msg.chat.id;
|
|
378
|
+
const messageText = msg.text;
|
|
379
|
+
|
|
380
|
+
if (!messageText) {
|
|
381
|
+
log('telegram', `Message without text from chat ${chatId}`, 'gray');
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
log('telegram', `Inbound message from chat ${chatId} (${messageText.length} chars)`, 'cyan');
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
const { sendMessage } = require('../utils/api');
|
|
389
|
+
const { getMemoryPrompt, extractMemoryFromMessage, addMemoryEntry } = require('../utils/memory');
|
|
390
|
+
|
|
391
|
+
log('telegram', 'Sending to AI provider...', 'cyan');
|
|
392
|
+
|
|
393
|
+
// Use Telegram-specific conversation ID for persistent history
|
|
394
|
+
const conversationId = `telegram_${chatId}`;
|
|
395
|
+
|
|
396
|
+
// Use same botId as terminal for shared memory
|
|
397
|
+
const botId = 'universal-provider';
|
|
398
|
+
const memoryPrompt = getMemoryPrompt(botId);
|
|
399
|
+
|
|
400
|
+
// Telegram system prompt with memory
|
|
401
|
+
let systemPrompt = `You are a helpful Telegram assistant. Keep responses concise and friendly. Use emojis when appropriate. If users ask for file operations or system commands, politely explain that those features are available in the terminal version.`;
|
|
402
|
+
|
|
403
|
+
if (memoryPrompt) {
|
|
404
|
+
systemPrompt += '\n\n' + memoryPrompt;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const response = await sendMessage(null, null, messageText, conversationId, systemPrompt);
|
|
408
|
+
const reply = response?.reply || response?.message || '';
|
|
409
|
+
|
|
410
|
+
if (reply) {
|
|
411
|
+
log('telegram', 'Sending reply...', 'cyan');
|
|
412
|
+
|
|
413
|
+
await bot.sendMessage(chatId, reply);
|
|
414
|
+
|
|
415
|
+
log('telegram', `Reply sent (${reply.length} chars)`, 'green');
|
|
416
|
+
|
|
417
|
+
// Extract and save memory from user message
|
|
418
|
+
const memoryEntries = extractMemoryFromMessage(messageText);
|
|
419
|
+
for (const entry of memoryEntries) {
|
|
420
|
+
addMemoryEntry(botId, entry.key, entry.value);
|
|
421
|
+
log('telegram', `Memory saved: ${entry.key} = ${entry.value}`, 'gray');
|
|
422
|
+
}
|
|
423
|
+
} else {
|
|
424
|
+
log('telegram', 'No reply from provider', 'yellow');
|
|
425
|
+
}
|
|
426
|
+
} catch (err) {
|
|
427
|
+
log('telegram', `Provider error: ${err.message}`, 'red');
|
|
428
|
+
|
|
429
|
+
// Send error message to user
|
|
430
|
+
try {
|
|
431
|
+
await bot.sendMessage(chatId, '❌ Bir hata oluştu. Lütfen tekrar deneyin.');
|
|
432
|
+
} catch (sendErr) {
|
|
433
|
+
log('telegram', `Failed to send error message: ${sendErr.message}`, 'red');
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
bot.on('polling_error', (error) => {
|
|
439
|
+
log('telegram', `Polling error: ${error.message}`, 'red');
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
} catch (err) {
|
|
443
|
+
log('telegram', `Failed to start: ${err.message}`, 'red');
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
351
447
|
function stopGateway() {
|
|
352
448
|
if (!fs.existsSync(PID_FILE)) {
|
|
353
449
|
console.log(chalk.gray('\n⚠️ Gateway not running\n'));
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
4
|
+
|
|
5
|
+
async function telegram(action) {
|
|
6
|
+
if (!action || action === 'connect') {
|
|
7
|
+
return connectTelegram();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (action === 'disconnect') {
|
|
11
|
+
return disconnectTelegram();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (action === 'status') {
|
|
15
|
+
return statusTelegram();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(chalk.red('\n❌ Unknown action\n'));
|
|
19
|
+
console.log(chalk.gray('Available actions: connect, disconnect, status\n'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function connectTelegram() {
|
|
24
|
+
const config = getConfig();
|
|
25
|
+
|
|
26
|
+
if (!config.providerUrl) {
|
|
27
|
+
console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log(chalk.yellow('\n⏳ Telegram bot bağlantısı hazırlanıyor...\n'));
|
|
32
|
+
console.log(chalk.gray('Telegram bot token almak için:'));
|
|
33
|
+
console.log(chalk.gray('1. Telegram\'da @BotFather\'ı aç'));
|
|
34
|
+
console.log(chalk.gray('2. /newbot komutunu gönder'));
|
|
35
|
+
console.log(chalk.gray('3. Bot adı ve kullanıcı adı belirle'));
|
|
36
|
+
console.log(chalk.gray('4. Aldığın token\'ı buraya gir\n'));
|
|
37
|
+
|
|
38
|
+
process.stdin.resume();
|
|
39
|
+
|
|
40
|
+
const answers = await inquirer.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: 'input',
|
|
43
|
+
name: 'token',
|
|
44
|
+
message: 'Telegram bot token:',
|
|
45
|
+
validate: (val) => {
|
|
46
|
+
if (val.trim() === '') return 'Token boş olamaz';
|
|
47
|
+
if (!val.includes(':')) return 'Geçersiz token formatı (örnek: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)';
|
|
48
|
+
return true;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
// Telegram için bot ID oluştur (timestamp-based)
|
|
54
|
+
const botId = `telegram_${Date.now()}`;
|
|
55
|
+
|
|
56
|
+
console.log(chalk.yellow('\n⏳ Telegram bağlantısı kaydediliyor...\n'));
|
|
57
|
+
|
|
58
|
+
// Save to config (v2.x - no backend call)
|
|
59
|
+
config.telegramToken = answers.token.trim();
|
|
60
|
+
config.telegramBotId = botId;
|
|
61
|
+
saveConfig(config);
|
|
62
|
+
|
|
63
|
+
console.log(chalk.green('✅ Telegram bot token kaydedildi!\n'));
|
|
64
|
+
console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
|
|
65
|
+
console.log(chalk.cyan('Token:'), chalk.white(answers.token.slice(0, 20) + '...'));
|
|
66
|
+
console.log(chalk.gray('\nSession kaydedildi: ~/.natureco/config.json'));
|
|
67
|
+
|
|
68
|
+
console.log(chalk.green('\n✅ Kurulum tamamlandı!\n'));
|
|
69
|
+
console.log(chalk.yellow('Gateway ile başlatmak için:'), chalk.cyan('natureco gateway start'));
|
|
70
|
+
console.log(chalk.gray('Gateway, Telegram botunu otomatik olarak başlatacak.\n'));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function disconnectTelegram() {
|
|
74
|
+
const config = getConfig();
|
|
75
|
+
|
|
76
|
+
if (!config.telegramToken) {
|
|
77
|
+
console.log(chalk.gray('\n⚠️ No Telegram connection found\n'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
process.stdin.resume();
|
|
82
|
+
|
|
83
|
+
const { confirm } = await inquirer.prompt([
|
|
84
|
+
{
|
|
85
|
+
type: 'confirm',
|
|
86
|
+
name: 'confirm',
|
|
87
|
+
message: 'Are you sure you want to disconnect Telegram?',
|
|
88
|
+
default: false,
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
if (!confirm) {
|
|
93
|
+
console.log(chalk.gray('\nCancelled\n'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Remove from config
|
|
98
|
+
delete config.telegramToken;
|
|
99
|
+
delete config.telegramBotId;
|
|
100
|
+
saveConfig(config);
|
|
101
|
+
|
|
102
|
+
console.log(chalk.green('\n✅ Telegram disconnected\n'));
|
|
103
|
+
console.log(chalk.gray('Note: The bot is still active on Telegram.'));
|
|
104
|
+
console.log(chalk.gray('You may need to manually delete it via @BotFather.\n'));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function statusTelegram() {
|
|
108
|
+
const config = getConfig();
|
|
109
|
+
|
|
110
|
+
if (!config.telegramToken) {
|
|
111
|
+
console.log(chalk.gray('\n⚠️ Telegram not connected\n'));
|
|
112
|
+
console.log(chalk.gray('Connect with: natureco telegram connect\n'));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(chalk.green('\n✅ Telegram connected\n'));
|
|
117
|
+
console.log(chalk.cyan('Token:'), chalk.white(config.telegramToken.slice(0, 20) + '...'));
|
|
118
|
+
|
|
119
|
+
if (config.telegramBotId) {
|
|
120
|
+
console.log(chalk.cyan('Bot ID:'), chalk.white(config.telegramBotId));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log(chalk.gray('\nDisconnect with: natureco telegram disconnect\n'));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = telegram;
|
package/src/tools/web_search.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
const { getConfig } = require('../utils/config');
|
|
2
|
+
|
|
1
3
|
module.exports = {
|
|
2
4
|
name: 'web_search',
|
|
3
|
-
description: 'Search the web for current information using
|
|
5
|
+
description: 'Search the web for current information using Tavily',
|
|
4
6
|
inputSchema: {
|
|
5
7
|
type: 'object',
|
|
6
8
|
properties: {
|
|
@@ -14,44 +16,44 @@ module.exports = {
|
|
|
14
16
|
|
|
15
17
|
async execute(params) {
|
|
16
18
|
try {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
+
const config = getConfig();
|
|
20
|
+
const apiKey = config.tavilyApiKey || process.env.TAVILY_API_KEY;
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
if (!apiKey) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
error: 'Tavily API key gerekli. Kur: natureco config set tavilyApiKey tvly_xxx\nÜcretsiz key: https://tavily.com'
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const response = await fetch('https://api.tavily.com/search', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
api_key: apiKey,
|
|
34
|
+
query: params.query,
|
|
35
|
+
search_depth: 'basic',
|
|
36
|
+
max_results: 5
|
|
37
|
+
})
|
|
38
|
+
});
|
|
21
39
|
|
|
22
40
|
if (!response.ok) {
|
|
23
41
|
return {
|
|
24
42
|
success: false,
|
|
25
|
-
error: `
|
|
43
|
+
error: `Tavily API error: ${response.status} ${response.statusText}`
|
|
26
44
|
};
|
|
27
45
|
}
|
|
28
46
|
|
|
29
47
|
const data = await response.json();
|
|
30
|
-
const results = [];
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
url: data.AbstractURL || ''
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Add related topics (up to 5)
|
|
42
|
-
if (data.RelatedTopics && Array.isArray(data.RelatedTopics)) {
|
|
43
|
-
data.RelatedTopics.slice(0, 5).forEach(topic => {
|
|
44
|
-
if (topic.Text && topic.FirstURL) {
|
|
45
|
-
results.push({
|
|
46
|
-
title: topic.Text.split(' - ')[0] || 'Related',
|
|
47
|
-
snippet: topic.Text,
|
|
48
|
-
url: topic.FirstURL
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
});
|
|
49
|
+
if (data.error) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
error: data.error
|
|
53
|
+
};
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
if (results.length === 0) {
|
|
56
|
+
if (!data.results || data.results.length === 0) {
|
|
55
57
|
return {
|
|
56
58
|
success: true,
|
|
57
59
|
message: 'Sonuç bulunamadı',
|
|
@@ -63,8 +65,12 @@ module.exports = {
|
|
|
63
65
|
return {
|
|
64
66
|
success: true,
|
|
65
67
|
query: params.query,
|
|
66
|
-
results: results
|
|
67
|
-
|
|
68
|
+
results: data.results.map(r => ({
|
|
69
|
+
title: r.title,
|
|
70
|
+
snippet: r.content,
|
|
71
|
+
url: r.url
|
|
72
|
+
})),
|
|
73
|
+
count: data.results.length
|
|
68
74
|
};
|
|
69
75
|
} catch (error) {
|
|
70
76
|
return {
|
package/src/utils/api.js
CHANGED