natureco-cli 5.14.1 → 5.14.3
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/tools/memory.js +46 -3
- package/src/tools/workflow.js +24 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.14.
|
|
3
|
+
"version": "5.14.3",
|
|
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/tools/memory.js
CHANGED
|
@@ -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
|
-
|
|
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';
|
package/src/tools/workflow.js
CHANGED
|
@@ -73,14 +73,14 @@ async function workflow(params) {
|
|
|
73
73
|
// Phase 0: Check if simple chat (passthrough) — no planning needed
|
|
74
74
|
const simpleCheckPrompt = {
|
|
75
75
|
role: 'system',
|
|
76
|
-
content: 'Gorevin basit bir selamlasma/sohbet mi yoksa arac gerektiren bir islem mi oldugunu belirle. Sadece "simple" veya "complex" yaz, baska bir sey yazma.\n\nSimple: selamlasma, nasilsin, bugun ne yaptin, havadan sudan, genel bilgi sorusu\nComplex: dosya islemleri, kod yazma, arastirma, karsilastirma, duzenleme, otomasyon, proje yonetimi, debug'
|
|
76
|
+
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. Noktalama isareti koyma.\n\nSimple: selamlasma, nasilsin, bugun ne yaptin, havadan sudan, genel bilgi sorusu\nComplex: dosya islemleri, kod yazma, arastirma, karsilastirma, duzenleme, otomasyon, proje yonetimi, debug'
|
|
77
77
|
};
|
|
78
|
-
const simpleBody = { model, stream: false, messages: [simpleCheckPrompt, { role: 'user', content: task }], temperature: 0, max_tokens:
|
|
78
|
+
const simpleBody = { model, stream: false, messages: [simpleCheckPrompt, { role: 'user', content: task }], temperature: 0, max_tokens: 20 };
|
|
79
79
|
let isSimple = false;
|
|
80
80
|
try {
|
|
81
81
|
const simpleResult = await apiCall(providerUrl, providerApiKey, simpleBody);
|
|
82
|
-
const
|
|
83
|
-
isSimple =
|
|
82
|
+
const raw = (simpleResult.choices?.[0]?.message?.content || '').trim().toLowerCase().replace(/[^a-z]/g, '');
|
|
83
|
+
isSimple = raw === 'simple';
|
|
84
84
|
} catch {}
|
|
85
85
|
|
|
86
86
|
if (isSimple) {
|
|
@@ -115,11 +115,29 @@ async function workflow(params) {
|
|
|
115
115
|
return { success: false, error: 'Plan olusturulamadi: ' + e.message, phase: 'planning' };
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
// v5.14.2: Brace-balanced JSON extraction (handles explanatory text around JSON)
|
|
119
|
+
function extractJSON(str) {
|
|
120
|
+
const start = str.indexOf('{');
|
|
121
|
+
if (start === -1) return null;
|
|
122
|
+
let depth = 0, inString = false, escape = false;
|
|
123
|
+
for (let i = start; i < str.length; i++) {
|
|
124
|
+
const ch = str[i];
|
|
125
|
+
if (escape) { escape = false; continue; }
|
|
126
|
+
if (ch === '\\' && inString) { escape = true; continue; }
|
|
127
|
+
if (ch === '"') { inString = !inString; continue; }
|
|
128
|
+
if (!inString) {
|
|
129
|
+
if (ch === '{') depth++;
|
|
130
|
+
else if (ch === '}') { depth--; if (depth === 0) return str.slice(start, i + 1); }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
118
135
|
let plan;
|
|
119
136
|
try {
|
|
120
137
|
const content = planResult.choices?.[0]?.message?.content || '';
|
|
121
|
-
const
|
|
122
|
-
|
|
138
|
+
const jsonStr = extractJSON(content);
|
|
139
|
+
if (!jsonStr) throw new Error('JSON bloku bulunamadi');
|
|
140
|
+
plan = JSON.parse(jsonStr);
|
|
123
141
|
if (!plan.steps || !Array.isArray(plan.steps)) throw new Error('Steps bulunamadi');
|
|
124
142
|
} catch (e) {
|
|
125
143
|
return { success: false, error: 'Plan cozumlenemedi: ' + e.message, raw: planResult.choices?.[0]?.message?.content?.slice(0, 500) };
|