natureco-cli 1.0.24 → 1.0.25

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.25",
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,111 @@ 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
 
68
91
  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
- });
92
+ // Load Baileys
93
+ loadBaileys();
79
94
 
80
- if (!response.ok) {
81
- const error = await response.text();
82
- throw new Error(error);
95
+ // Create session directory
96
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, botId);
97
+ if (!fs.existsSync(sessionDir)) {
98
+ fs.mkdirSync(sessionDir, { recursive: true });
83
99
  }
84
100
 
85
- const data = await response.json();
101
+ // Create auth state
102
+ const { state, saveCreds } = await useMultiFileAuthState(sessionDir);
86
103
 
87
- if (!data.session_id) {
88
- throw new Error('No session ID returned');
89
- }
104
+ // Get latest Baileys version
105
+ const { version } = await fetchLatestBaileysVersion();
90
106
 
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'));
107
+ console.log(chalk.yellow(' WhatsApp client başlatılıyor...\n'));
94
108
 
95
- // Save session ID to config
96
- config.whatsappSessionId = data.session_id;
97
- config.whatsappConnected = true;
98
- config.whatsappBotId = botId;
99
- saveConfig(config);
100
-
101
- // Connect to SSE endpoint for QR code
102
- const sseUrl = `http://localhost:3000/qr/${data.session_id}`;
103
- const eventSource = new EventSource(sseUrl);
109
+ // Create socket
110
+ const sock = makeWASocket({
111
+ version,
112
+ auth: state,
113
+ printQRInTerminal: false,
114
+ browser: Browsers.ubuntu('Chrome'),
115
+ logger: logger,
116
+ });
104
117
 
105
118
  let qrDisplayed = false;
119
+ let isConnected = false;
106
120
 
107
- eventSource.onmessage = (event) => {
108
- try {
109
- const eventData = JSON.parse(event.data);
121
+ // Connection update handler
122
+ sock.ev.on('connection.update', async (update) => {
123
+ const { connection, lastDisconnect, qr } = update;
124
+
125
+ if (qr && !qrDisplayed) {
126
+ console.log(chalk.green('✅ QR kod hazır!\n'));
110
127
 
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();
136
- process.exit(0);
137
- } else if (eventData.type === 'error') {
138
- console.log(chalk.red(`\n❌ Hata: ${eventData.error}\n`));
139
- eventSource.close();
140
- process.exit(1);
141
- } else if (eventData.type === 'disconnected') {
142
- console.log(chalk.yellow(`\n⚠️ Bağlantı kesildi: ${eventData.reason}\n`));
143
- eventSource.close();
144
- process.exit(1);
128
+ // Display QR code in terminal
129
+ qrcode.generate(qr, { small: true });
130
+
131
+ console.log('');
132
+ console.log(chalk.gray('1. WhatsApp\'ı açın'));
133
+ console.log(chalk.gray('2. Ayarlar > Bağlı Cihazlar > Cihaz Bağla'));
134
+ console.log(chalk.gray('3. Bu QR kodu taratın\n'));
135
+ console.log(chalk.yellow('⏳ QR kod taranması bekleniyor...\n'));
136
+
137
+ qrDisplayed = true;
138
+ }
139
+
140
+ if (connection === 'close') {
141
+ const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
142
+ const statusCode = lastDisconnect?.error?.output?.statusCode;
143
+
144
+ if (statusCode === DisconnectReason.loggedOut) {
145
+ console.log(chalk.red('\n❌ WhatsApp oturumu kapatıldı\n'));
146
+ } else if (!isConnected) {
147
+ console.log(chalk.red('\n❌ Bağlantı başarısız\n'));
148
+ console.log(chalk.gray(`Hata kodu: ${statusCode}\n`));
149
+ } else {
150
+ console.log(chalk.yellow('\n⚠️ Bağlantı kesildi\n'));
145
151
  }
146
- } catch (err) {
147
- console.error(chalk.red('Event parse error:'), err.message);
152
+
153
+ process.exit(statusCode === DisconnectReason.loggedOut ? 0 : 1);
154
+ } else if (connection === 'open') {
155
+ isConnected = true;
156
+ console.log(chalk.green('✅ WhatsApp bağlandı!\n'));
157
+ console.log(chalk.cyan('Bot:'), chalk.white(selectedBot.name));
158
+ console.log(chalk.cyan('Telefon:'), chalk.white(sock.user?.id || 'Unknown'));
159
+ console.log(chalk.gray('\nSession kaydedildi: ~/.natureco/whatsapp-sessions/'));
160
+
161
+ // Save to config
162
+ config.whatsappConnected = true;
163
+ config.whatsappBotId = botId;
164
+ config.whatsappPhone = sock.user?.id;
165
+ saveConfig(config);
166
+
167
+ console.log(chalk.green('\n✅ Kurulum tamamlandı!\n'));
168
+ console.log(chalk.gray('Botunuz WhatsApp\'ta aktif.\n'));
169
+
170
+ // Keep process alive for a moment then exit
171
+ setTimeout(() => {
172
+ process.exit(0);
173
+ }, 2000);
148
174
  }
149
- };
175
+ });
150
176
 
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
- };
177
+ // Save credentials on update
178
+ sock.ev.on('creds.update', saveCreds);
157
179
 
