natureco-cli 5.4.9 → 5.4.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/commands/repl.js +129 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.4.9",
3
+ "version": "5.4.11",
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"
@@ -471,13 +471,38 @@ async function startRepl(args) {
471
471
  const fs = require('fs');
472
472
  const memFile = path.join(os.homedir(), '.natureco', 'memory', ((cfg.userName || 'default').toLowerCase()) + '.json');
473
473
  if (fs.existsSync(memFile)) {
474
- const memData = JSON.parse(fs.readFileSync(memFile, 'utf8'));
474
+ const memData = JSON.parse(memFile, 'utf8'));
475
475
  if (!memData.botName || memData.botName !== memory.botName) {
476
476
  memData.botName = memory.botName;
477
477
  fs.writeFileSync(memFile, JSON.stringify(memData, null, 2), 'utf8');
478
478
  }
479
479
  }
480
480
  } catch (e) {} // Sessizce devam et, kritik degil
481
+
482
+ // v5.4.11: Sasuke Brain - Cross-session context otomatik yukle
483
+ // REPL acildiginda son oturumdan 1-2 context mesaji al
484
+ let crossSessionContext = '';
485
+ try {
486
+ const { listSessions, loadSession } = require('../utils/sessions-helper');
487
+ if (listSessions && loadSession) {
488
+ const sessions = listSessions(1);
489
+ if (sessions && sessions.length > 0) {
490
+ const lastSession = loadSession(sessions[0].id);
491
+ if (lastSession && lastSession.messages && lastSession.messages.length > 0) {
492
+ // Son 2 user message
493
+ const lastUserMsgs = lastSession.messages
494
+ .filter(m => m.role === 'user')
495
+ .slice(-2);
496
+ if (lastUserMsgs.length > 0) {
497
+ crossSessionContext = '\n[KONUSMA GECMISI: ' + sessions[0].id + ']\n' +
498
+ lastUserMsgs.map(m => 'User: ' + (m.content || '').slice(0, 100)).join('\n') + '\n[/GECMISI]\n';
499
+ }
500
+ }
501
+ }
502
+ }
503
+ } catch (e) {
504
+ // Cross-session yukleme basarisiz, devam et
505
+ }
481
506
  // v5.4.5: SOUL.md'yi yukle ve kisiligi system prompt'a enjekte et
482
507
  const { loadSoul, summarizeSoul } = require("../tools/soul");
483
508
  const soulContent = loadSoul();
