natureco-cli 1.0.24 → 1.0.26

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  "author": "NatureCo",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
+ "@whiskeysockets/baileys": "^7.0.0-rc10",
27
28
  "boxen": "^5.1.2",
28
29
  "chalk": "^4.1.2",
29
30
  "commander": "^11.1.0",
@@ -32,6 +33,7 @@
32
33
  "inquirer": "^8.2.7",
33
34
  "node-cron": "^2.0.3",
34
35
  "ora": "^5.4.1",
36
+ "pino": "^8.21.0",
35
37
  "qrcode-terminal": "^0.12.0",
36
38
  "ws": "^8.20.0"
37
39
  },
@@ -63,10 +63,54 @@ async function setup() {
63
63
  },
64
64
  ]);
65
65
 
66
+ // Model listesi
67
+ const MODELS = {
68
+ anthropic: [
69
+ { name: 'Claude Opus 4.7', value: 'claude-opus-4-7' },
70
+ { name: 'Claude Opus 4.6', value: 'claude-opus-4-6' },
71
+ { name: 'Claude Opus 4.5', value: 'claude-opus-4-5-20251101' },
72
+ { name: 'Claude Sonnet 4.6', value: 'claude-sonnet-4-6' },
73
+ { name: 'Claude Sonnet 4.5', value: 'claude-sonnet-4-5-20251001' },
74
+ { name: 'Claude Haiku 4.5', value: 'claude-haiku-4-5-20251001' },
75
+ { name: 'Claude Haiku 3.5', value: 'claude-haiku-3-5-20241022' },
76
+ ],
77
+ openai: [
78
+ { name: 'GPT-5.5', value: 'gpt-5.5' },
79
+ { name: 'GPT-5.4', value: 'gpt-5.4' },
80
+ { name: 'GPT-5.4 Mini', value: 'gpt-5.4-mini' },
81
+ { name: 'GPT-5.4 Nano', value: 'gpt-5.4-nano' },
82
+ { name: 'GPT-5', value: 'gpt-5' },
83
+ { name: 'GPT-5 Mini', value: 'gpt-5-mini' },
84
+ { name: 'GPT-4.1', value: 'gpt-4.1' },
85
+ { name: 'GPT-4.1 Mini', value: 'gpt-4.1-mini' },
86
+ { name: 'GPT-4.1 Nano', value: 'gpt-4.1-nano' },
87
+ { name: 'GPT-4o', value: 'gpt-4o' },
88
+ { name: 'GPT-4o Mini', value: 'gpt-4o-mini' },
89
+ { name: 'o3', value: 'o3' },
90
+ { name: 'o3 Mini', value: 'o3-mini' },
91
+ { name: 'o4 Mini', value: 'o4-mini' },
92
+ ],
93
+ groq: [
94
+ { name: 'Llama 3.3 70B', value: 'llama-3.3-70b-versatile' },
95
+ { name: 'Llama 3.1 8B', value: 'llama-3.1-8b-instant' },
96
+ { name: 'Llama 3.1 70B', value: 'llama-3.1-70b-versatile' },
97
+ { name: 'Mixtral 8x7B', value: 'mixtral-8x7b-32768' },
98
+ { name: 'Gemma 2 9B', value: 'gemma2-9b-it' },
99
+ ],
100
+ gemini: [
101
+ { name: 'Gemini 2.5 Pro', value: 'gemini-2.5-pro' },
102
+ { name: 'Gemini 2.5 Flash', value: 'gemini-2.5-flash' },
103
+ { name: 'Gemini 2.0 Flash', value: 'gemini-2.0-flash' },
104
+ { name: 'Gemini 1.5 Pro', value: 'gemini-1.5-pro' },
105
+ { name: 'Gemini 1.5 Flash', value: 'gemini-1.5-flash' },
106
+ ],
107
+ };
108
+
66
109
  let aiApiKey = null;
110
+ let aiModel = null;
67
111
  let naturecoApiKey = null;
68
112
 
