natureco-cli 5.14.2 → 5.14.4

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": "5.14.2",
3
+ "version": "5.14.4",
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"
@@ -119,13 +119,38 @@ function _searchSessions(query, maxResults) {
119
119
  return results;
120
120
  }
121
121
 
122
+ // ── Bridge to JSON fact store (memory_write) ──────────────────────────────
123
+ function _loadJsonFacts(username) {
124
+ try {
125
+ const file = path.join(MEMORY_DIR, `${(username || 'default').toLowerCase()}.json`);
126
+ if (fs.existsSync(file)) return JSON.parse(fs.readFileSync(file, 'utf8'));
127
+ } catch {}
128
+ return { facts: [], name: null };
129
+ }
130
+
131
+ function _saveJsonFact(username, fact, category) {
132
+ try {
133
+ const file = path.join(MEMORY_DIR, `${(username || 'default').toLowerCase()}.json`);
134
+ const mem = _loadJsonFacts(username);
135
+ const now = new Date().toISOString();
136
+ const existing = mem.facts.find(f => (f.value || '').toLowerCase() === fact.toLowerCase());
137
+ if (existing) { existing.score = Math.min(10, (existing.score || 5) + 2); existing.updatedAt = now; }
138
+ else { mem.facts.push({ value: fact, score: 5, category: category || 'personal', createdAt: now, updatedAt: now }); }
139
+ if (mem.facts.length > 50) mem.facts.sort((a,b) => (b.score||0)-(a.score||0)).slice(0, 50);
140
+ if (!fs.existsSync(path.dirname(file))) fs.mkdirSync(path.dirname(file), { recursive: true });
141
+ fs.writeFileSync(file, JSON.stringify(mem, null, 2));
142
+ } catch {}
143
+ }
144
+
122
145
  async function execute(args) {
123
146
  const store = getMemoryStore();
124
- const { action, target = 'memory', content, oldContent, scope, maxResults = 10 } = args;
147
+ const { action, target = 'memory', content, oldContent, scope, maxResults = 10, username } = args;
125
148
 
126
149
  switch (action) {
127
150
  case 'add':
128
151
  if (!content) return JSON.stringify({ success: false, error: 'content required for add' });
152
+ // Bridge: also save to JSON fact store for target=user
153
+ if (target === 'user') _saveJsonFact(username || 'default', content, 'personal');
129
154
  return store.add(target, content);
130
155
  case 'remove':
131
156
  if (!content) return JSON.stringify({ success: false, error: 'content required for remove' });
@@ -133,8 +158,26 @@ async function execute(args) {
133
158
  case 'replace':
134
159
  if (!content || !oldContent) return JSON.stringify({ success: false, error: 'content and oldContent required for replace' });
135
160
  return store.replace(target, oldContent, content);
136
- case 'list':
137
- return store.list(target);
161
+ case 'list': {
162
+ // Bridge: include JSON facts for target=user
163
+ let result = store.list(target);
164
+ if (target === 'user') {
165
+ try {
166
+ const parsed = typeof result === 'string' ? JSON.parse(result) : result;
167
+ if (parsed.success) {
168
+ const jsonMem = _loadJsonFacts(username || 'default');
169
+ if (jsonMem.facts && jsonMem.facts.length > 0) {
170
+ const storedFacts = jsonMem.facts.map(f => `- ${f.value} (onem: ${f.score || 5})`);
171
+ parsed.entries.push('--- JSON hafiza ---');
172
+ parsed.entries.push(...storedFacts);
173
+ parsed.count = parsed.entries.length;
174
+ result = JSON.stringify(parsed);
175
+ }
176
+ }
177
+ } catch {}
178
+ }
179
+ return result;
180
+ }
138
181
  case 'search': {
139
182
  if (!content) return JSON.stringify({ success: false, error: 'content (query) required for search' });
140
183
  const s = scope || 'all';
@@ -20,6 +20,27 @@ function allToolNames() {
20
20
  } catch { return []; }
21
21
  }
22
22
 
23
+ function loadUserMemory(username) {
24
+ try {
25
+ const file = path.join(os.homedir(), '.natureco', 'memory', `${(username || 'default').toLowerCase()}.json`);
26
+ if (fs.existsSync(file)) {
27
+ const mem = JSON.parse(fs.readFileSync(file, 'utf8'));
28
+ const facts = (mem.facts || []).map(f => f.value || f).filter(Boolean);
29
+ const name = mem.name || '';
30
+ const parts = [];
31
+ if (name) parts.push(`Kullanici adi: ${name}`);
32
+ if (facts.length > 0) parts.push(`Bilinenler: ${facts.slice(0, 10).join('; ')}`);
33
+ return parts.join('\n');
34
+ }
35
+ } catch {}
36
+ return '';
37
+ }
38
+
39
+ function memoryContext() {
40
+ const cfg = loadConfig();
41
+ return loadUserMemory(cfg.userName);
42
+ }
43
+
23
44
  function apiCall(providerUrl, apiKey, body) {
24
45
  return new Promise((resolve, reject) => {
25
46
  const base = providerUrl.replace(/\/+$/, '');
@@ -84,8 +105,10 @@ async function workflow(params) {
84
105
  } catch {}
85
106
 
86
107
  if (isSimple) {
87
- // Passthrough: just chat with LLM, no tools
88
- const chatBody = { model, stream: false, messages: [{ role: 'system', content: 'Sen yardimci bir asistansin. Kisa ve oz yanit ver.' }, { role: 'user', content: task }], temperature: 0.7, max_tokens: 1000 };
108
+ // Passthrough: just chat with LLM, no tools — include user memory
109
+ const memCtx = memoryContext();
110
+ const sysMsg = 'Sen yardimci bir asistansin. Kisa ve oz yanit ver.' + (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '');
111
+ const chatBody = { model, stream: false, messages: [{ role: 'system', content: sysMsg }, { role: 'user', content: task }], temperature: 0.7, max_tokens: 1000 };
89
112
  try {
90
113
  const chatResult = await apiCall(providerUrl, providerApiKey, chatBody);
91
114
  const reply = chatResult.choices?.[0]?.message?.content || '';
@@ -96,10 +119,12 @@ async function workflow(params) {
96
119
  }
97
120
 
98
121
  // Phase 1: LLM plans the workflow
122
+ const memCtx = memoryContext();
99
123
  const planPrompt = {
100
124
  role: 'system',
101
125
  content: 'Sen bir workflow planlama asistanisin. Verilen gorev icin hangi tool\'larin kullanilacagini ve hangi sirayla calisacagini belirle. SADECE JSON formatinda yanit ver, baska bir sey yazma.\n\nKullanilabilir tool\'lar:\n' +
102
126
  tools.map(t => '- ' + t).join('\n') +
127
+ (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '') +
103
128
  '\n\nJSON format:\n{\n "workflowName": "...",\n "description": "...",\n "steps": [\n { "step": 1, "tool": "tool_name", "purpose": "...", "params": { ... } }\n ]\n}\n\nHer adim icin params kismina tool\'un gerektirdigi parametreleri ekle. Adimlar birbirine bagimli olabilir, onceki adimin outputu sonraki adimin inputu olarak kullanilabilir.'
104
129
  };
105
130
  const planBody = {