natureco-cli 5.22.0 → 5.23.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to NatureCo CLI will be documented in this file.
4
4
 
5
+ ## [5.23.0] - 2026-07-02 — "NON-TOOL-CALLING FIX" (MiniMax dosya yazma)
6
+
7
+ ### 🐛 Düzeltme
8
+ - **MiniMax (non-tool-calling) dosya oluşturamıyordu**: workflow non-tool-calling path'inde simple/complex ayrımı yoktu — LLM yanıtını doğrudan sohbete yazıp geçiyordu. Artık complex görevlerde LLM'den JSON plan istenir, dosyalar Node.js tarafında yazılır.
9
+
10
+ ## [5.22.0] - 2026-07-02
11
+
5
12
  ## [5.21.0] - 2026-07-02 — "GÜVENİLİRLİK SPRİNTİ" (gerçek API E2E denetimi)
6
13
 
7
14
  Gerçek MiniMax API anahtarıyla uçtan uca canlı test turu; bulunan her hata düzeltilip yine canlı doğrulandı. 461 test yeşil.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.22.0",
3
+ "version": "5.23.0",
4
4
  "description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
5
5
  "bin": {
6
6
  "natureco": "bin/natureco.js"
@@ -126,14 +126,88 @@ async function workflow(params) {
126
126
  if (action === 'run') {
127
127
  if (!task) return { success: false, error: 'task gerekli' };
128
128
 
129
- // Non-tool-calling modellerde dogrudan passthrough (plan yok, direkt uretim)
129
+ // Non-tool-calling modellerde once simple/complex kontrolu yap
130
130
  if (!supportsToolCalls()) {
131
131
  const memCtx = memoryContext();
132
- const sysMsg = 'Sen yardimci bir asistansin. Kullanici ne istediyse onu dogrudan yap. Dosya olusturulacaksa icerigi eksiksiz olarak yanitla.' + (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '') + '\n\n' + skillsIndexBlock;
133
- const chatBody = { model, stream: false, messages: chatMessages(sysMsg, task), temperature: 0.7, max_tokens: 4000 };
132
+ // Phase 0: Check if simple chat or complex task
133
+ const simpleCheckPrompt = {
134
+ role: 'system',
135
+ content: 'Gorevin basit bir selamlasma/sohbet mi yoksa arac gerektiren bir islem mi oldugunu belirle. Sadece "simple" veya "complex" yaz, kesinlikle baska bir sey yazma.\n\nSimple: selamlasma, nasilsin, bugun ne yaptin, havadan sudan, genel bilgi sorusu, ben kimim, adim ne, kullanici bilgisi sorgulama, hatirlatma talebi\nComplex: dosya islemleri, kod yazma, arastirma, karsilastirma, duzenleme, otomasyon'
136
+ };
137
+ let isComplex = true;
134
138
  try {
135
- const chatResult = await apiCall(providerUrl, providerApiKey, chatBody);
136
- const reply = chatResult.choices?.[0]?.message?.content || '';
139
+ const checkBody = { model, stream: false, messages: [simpleCheckPrompt, { role: 'user', content: task }], temperature: 0, max_tokens: 20 };
140
+ const checkResult = await apiCall(providerUrl, providerApiKey, checkBody);
141
+ const raw = (checkResult.choices?.[0]?.message?.content || '').trim().toLowerCase().replace(/[^a-z]/g, '');
142
+ isComplex = raw !== 'simple';
143
+ } catch {}
144
+
145
+ if (!isComplex) {
146
+ // Simple chat — passthrough
147
+ const sysMsg = 'Sen yardimci bir asistansin. Kisa ve oz yanit ver. Konusma gecmisi varsa onceki mesajlari dikkate al.' + (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '') + '\n\n' + skillsIndexBlock;
148
+ const chatBody = { model, stream: false, messages: chatMessages(sysMsg, task), temperature: 0.7, max_tokens: 1000 };
149
+ try {
150
+ const chatResult = await apiCall(providerUrl, providerApiKey, chatBody);
151
+ const reply = chatResult.choices?.[0]?.message?.content || '';
152
+ return { success: true, workflowId: 'passthrough', name: 'Direct Chat', status: 'completed', totalSteps: 0, completedSteps: 0, results: [], passthrough: true, reply };
153
+ } catch (e) {
154
+ return { success: false, error: 'Sohbet yaniti alinamadi: ' + e.message };
155
+ }
156
+ }
157
+
158
+ // Complex task for non-tool-calling model: ask LLM for structured file ops
159
+ const execSysMsg = 'Gorevi tamamlamak icin hangi dosyalarin olusturulacagini JSON olarak belirt. SADECE JSON yaz.\n\n' +
160
+ 'Kullanici bilgisi:\n' + (memCtx || '') +
161
+ '\n\nMasaustu yolu: ' + require('path').join(require('os').homedir(), 'Desktop') +
162
+ '\n\nKullanici home: ' + require('os').homedir() +
163
+ '\n\nJSON format:\n{"files": [{"path": "/tam/dosya/yolu/dosya.html", "content": "dosya icerigi buraya"}]}\n\nHer dosya icin path ve content zorunlu. path TAM yol olmali (~ veya goreceli degil). Birden fazla dosya olusturulabilir.' +
164
+ '\n\n' + skillsIndexBlock;
165
+ const execBody = { model, stream: false, messages: chatMessages(execSysMsg, task), temperature: 0.3, max_tokens: 8000 };
166
+ try {
167
+ const execResult = await apiCall(providerUrl, providerApiKey, execBody);
168
+ const reply = execResult.choices?.[0]?.message?.content || '';
169
+
170
+ // Try to extract JSON with file operations
171
+ const jsonStart = reply.indexOf('{');
172
+ const jsonEnd = reply.lastIndexOf('}');
173
+ let stepResults = [];
174
+ let fileWriteSuccess = false;
175
+
176
+ if (jsonStart !== -1 && jsonEnd > jsonStart) {
177
+ try {
178
+ const plan = JSON.parse(reply.slice(jsonStart, jsonEnd + 1));
179
+ if (plan.files && Array.isArray(plan.files)) {
180
+ // Execute file writes locally
181
+ for (const f of plan.files) {
182
+ try {
183
+ const wfPath = f.path ? require('path').resolve(f.path.replace(/^~/, require('os').homedir())) : '';
184
+ if (!wfPath) continue;
185
+ require('fs').mkdirSync(require('path').dirname(wfPath), { recursive: true });
186
+ require('fs').writeFileSync(wfPath, f.content || '', 'utf-8');
187
+ const stats = require('fs').statSync(wfPath);
188
+ stepResults.push({ step: 1, tool: 'write_file', status: 'done', args: { path: wfPath }, result: { success: true, path: wfPath, size: stats.size } });
189
+ fileWriteSuccess = true;
190
+ } catch (wfErr) {
191
+ stepResults.push({ step: 1, tool: 'write_file', status: 'error', error: wfErr.message });
192
+ }
193
+ }
194
+ }
195
+ } catch {}
196
+ }
197
+
198
+ if (fileWriteSuccess) {
199
+ const lines = stepResults.map(r => { const p = r.result?.path || ''; const s = r.result?.size || 0; const name = require('path').basename(p); return ` ✓ ${name} oluşturuldu (${s} bytes)`; }).join('\n');
200
+ const reply = `Dosya(lar) başarıyla oluşturuldu:\n${lines}`;
201
+ return {
202
+ success: true, workflowId: 'file_write_' + Date.now().toString(36),
203
+ name: 'File Operations', status: 'completed',
204
+ totalSteps: stepResults.length, completedSteps: stepResults.length,
205
+ results: stepResults,
206
+ passthrough: true, reply,
207
+ };
208
+ }
209
+
210
+ // If no structured file ops detected, return LLM reply as passthrough
137
211
  return { success: true, workflowId: 'passthrough', name: 'Direct Generation', status: 'completed', totalSteps: 0, completedSteps: 0, results: [{ step: 0, tool: 'chat', status: 'done', result: { reply } }], passthrough: true, reply };
138
212
  } catch (e) {
139
213
  return { success: false, error: 'Yanit alinamadi: ' + e.message };