69
- // NatureCo dışı sağlayıcı seçildiyse key sor
113
+ // NatureCo dışı sağlayıcı seçildiyse key ve model sor
70
114
  if (aiProvider !== 'natureco') {
71
115
  const providerInfo = {
72
116
  openai: { name: 'OpenAI', prefix: 'sk-', example: 'sk-...' },
@@ -97,6 +141,19 @@ async function setup() {
97
141
 
98
142
  aiApiKey = customApiKey.trim();
99
143
 
144
+ // Model seçimi
145
+ process.stdin.resume();
146
+ const { selectedModel } = await inquirer.prompt([
147
+ {
148
+ type: 'list',
149
+ name: 'selectedModel',
150
+ message: 'Model seçin:',
151
+ choices: MODELS[aiProvider],
152
+ },
153
+ ]);
154
+
155
+ aiModel = selectedModel;
156
+
100
157
  // NatureCo API key de sor (opsiyonel)
101
158
  process.stdin.resume();
102
159
  const { wantNaturecoKey } = await inquirer.prompt([
@@ -613,6 +670,7 @@ async function setup() {
613
670
  if (aiProvider !== 'natureco') {
614
671
  config.aiProvider = aiProvider;
615
672
  config.aiApiKey = aiApiKey;
673
+ config.aiModel = aiModel;
616
674
  }
617
675
 
618
676
  if (naturecoApiKey) {
@@ -1,10 +1,34 @@
1
1
  const chalk = require('chalk');
2
2
  const inquirer = require('inquirer');
3
3
  const qrcode = require('qrcode-terminal');
4
- const EventSource = require('eventsource');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+ const pino = require('pino');
5
8
  const { getApiKey, getConfig, saveConfig } = require('../utils/config');
6
9
  const { getBots } = require('../utils/api');
7
10
 
11
+ // Baileys imports
12
+ let makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, Browsers;
13
+
14
+ // Logger
15
+ const logger = pino({ level: 'silent' });
16
+
17
+ // Lazy load Baileys (only when needed)
18
+ function loadBaileys() {
19
+ if (!makeWASocket) {
20
+ const baileys = require('@whiskeysockets/baileys');
21
+ makeWASocket = baileys.default;
22
+ useMultiFileAuthState = baileys.useMultiFileAuthState;
23
+ DisconnectReason = baileys.DisconnectReason;
24
+ fetchLatestBaileysVersion = baileys.fetchLatestBaileysVersion;
25
+ Browsers = baileys.Browsers;
26
+ }
27
+ }
28
+
29
+ // WhatsApp session directory
30
+ const WHATSAPP_SESSION_DIR = path.join(os.homedir(), '.natureco', 'whatsapp-sessions');
31
+
8
32
  async function whatsapp(action) {
9
33
  if (!action || action === 'connect') {
10
34
  return connectWhatsApp();
@@ -61,110 +85,124 @@ async function connectWhatsApp() {
61
85
 
62
86
  const selectedBot = botList.bots.find(b => b.id === botId);
63
87
 
64
- console.log(chalk.cyan('\n📱 WhatsApp bağlantısı QR kod ile yapılır.'));
88
+ console.log(chalk.cyan('\n📱 WhatsApp bağlantısı başlatılıyor...'));
65
89
  console.log(chalk.gray('Telefonunuzda WhatsApp\'ı açın ve QR kodu taratın.\n'));
66
- console.log(chalk.yellow('⏳ Session oluşturuluyor...\n'));
67
90
 
91
+ // Load Baileys
92
+ loadBaileys();
93
+
94
+ // Create session directory
95
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, botId);
96
+ if (!fs.existsSync(sessionDir)) {
97
+ fs.mkdirSync(sessionDir, { recursive: true });
98
+ }
99
+
100
+ // Start connection
101
+ await startWhatsAppConnection(sessionDir, botId, selectedBot, config);
102
+ }
103
+
104
+ async function startWhatsAppConnection(sessionDir, botId, selectedBot, config) {
68
105
  try {
69
- // Create WhatsApp session
70
- const response = await fetch('http://localhost:3000/connect', {
71
- method: 'POST',
72
- headers: {
73
- 'Content-Type': 'application/json',
74
- },
75
- body: JSON.stringify({
76
- bot_id: botId,
77
- }),
78
- });
79
-
80
- if (!response.ok) {
81
- const error = await response.text();
82
- throw new Error(error);
83
- }
84
-
85
- const data = await response.json();
86
-
87
- if (!data.session_id) {
88
- throw new Error('No session ID returned');
89
- }
106
+ // Create auth state
107
+ const { state, saveCreds } = await useMultiFileAuthState(sessionDir);
90
108
 
91
- console.log(chalk.green('✅ Session oluşturuldu!\n'));
92
- console.log(chalk.cyan('Session ID:'), chalk.white(data.session_id));
93
- console.log(chalk.yellow('\n⏳ QR kod bekleniyor...\n'));
109
+ // Get latest Baileys version
110
+ const { version } = await fetchLatestBaileysVersion();
94
111
 
95
- // Save session ID to config
96
- config.whatsappSessionId = data.session_id;
97
- config.whatsappConnected = true;
98
- config.whatsappBotId = botId;
99
- saveConfig(config);
112
+ console.log(chalk.yellow('⏳ WhatsApp client başlatılıyor...\n'));
100
113
 
101
- // Connect to SSE endpoint for QR code
102
- const sseUrl = `http://localhost:3000/qr/${data.session_id}`;
103
- const eventSource = new EventSource(sseUrl);
114
+ // Create socket
115
+ const sock = makeWASocket({
116
+ version,
117
+ auth: state,
118
+ printQRInTerminal: false,
119
+ browser: Browsers.ubuntu('Chrome'),
120
+ logger: logger,
121
+ });
104
122
 
105
123
  let qrDisplayed = false;
124
+ let isConnected = false;
106
125
 
107
- eventSource.onmessage = (event) => {
108
- try {
109
- const eventData = JSON.parse(event.data);
126
+ // Connection update handler
127
+ sock.ev.on('connection.update', async (update) => {
128
+ const { connection, lastDisconnect, qr } = update;
129
+
130
+ if (qr && !qrDisplayed) {
131
+ console.log(chalk.green('✅ QR kod hazır!\n'));
132
+
133
+ // Display QR code in terminal
134
+ qrcode.generate(qr, { small: true });
135
+
136
+ console.log('');
137
+ console.log(chalk.gray('1. WhatsApp\'ı açın'));
138
+ console.log(chalk.gray('2. Ayarlar > Bağlı Cihazlar > Cihaz Bağla'));
139
+ console.log(chalk.gray('3. Bu QR kodu taratın\n'));
140
+ console.log(chalk.yellow('⏳ QR kod taranması bekleniyor...\n'));
141
+
142
+ qrDisplayed = true;
143
+ }
144
+
145
+ if (connection === 'close') {
146
+ const statusCode = lastDisconnect?.error?.output?.statusCode;
110
147
 
111
- if (eventData.type === 'qr') {
112
- if (!qrDisplayed) {
113
- console.log(chalk.green(' QR kod hazır!\n'));
114
-
115
- // Display QR code in terminal using the text version
116
- if (eventData.qrText) {
117
- qrcode.generate(eventData.qrText, { small: true });
118
- } else if (eventData.qr) {
119
- // Fallback: try to extract from base64 data URL
120
- console.log(chalk.yellow('QR kod alındı (base64 format)\n'));
121
- }
122
-
123
- console.log('');
124
- console.log(chalk.gray('1. WhatsApp\'ı açın'));
125
- console.log(chalk.gray('2. Ayarlar > Bağlı Cihazlar > Cihaz Bağla'));
126
- console.log(chalk.gray('3. Bu QR kodu taratın\n'));
127
- console.log(chalk.yellow('⏳ QR kod taranması bekleniyor...\n'));
128
-
129
- qrDisplayed = true;
130
- }
131
- } else if (eventData.type === 'ready') {
132
- console.log(chalk.green('✅ WhatsApp bağlandı!\n'));
133
- console.log(chalk.cyan('Bot:'), chalk.white(selectedBot.name));
134
- console.log(chalk.gray('Botunuz WhatsApp\'ta aktif.\n'));
135
- eventSource.close();
148
+ if (statusCode === 515) {
149
+ // Normal — yeniden bağlan, logout değil
150
+ console.log(chalk.yellow('🔄 Yeniden bağlanıyor...'));
151
+ setTimeout(() => startWhatsAppConnection(sessionDir, botId, selectedBot, config), 1000);
152
+ return;
153
+ } else if (statusCode === 401) {
154
+ console.log(chalk.red('❌ Oturum sonlandı, tekrar bağlanın.'));
155
+ process.exit(1);
156
+ } else if (statusCode === DisconnectReason.loggedOut) {
157
+ console.log(chalk.red('\n❌ WhatsApp oturumu kapatıldı\n'));
136
158
  process.exit(0);
137
- } else if (eventData.type === 'error') {
138
- console.log(chalk.red(`\n❌ Hata: ${eventData.error}\n`));
139
- eventSource.close();
159
+ } else if (!isConnected) {
160
+ console.log(chalk.red('\n❌ Bağlantı başarısız\n'));
161
+ console.log(chalk.gray(`Hata kodu: ${statusCode}\n`));
140
162
  process.exit(1);
141
- } else if (eventData.type === 'disconnected') {
142
- console.log(chalk.yellow(`\n⚠️ Bağlantı kesildi: ${eventData.reason}\n`));
143
- eventSource.close();
163
+ } else {
164
+ console.log(chalk.red(`❌ Bağlantı kesildi: ${statusCode}\n`));
144
165
  process.exit(1);
145
166
  }
146
- } catch (err) {
147
- console.error(chalk.red('Event parse error:'), err.message);
167
+ } else if (connection === 'open') {
168
+ isConnected = true;
169
+ console.log(chalk.green('✅ WhatsApp bağlandı!\n'));
170
+ console.log(chalk.cyan('Bot:'), chalk.white(selectedBot.name));
171
+ console.log(chalk.cyan('Telefon:'), chalk.white(sock.user?.id || 'Unknown'));
172
+ console.log(chalk.gray('\nSession kaydedildi: ~/.natureco/whatsapp-sessions/'));
173
+
174
+ // Save to config
175
+ config.whatsappConnected = true;
176
+ config.whatsappBotId = botId;
177
+ config.whatsappPhone = sock.user?.id;
178
+ saveConfig(config);
179
+
180
+ console.log(chalk.green('\n✅ Kurulum tamamlandı!\n'));
181
+ console.log(chalk.gray('Botunuz WhatsApp\'ta aktif.\n'));
182
+
183
+ // Keep process alive for a moment then exit
184
+ setTimeout(() => {
185
+ process.exit(0);
186
+ }, 2000);
148
187
  }
149
- };
188
+ });
150
189
 
151
- eventSource.onerror = (err) => {
152
- console.log(chalk.red('\n❌ SSE connection error\n'));
153
- console.log(chalk.gray('Make sure WhatsApp service is running on http://localhost:3000\n'));
154
- eventSource.close();
155
- process.exit(1);
156
- };
190
+ // Save credentials on update
191
+ sock.ev.on('creds.update', saveCreds);
157
192
 
158
193
  // Handle Ctrl+C
159
194
  process.on('SIGINT', () => {
160
195
  console.log(chalk.yellow('\n\n⚠️ Bağlantı iptal edildi\n'));
161
- eventSource.close();
162
196
  process.exit(0);
163
197
  });
164
198
 
165
199
  } catch (err) {
166
200
  console.log(chalk.red(`\n❌ Connection failed: ${err.message}\n`));
167
- console.log(chalk.gray('Make sure WhatsApp service is running on http://localhost:3000\n'));
201
+ if (err.message.includes('Cannot find module')) {
202
+ console.log(chalk.yellow('⚠️ Baileys paketi yüklü değil. Yükleniyor...\n'));
203
+ console.log(chalk.gray('Lütfen şu komutu çalıştırın:\n'));
204
+ console.log(chalk.cyan('npm install -g @whiskeysockets/baileys pino\n'));
205
+ }
168
206
  process.exit(1);
169
207
  }
170
208
  }
@@ -193,39 +231,28 @@ async function disconnectWhatsApp() {
193
231
  return;
194
232
  }
195
233
 
196
- const apiKey = getApiKey();
197
-
198
- if (apiKey && config.whatsappSessionId) {
199
- try {
200
- const response = await fetch('http://localhost:3000/disconnect', {
201
- method: 'POST',
202
- headers: {
203
- 'Content-Type': 'application/json',
204
- },
205
- body: JSON.stringify({
206
- session_id: config.whatsappSessionId,
207
- }),
208
- });
209
-
210
- if (response.ok) {
211
- console.log(chalk.green('\n✅ WhatsApp session disconnected from server\n'));
212
- }
213
- } catch (err) {
214
- console.log(chalk.yellow(`\n⚠️ API disconnect failed: ${err.message}`));
234
+ try {
235
+ // Remove session directory
236
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, config.whatsappBotId);
237
+ if (fs.existsSync(sessionDir)) {
238
+ fs.rmSync(sessionDir, { recursive: true, force: true });
239
+ console.log(chalk.green('\n✅ Session dosyaları silindi\n'));
215
240
  }
241
+
242
+ // Remove from config
243
+ delete config.whatsappConnected;
244
+ delete config.whatsappBotId;
245
+ delete config.whatsappPhone;
246
+ saveConfig(config);
247
+
248
+ console.log(chalk.green('✅ WhatsApp disconnected\n'));
249
+ console.log(chalk.gray('Note: You may need to manually remove the device from WhatsApp settings.\n'));
250
+ } catch (err) {
251
+ console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
216
252
  }
217
-
218
- // Remove from config
219
- delete config.whatsappConnected;
220
- delete config.whatsappBotId;
221
- delete config.whatsappSessionId;
222
- saveConfig(config);
223
-
224
- console.log(chalk.green('✅ WhatsApp disconnected locally\n'));
225
- console.log(chalk.gray('Note: You may need to manually remove the device from WhatsApp settings.\n'));
226
253
  }
227
254
 
228
- async function statusWhatsApp() {
255
+ function statusWhatsApp() {
229
256
  const config = getConfig();
230
257
 
231
258
  if (!config.whatsappConnected) {
@@ -234,54 +261,23 @@ async function statusWhatsApp() {
234
261
  return;
235
262
  }
236
263
 
237
- const apiKey = getApiKey();
238
-
239
- // Try to get status from API if session ID exists
240
- if (apiKey && config.whatsappSessionId) {
241
- try {
242
- console.log(chalk.yellow('\n⏳ Checking connection status...\n'));
243
-
244
- const response = await fetch(`http://localhost:3000/status/${config.whatsappSessionId}`, {
245
- method: 'GET',
246
- });
247
-
248
- if (response.ok) {
249
- const data = await response.json();
250
-
251
- if (data.status === 'connected') {
252
- console.log(chalk.green('✅ WhatsApp connected\n'));
253
- } else if (data.status === 'pending') {
254
- console.log(chalk.yellow('⏳ WhatsApp connection pending\n'));
255
- console.log(chalk.gray('Waiting for QR code scan...\n'));
256
- } else {
257
- console.log(chalk.red('❌ WhatsApp disconnected\n'));
258
- }
259
-
260
- console.log(chalk.cyan('Session ID:'), chalk.white(data.session_id));
261
- console.log(chalk.cyan('Bot ID:'), chalk.white(data.bot_id));
262
- console.log(chalk.cyan('Created:'), chalk.white(data.created_at));
263
-
264
- if (data.connected_at) {
265
- console.log(chalk.cyan('Connected:'), chalk.white(data.connected_at));
266
- }
267
-
268
- console.log('');
269
- return;
270
- }
271
- } catch (err) {
272
- console.log(chalk.yellow(`⚠️ Could not fetch status: ${err.message}\n`));
273
- }
274
- }
275
-
276
- // Fallback to local config
277
- console.log(chalk.green('\n✅ WhatsApp connected (local)\n'));
264
+ console.log(chalk.green('\n✅ WhatsApp connected\n'));
278
265
 
279
266
  if (config.whatsappBotId) {
280
267
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.whatsappBotId));
281
268
  }
282
269
 
283
- if (config.whatsappSessionId) {
284
- console.log(chalk.cyan('Session ID:'), chalk.white(config.whatsappSessionId));
270
+ if (config.whatsappPhone) {
271
+ console.log(chalk.cyan('Phone:'), chalk.white(config.whatsappPhone));
272
+ }
273
+
274
+ // Check if session files exist
275
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, config.whatsappBotId);
276
+ if (fs.existsSync(sessionDir)) {
277
+ console.log(chalk.cyan('Session:'), chalk.white('Active'));
278
+ console.log(chalk.gray(`Location: ${sessionDir}`));
279
+ } else {
280
+ console.log(chalk.yellow('Session:'), chalk.gray('Not found (may need to reconnect)'));
285
281
  }
286
282
 
287
283
  console.log(chalk.gray('\nDisconnect with: natureco whatsapp disconnect\n'));
package/src/utils/api.js CHANGED
@@ -45,6 +45,11 @@ async function sendMessage(apiKey, botId, message, conversationId = null, skillP
45
45
  if (config.aiProvider && config.aiApiKey) {
46
46
  body.custom_provider = config.aiProvider;
47
47
  body.custom_api_key = config.aiApiKey;
48
+
49
+ // Model varsa ekle
50
+ if (config.aiModel) {
51
+ body.model = config.aiModel;
52
+ }
48
53
  }
49
54
 
50
55
  return request('/api/agent/chat', {