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.
- package/package.json +1 -1
- 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.
|
|
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"
|
package/src/commands/repl.js
CHANGED
|
@@ -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(
|
|
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.
|
|
752
|
-
//
|
|
753
|
-
//
|
|
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
|
-
//
|
|
768
|
-
toProcess = toProcess.replace(
|
|
769
|
-
toProcess = toProcess.replace(
|
|
770
|
-
toProcess = toProcess.replace(
|
|
771
|
-
|
|
772
|
-
toProcess = toProcess.replace(
|
|
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
|
}
|