natureco-cli 2.3.1 → 2.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -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.3.1</div>
214
+ <div class="version-badge" id="version-badge">v2.4.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.3.1',
344
+ version: 'v2.4.0',
345
345
  bots: cfg.bots || [],
346
346
  telegramToken: cfg.telegramToken || null,
347
347
  whatsappConnected: cfg.whatsappConnected || false,
@@ -24,25 +24,17 @@ function loadBaileys() {
24
24
  }
25
25
  }
26
26
 
27
- // Log helper
27
+ // Log helper - only writes to console in worker, file writing handled by stdio redirect
28
28
  function log(module, message, color = 'white') {
29
29
  const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
30
30
  const logLine = `[${timestamp}] [${module}] ${message}`;
31
31
 
32
- // Console output with color
32
+ // Console output with color (will be redirected to file by parent process)
33
33
  const colorFn = chalk[color] || chalk.white;
34
34
  console.log(colorFn(logLine));
35
35
 
36
- // File output (no color)
37
- try {
38
- const dir = path.dirname(LOG_FILE);
39
- if (!fs.existsSync(dir)) {
40
- fs.mkdirSync(dir, { recursive: true });
41
- }
42
- fs.appendFileSync(LOG_FILE, logLine + '\n', 'utf-8');
43
- } catch (err) {
44
- // Ignore file write errors
45
- }
36
+ // Note: File writing removed - parent process redirects stdout/stderr to log file
37
+ // This prevents duplicate log entries
46
38
  }
47
39
 
48
40
  // Number matching helper - compare last 10 digits only
@@ -136,7 +128,7 @@ async function startGateway() {
136
128
 
137
129
  async function runGatewayWorker() {
138
130
  // This runs in the background
139
- log('gateway', 'Starting NatureCo Gateway v2.3.1...', 'green');
131
+ log('gateway', 'Starting NatureCo Gateway v2.3.2...', 'green');
140
132
 
141
133
  // Load config
142
134
  const { getConfig } = require('../utils/config');
package/src/utils/api.js CHANGED
@@ -1,13 +1,48 @@
1
- // NatureCo CLI v2.2.2 - Universal LLM Provider Support
1
+ // NatureCo CLI v2.4.0 - Universal LLM Provider Support
2
2
  // Supports: OpenAI, Groq, Together, Fireworks, Perplexity, Mistral, DeepSeek, OpenRouter, Ollama, LM Studio, Anthropic
3
3
 
4
+ const fs = require('fs');
4
5
  const os = require('os');
6
+ const path = require('path');
5
7
  const { getConfig } = require('./config');
6
8
  const { getToolDefinitions, executeToolCalls } = require('./tool-runner');
7
9
 
8
- // Conversation history for multi-turn chat
10
+ // Persistent conversation directory
11
+ const CONV_DIR = path.join(os.homedir(), '.natureco', 'conversations');
12
+
13
+ // Conversation history for multi-turn chat (deprecated - now using disk storage)
9
14
  const conversationHistory = new Map();
10
15
 
16
+ /**
17
+ * Load conversation from disk
18
+ */
19
+ function loadConversation(convId) {
20
+ const file = path.join(CONV_DIR, `${convId.replace(/[^a-z0-9]/gi, '_')}.json`);
21
+ try {
22
+ fs.mkdirSync(CONV_DIR, { recursive: true });
23
+ if (fs.existsSync(file)) {
24
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
25
+ }
26
+ } catch (e) {
27
+ // Silently fail
28
+ }
29
+ return [];
30
+ }
31
+
32
+ /**
33
+ * Save conversation to disk
34
+ */
35
+ function saveConversation(convId, messages) {
36
+ const file = path.join(CONV_DIR, `${convId.replace(/[^a-z0-9]/gi, '_')}.json`);
37
+ try {
38
+ fs.mkdirSync(CONV_DIR, { recursive: true });
39
+ // Keep only last 20 messages
40
+ fs.writeFileSync(file, JSON.stringify(messages.slice(-20), null, 2));
41
+ } catch (e) {
42
+ // Silently fail
43
+ }
44
+ }
45
+
11
46
  /**
12
47
  * Check if debug mode is enabled
13
48
  */
@@ -182,12 +217,9 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
182
217
  );
183
218
  }
184
219
 
185
- // Get or create conversation history
220
+ // Get or create conversation history (load from disk)
186
221
  const convId = conversationId || `conv_${Date.now()}`;
187
- if (!conversationHistory.has(convId)) {
188
- conversationHistory.set(convId, []);
189
- }
190
- const history = conversationHistory.get(convId);
222
+ const history = loadConversation(convId);
191
223
 
192
224
  // Build messages
193
225
  const messages = [];
@@ -276,10 +308,8 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
276
308
  history.push({ role: 'user', content: message });
277
309
  history.push({ role: 'assistant', content: finalResponse });
278
310
 
279
- // Keep history limited to last 20 messages
280
- if (history.length > 20) {
281
- conversationHistory.set(convId, history.slice(-20));
282
- }
311
+ // Save to disk (automatically keeps last 20 messages)
312
+ saveConversation(convId, history);
283
313
 
284
314
  return {
285
315
  reply: finalResponse,
@@ -294,8 +324,30 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
294
324
  */
295
325
  function clearConversation(conversationId) {
296
326
  if (conversationId) {
327
+ // Delete from disk
328
+ const file = path.join(CONV_DIR, `${conversationId.replace(/[^a-z0-9]/gi, '_')}.json`);
329
+ try {
330
+ if (fs.existsSync(file)) {
331
+ fs.unlinkSync(file);
332
+ }
333
+ } catch (e) {
334
+ // Silently fail
335
+ }
336
+ // Also clear from memory (legacy)
297
337
  conversationHistory.delete(conversationId);
298
338
  } else {
339
+ // Clear all conversations from disk
340
+ try {
341
+ if (fs.existsSync(CONV_DIR)) {
342
+ const files = fs.readdirSync(CONV_DIR);
343
+ files.forEach(file => {
344
+ fs.unlinkSync(path.join(CONV_DIR, file));
345
+ });
346
+ }
347
+ } catch (e) {
348
+ // Silently fail
349
+ }
350
+ // Also clear from memory (legacy)
299
351
  conversationHistory.clear();
300
352
  }
301
353
  }