@@ -538,6 +563,8 @@ async function startRepl(args) {
538
563
  // === KULLANICI BAGLAMI ===
539
564
  cfg.userHome ? `Kullanicinin home dizini: ${cfg.userHome}. Downloads: ${cfg.userHome}/Downloads, Desktop: ${cfg.userHome}/Desktop.` : '',
540
565
  messages.length > 0 ? 'Bu oturum daha onceki konusmalarin devami.' : '',
566
+ // v5.4.11: Cross-session context (Sasuke Brain)
567
+ crossSessionContext ? `GECMISTE KONUSULAN KONULAR: Bu konulari biliyorsun, tekrar sorma:\n${crossSessionContext}` : '',
541
568
 
542
569
  // === SOUL.md (kisilik manifestosu) ===
543
570
  soulSummary ? `=== BENIM KISILIK DOSYAM (SOUL.md) ===\n${soulSummary}\n=== SOUL SONU ===\nBu kisilik dosyasi sana kim oldugunu hatirlatiyor. Burada yazilanlara gore davran. Kullanici "sen kimsin?" derse buradan bilgi kullan.` : '',
@@ -582,23 +609,97 @@ async function startRepl(args) {
582
609
 
583
610
  const cleanup = async (exitCode = 0) => {
584
611
  if (messages.length > 1) {
612
+ // v5.4.10: Once oturumdaki butun conversation'i memory'ye persist et
613
+ // Bu, Parton'un "oturum sonunda konusmalar kaydedilmiyor" sikayetini cözüyor
614
+ const persistResult = await persistSessionToMemory(messages, memory, cfg);
615
+ if (persistResult && persistResult.factsAdded > 0) {
616
+ console.log(chalk.gray(`\n 🧠 ${persistResult.factsAdded} yeni fact memory'ye kaydedildi`));
617
+ }
618
+ if (persistResult && persistResult.preferencesAdded > 0) {
619
+ console.log(chalk.gray(` 🎯 ${persistResult.preferencesAdded} yeni tercih kaydedildi`));
620
+ }
621
+
585
622
  const sessId = saveSession(messages, {
586
623
  provider: providerUrl, model, user: cfg.userName,
587
624
  bot: memory.botName, factCount: memory.facts?.length || 0,
588
625
  });
589
- // Fact extraction (konuşmadan öğren)
590
- const newFacts = extractFacts(messages, memory.facts || []);
591
- if (newFacts.length > 0) {
592
- memory.facts = [...(memory.facts || []), ...newFacts];
593
- saveMemory(cfg.userName, memory);
594
- console.log(chalk.gray(`\n 🧠 ${newFacts.length} yeni fact öğrenildi ve memory'ye eklendi`));
595
- }
596
626
  console.log(chalk.gray(`\n 💾 Oturum kaydedildi: ${sessId}`));
597
627
  }
628
+ // Global buffer temizle
629
+ if (global._fixBuffer) global._fixBuffer = '';
598
630
  console.log(chalk.gray('\n 👋 Görüşürüz!\n'));
599
631
  process.exit(exitCode);
600
632
  };
601
633
 
634
+ /**
635
+ * v5.4.10: Oturum sonunda conversation'dan otomatik fact/preference extraction
636
+ * Bu, kullanıcının "her çıkışta konuşmalar kaydedilmiyor" sikayetini çözer
637
+ */
638
+ async function persistSessionToMemory(messages, memory, cfg) {
639
+ let factsAdded = 0;
640
+ let preferencesAdded = 0;
641
+
642
+ try {
643
+ // Pattern-based extraction (zaten extractFacts var)
644
+ const newFacts = extractFacts(messages, memory.facts || []);
645
+
646
+ // Bazi user message'lari da tara - 'Parton', 'Ichigo', 'patron', 'CEO' gecerse ekle
647
+ const userMessages = messages.filter(m => m.role === 'user' && !m._internal);
648
+ for (const msg of userMessages) {
649
+ const text = (msg.content || '').toLowerCase();
650
+
651
+ // BotName hatirlatmasi
652
+ if (text.includes('ichigo') && text.includes('ad')) {
653
+ if (memory.botName !== 'İchigo') {
654
+ memory.botName = 'İchigo';
655
+ }
656
+ }
657
+
658
+ // Patron/partnership
659
+ if ((text.includes('patron') || text.includes('patronum')) && text.length < 100) {
660
+ const fact = 'Kullanici benim patronum, ona patron diye hitap etmeliyim';
661
+ if (!(memory.facts || []).some(f => f.value === fact)) {
662
+ newFacts.push({ value: fact, score: 8, category: 'personal', createdAt: new Date().toISOString() });
663
+ }
664
+ }
665
+
666
+ // NatureCo CEO
667
+ if (text.includes('natureco') && text.includes('ceo')) {
668
+ const fact = "Kullanici NatureCo CEO'sudur";
669
+ if (!(memory.facts || []).some(f => f.value === fact)) {
670
+ newFacts.push({ value: fact, score: 9, category: 'work', createdAt: new Date().toISOString() });
671
+ }
672
+ }
673
+ }
674
+
675
+ // Deduplicate
676
+ const existingValues = new Set((memory.facts || []).map(f => (f.value || f).toLowerCase()));
677
+ const uniqueFacts = newFacts.filter(f => !existingValues.has((f.value || f).toLowerCase()));
678
+
679
+ if (uniqueFacts.length > 0) {
680
+ memory.facts = [...(memory.facts || []), ...uniqueFacts];
681
+ // v5.4.10: Verification ile kaydet
682
+ const memFile = path.join(MEMORY_DIR, (cfg.userName || 'default').toLowerCase() + '.json');
683
+ memory.lastUpdated = new Date().toISOString();
684
+ fs.writeFileSync(memFile, JSON.stringify(memory, null, 2), 'utf8');
685
+ // Verification: geri oku
686
+ const verify = JSON.parse(fs.readFileSync(memFile, 'utf8');
687
+ factsAdded = uniqueFacts.length;
688
+ }
689
+
690
+ // Decay (eski fact'leri dusuk skora dusur)
691
+ if (memory.facts && memory.facts.length > 15) {
692
+ // Max 15 fact tut, en dusuk skorlu olanlari sil
693
+ memory.facts.sort((a, b) => (b.score || 5) - (a.score || 5));
694
+ memory.facts = memory.facts.slice(0, 15);
695
+ }
696
+ } catch (e) {
697
+ // Sessizce devam et, kritik degil
698
+ }
699
+
700
+ return { factsAdded, preferencesAdded };
701
+ }
702
+
602
703
  rl.on('SIGINT', () => cleanup(0));
603
704
  process.on('SIGINT', () => cleanup(0));
604
705
  process.on('SIGTERM', () => cleanup(0));
@@ -748,31 +849,38 @@ async function startRepl(args) {
748
849
  providerApiKey,
749
850
  apiMessages,
750
851
  model,
751
- // Text chunk callback — v5.4.9: streaming buffer + fix
752
- // Streaming'de cümleler chunk'lar arasinda bolunur ("Ben " + "NatureCo " + "CLI").
753
- // Buffer biriktir, cumle tamamlaninca (. ! ? veya newline) fix uygula.
852
+ // Text chunk callback — v5.4.10: streaming buffer + akıllı fix
853
+ // v5.4.10 FIX: "MiniMax" pattern'inde "[\s\-\w\.]*" İchigo kelimesinin sonuna
854
+ // rakam eklemiş (örn "İchigo5"). Simdi daha spesifik pattern kullan.
754
855
  (chunk) => {
755
856
  try {
756
857
  let c = String(chunk || '');
757
- // Eger fixBuffer global'de yoksa olustur
758
858
  if (!global._fixBuffer) global._fixBuffer = '';
759
859
  global._fixBuffer += c;
760
860
 
761
- // Son karakterle karar ver
762
861
  const lastChar = global._fixBuffer.slice(-1);
763
- // Noktalama veya newline varsa, buffer'i isle ve temizle
764
862
  if (/[.!?\n]/.test(lastChar)) {
765
863
  let toProcess = global._fixBuffer;
766
864
  global._fixBuffer = '';
767
- // Tum model adlarini İchigo ile degistir
768
- toProcess = toProcess.replace(/MiniMax[\s\-\w\.]*/g, 'İchigo');
769
- toProcess = toProcess.replace(/Claude[\s\-\w\.]*/g, 'İchigo');
770
- toProcess = toProcess.replace(/GPT[\s\-\w\.]*/g, 'İchigo');
771
- toProcess = toProcess.replace(/ChatGPT/g, 'İchigo');
772
- toProcess = toProcess.replace(/Ben\s+(?:MiniMax|Claude|GPT|NatureCo\s+CLI|bir\s+AI)[^\n.!?]*/gi, 'Ben İchigo');
865
+ // v5.4.10: Daha spesifik pattern - sadece tam model adlari
866
+ toProcess = toProcess.replace(/\bMiniMax-M[\d.]+\b/gi, 'İchigo');
867
+ toProcess = toProcess.replace(/\bMiniMaxM[\d.]+\b/gi, 'İchigo');
868
+ toProcess = toProcess.replace(/\bMiniMax M[\d.]+\b/gi, 'İchigo');
869
+ // "NatureCo CLI" tam ifadesi
870
+ toProcess = toProcess.replace(/\bNatureCo\s+CLI\b/g, 'İchigo');
871
+ toProcess = toProcess.replace(/\bClaude-[\d.]+\b/gi, 'İchigo');
872
+ toProcess = toProcess.replace(/\bGPT-[\d.]+\b/gi, 'İchigo');
873
+ toProcess = toProcess.replace(/\bChatGPT\b/g, 'İchigo');
874
+ // "Ben X" pattern — sadece belirli kelimeler
875
+ toProcess = toProcess.replace(/Ben\s+MiniMax[-M][\w\.]*/gi, 'Ben İchigo');
876
+ toProcess = toProcess.replace(/Ben\s+Claude[-]?[\d\w\.]*/gi, 'Ben İchigo');
877
+ toProcess = toProcess.replace(/Ben\s+GPT[-]?[\d\w\.]*/gi, 'Ben İchigo');
878
+ toProcess = toProcess.replace(/Ben\s+bir\s+yapay\s+zeka/gi, 'Ben İchigo');
879
+ // v5.4.11: İchigo5 ve İchigo.5 gibi varyasyonları yakala
880
+ toProcess = toProcess.replace(/İchigo[\.\s\-_]*\d+/g, 'İchigo'); // İchigo5, İchigo.5, İchigo-2, İchigo_3
881
+ toProcess = toProcess.replace(/Ben\s+İchigo[\.\s\-_]*\d*/gi, 'Ben İchigo');
773
882
  process.stdout.write(toProcess);
774
883
  }
775
- // Noktalama yoksa, sadece bekle (sonraki chunk'ta tamamlanir)
776
884
  } catch (e) {
777
885
  process.stdout.write(chunk);
778
886
  }