158
180
  // Handle Ctrl+C
159
181
  process.on('SIGINT', () => {
160
182
  console.log(chalk.yellow('\n\n⚠️ Bağlantı iptal edildi\n'));
161
- eventSource.close();
162
183
  process.exit(0);
163
184
  });
164
185
 
165
186
  } catch (err) {
166
187
  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'));
188
+ if (err.message.includes('Cannot find module')) {
189
+ console.log(chalk.yellow('⚠️ Baileys paketi yüklü değil. Yükleniyor...\n'));
190
+ console.log(chalk.gray('Lütfen şu komutu çalıştırın:\n'));
191
+ console.log(chalk.cyan('npm install -g @whiskeysockets/baileys pino\n'));
192
+ }
168
193
  process.exit(1);
169
194
  }
170
195
  }
@@ -193,39 +218,28 @@ async function disconnectWhatsApp() {
193
218
  return;
194
219
  }
195
220
 
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}`));
221
+ try {
222
+ // Remove session directory
223
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, config.whatsappBotId);
224
+ if (fs.existsSync(sessionDir)) {
225
+ fs.rmSync(sessionDir, { recursive: true, force: true });
226
+ console.log(chalk.green('\n✅ Session dosyaları silindi\n'));
215
227
  }
228
+
229
+ // Remove from config
230
+ delete config.whatsappConnected;
231
+ delete config.whatsappBotId;
232
+ delete config.whatsappPhone;
233
+ saveConfig(config);
234
+
235
+ console.log(chalk.green('✅ WhatsApp disconnected\n'));
236
+ console.log(chalk.gray('Note: You may need to manually remove the device from WhatsApp settings.\n'));
237
+ } catch (err) {
238
+ console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
216
239
  }
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
240
  }
227
241
 
228
- async function statusWhatsApp() {
242
+ function statusWhatsApp() {
229
243
  const config = getConfig();
230
244
 
231
245
  if (!config.whatsappConnected) {
@@ -234,54 +248,23 @@ async function statusWhatsApp() {
234
248
  return;
235
249
  }
236
250
 
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'));
251
+ console.log(chalk.green('\n✅ WhatsApp connected\n'));
278
252
 
279
253
  if (config.whatsappBotId) {
280
254
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.whatsappBotId));
281
255
  }
282
256
 
283
- if (config.whatsappSessionId) {
284
- console.log(chalk.cyan('Session ID:'), chalk.white(config.whatsappSessionId));
257
+ if (config.whatsappPhone) {
258
+ console.log(chalk.cyan('Phone:'), chalk.white(config.whatsappPhone));
259
+ }
260
+
261
+ // Check if session files exist
262
+ const sessionDir = path.join(WHATSAPP_SESSION_DIR, config.whatsappBotId);
263
+ if (fs.existsSync(sessionDir)) {
264
+ console.log(chalk.cyan('Session:'), chalk.white('Active'));
265
+ console.log(chalk.gray(`Location: ${sessionDir}`));
266
+ } else {
267
+ console.log(chalk.yellow('Session:'), chalk.gray('Not found (may need to reconnect)'));
285
268
  }
286
269
 
287
270
  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', {