natureco-cli 5.6.20 → 5.6.22
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/code_v5.js +165 -8
- package/src/commands/repl.js +8 -1
- package/src/tools/filesystem.js +1 -1
- package/src/tools/git.js +52 -1
- package/src/tools/grep_search.js +41 -4
- package/src/tools/media_understanding.js +11 -1
- package/src/tools/memory_search.js +18 -10
- package/src/tools/read_file.js +1 -1
- package/src/tools/write_file.js +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.6.
|
|
3
|
+
"version": "5.6.22",
|
|
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/code_v5.js
CHANGED
|
@@ -81,13 +81,159 @@ async function sendMessageWithTools(providerUrl, providerKey, model, messages, t
|
|
|
81
81
|
function confirm(prompt) {
|
|
82
82
|
return new Promise(resolve => {
|
|
83
83
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
84
|
-
rl.question(chalk.yellow("\n ⚠ " + prompt + "
|
|
84
|
+
rl.question(chalk.yellow("\n ⚠ " + prompt + " "), ans => {
|
|
85
85
|
rl.close();
|
|
86
86
|
resolve(!ans || ans.toLowerCase().startsWith("y"));
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* v5.6.21: Risk seviyesi tespiti - sadece riskli işlemlerde onay iste
|
|
93
|
+
* @param {string} tool - tool adı
|
|
94
|
+
* @param {object} args - tool parametreleri
|
|
95
|
+
* @returns {{requiresApproval: boolean, reason: string, level: string}}
|
|
96
|
+
*/
|
|
97
|
+
function assessRisk(tool, args) {
|
|
98
|
+
const argsStr = JSON.stringify(args || {});
|
|
99
|
+
|
|
100
|
+
// ============================================================
|
|
101
|
+
// YÜKSEK RİSK - Mutlaka onay iste
|
|
102
|
+
// ============================================================
|
|
103
|
+
|
|
104
|
+
// bash / shell_command: Tehlikeli komutlar
|
|
105
|
+
if (tool === "bash" || tool === "shell_command") {
|
|
106
|
+
const cmd = (args.command || args.cmd || "").toLowerCase();
|
|
107
|
+
|
|
108
|
+
// Dosya/klasör silme
|
|
109
|
+
if (/\brm\s+(-[rf]+\s+)*/.test(cmd) || /rmdir/.test(cmd)) {
|
|
110
|
+
return { requiresApproval: true, level: "high", reason: `Dosya silme komutu: ${args.command}` };
|
|
111
|
+
}
|
|
112
|
+
if (cmd.includes("sudo ") || cmd.includes("doas ")) {
|
|
113
|
+
return { requiresApproval: true, level: "high", reason: `Yetki yükseltme: ${args.command}` };
|
|
114
|
+
}
|
|
115
|
+
if (cmd.includes("dd if=") || cmd.includes("mkfs") || cmd.includes("fdisk")) {
|
|
116
|
+
return { requiresApproval: true, level: "high", reason: `Disk işlemi: ${args.command}` };
|
|
117
|
+
}
|
|
118
|
+
if (cmd.match(/^\s*mv\s+.*\/(?:\.|\.\.)/)) {
|
|
119
|
+
return { requiresApproval: true, level: "medium", reason: `Üzerine yazma riski: ${args.command}` };
|
|
120
|
+
}
|
|
121
|
+
// chmod 777 veya chown -R
|
|
122
|
+
if (/chmod\s+(-[rR]+\s+)*777/.test(cmd) || /chown\s+-R/.test(cmd)) {
|
|
123
|
+
return { requiresApproval: true, level: "medium", reason: `İzin değişikliği: ${args.command}` };
|
|
124
|
+
}
|
|
125
|
+
// git push --force
|
|
126
|
+
if (/git\s+push.*--force/.test(cmd) || /git\s+push.*-f\s/.test(cmd)) {
|
|
127
|
+
return { requiresApproval: true, level: "high", reason: `Zorla push: ${args.command}` };
|
|
128
|
+
}
|
|
129
|
+
// git reset --hard
|
|
130
|
+
if (/git\s+reset\s+--hard/.test(cmd)) {
|
|
131
|
+
return { requiresApproval: true, level: "high", reason: `Hard reset: ${args.command}` };
|
|
132
|
+
}
|
|
133
|
+
// Üretim/kök dizin
|
|
134
|
+
if (cmd.includes("/etc/") || cmd.includes("/usr/") || cmd.includes("/var/") || cmd.includes("/System/")) {
|
|
135
|
+
return { requiresApproval: true, level: "high", reason: `Sistem dizinine erişim: ${args.command}` };
|
|
136
|
+
}
|
|
137
|
+
// curl/wget internet download
|
|
138
|
+
if (/curl.*\|\s*(bash|sh)/.test(cmd) || /wget.*\|\s*(bash|sh)/.test(cmd)) {
|
|
139
|
+
return { requiresApproval: true, level: "high", reason: `İnternet üzerinden script çalıştırma: ${args.command}` };
|
|
140
|
+
}
|
|
141
|
+
// mac_app_quit veya killall
|
|
142
|
+
if (cmd.includes("killall") || cmd.includes("pkill") || cmd.includes("kill -9")) {
|
|
143
|
+
return { requiresApproval: true, level: "high", reason: `Süreç sonlandırma: ${args.command}` };
|
|
144
|
+
}
|
|
145
|
+
// .natureco veya önemli dosyalara dokunma
|
|
146
|
+
if (cmd.includes(".natureco") && (cmd.includes("rm") || cmd.includes("mv"))) {
|
|
147
|
+
return { requiresApproval: true, level: "high", reason: `NatureCo dizininde tehlikeli işlem: ${args.command}` };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ============================================================
|
|
152
|
+
// ORTA RİSK - Onay iste (bilgilendir)
|
|
153
|
+
// ============================================================
|
|
154
|
+
|
|
155
|
+
// mac_app_quit - uygulama kapatma
|
|
156
|
+
if (tool === "mac_app_quit") {
|
|
157
|
+
return { requiresApproval: true, level: "medium", reason: `Uygulama kapatma: ${args.app || args.name || "?"}` };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// write_file / edit_file - kritik yollara yazma
|
|
161
|
+
if (tool === "write_file" || tool === "edit_file") {
|
|
162
|
+
const path = (args.path || args.file || "").toLowerCase();
|
|
163
|
+
// Hassas dosyalar
|
|
164
|
+
if (path.includes(".env") || path.includes("credentials") || path.includes("secret")) {
|
|
165
|
+
return { requiresApproval: true, level: "high", reason: `Hassas dosya: ${args.path}` };
|
|
166
|
+
}
|
|
167
|
+
if (path.includes("/etc/") || path.includes("/usr/") || path.includes("~/.ssh/")) {
|
|
168
|
+
return { requiresApproval: true, level: "high", reason: `Sistem dosyası: ${args.path}` };
|
|
169
|
+
}
|
|
170
|
+
if (path.includes(".natureco/config.json") || path.includes(".natureco/soul/")) {
|
|
171
|
+
return { requiresApproval: true, level: "medium", reason: `NatureCo config dosyası: ${args.path}` };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ============================================================
|
|
176
|
+
// GÜVENLİ - Onay isteme
|
|
177
|
+
// ============================================================
|
|
178
|
+
|
|
179
|
+
// Normal tool'lar (read_file, list_dir, grep_search, vs.)
|
|
180
|
+
return { requiresApproval: false, level: "low", reason: "" };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* v5.6.21: Tool call sonucunu güvenli yazdir - yol/size gizle
|
|
186
|
+
* Sadece status, success/error ve kisaltilmis onizleme gosterir
|
|
187
|
+
*/
|
|
188
|
+
function printToolCallSafe(name, args, result) {
|
|
189
|
+
console.log(" " + tui.styled("🔧 Tool: " + name, { color: tui.PALETTE.accent, bold: true }));
|
|
190
|
+
// Args'dan sadece ana bilgiyi goster
|
|
191
|
+
const argsShort = summarizeArgs(name, args);
|
|
192
|
+
if (argsShort) {
|
|
193
|
+
console.log(tui.styled(" Args: " + argsShort, { color: tui.PALETTE.muted }));
|
|
194
|
+
}
|
|
195
|
+
// Result'tan sadece status goster, yol/size gizle
|
|
196
|
+
if (!result) return;
|
|
197
|
+
if (result.error) {
|
|
198
|
+
console.log(tui.styled(" ✗ Hata: " + result.error.slice(0, 100), { color: tui.PALETTE.danger }));
|
|
199
|
+
} else {
|
|
200
|
+
const success = result.success !== false;
|
|
201
|
+
const resultStr = typeof result.result === "string"
|
|
202
|
+
? result.result.slice(0, 200)
|
|
203
|
+
: JSON.stringify(result.result || {}).slice(0, 200);
|
|
204
|
+
// Yol/size gizle
|
|
205
|
+
const cleanResult = resultStr
|
|
206
|
+
.replace(/\/?Users\/[^"\\\s]+/g, "~")
|
|
207
|
+
.replace(/\/?home\/[^"\\\s]+/g, "~")
|
|
208
|
+
.replace(/"\w:\\\[^"\\\s]*/g, "...")
|
|
209
|
+
.replace(/"size":\d+/g, "")
|
|
210
|
+
.replace(/"path":"[^"]*"/g, "")
|
|
211
|
+
.replace(/"fileCount":\d+/g, "");
|
|
212
|
+
const statusIcon = success ? "✓" : "✗";
|
|
213
|
+
const statusColor = success ? tui.PALETTE.success : tui.PALETTE.danger;
|
|
214
|
+
console.log(tui.styled(` ${statusIcon} Sonuç: ${cleanResult.trim()}`, { color: statusColor }));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Tool args'dan ana bilgiyi özetle
|
|
220
|
+
*/
|
|
221
|
+
function summarizeArgs(name, args) {
|
|
222
|
+
if (!args || Object.keys(args).length === 0) return null;
|
|
223
|
+
// Path varsa ~ olarak kisalt
|
|
224
|
+
if (args.path) {
|
|
225
|
+
const shortPath = (args.path || "")
|
|
226
|
+
.replace(/\/Users\/[^\/]+/g, "~")
|
|
227
|
+
.replace(/\/home\/[^\/]+/g, "~")
|
|
228
|
+
.replace(/^[A-Z]:\\Users\\[^\\]+/, "~");
|
|
229
|
+
return JSON.stringify({...args, path: shortPath}).slice(0, 120);
|
|
230
|
+
}
|
|
231
|
+
if (args.command) {
|
|
232
|
+
return JSON.stringify({command: args.command.slice(0, 80)}).slice(0, 120);
|
|
233
|
+
}
|
|
234
|
+
return JSON.stringify(args).slice(0, 120);
|
|
235
|
+
}
|
|
236
|
+
|
|
91
237
|
function printToolCall(name, args, result) {
|
|
92
238
|
const argsStr = JSON.stringify(args).slice(0, 100);
|
|
93
239
|
console.log("\n " + tui.styled(" 🔧 Tool: " + name, { color: tui.PALETTE.accent, bold: true }));
|
|
@@ -189,12 +335,18 @@ async function codeV5(targetPath) {
|
|
|
189
335
|
rl.question("", async (input) => {
|
|
190
336
|
input = input.trim();
|
|
191
337
|
if (!input) { process.stdout.write(" " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true })); return ask(); }
|
|
192
|
-
if (input === "/summary"
|
|
338
|
+
if (input === "/summary") {
|
|
339
|
+
printSummary(filesChanged, commandsRun, messages.length - 1, startTime);
|
|
340
|
+
// v5.6.22: /summary sadece gosterir, cikmaz
|
|
341
|
+
process.stdout.write("\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
|
|
342
|
+
return ask();
|
|
343
|
+
}
|
|
344
|
+
if (input === "/done" || input === "exit" || input === "quit") {
|
|
345
|
+
// v5.6.22: /done cikinca summary goster
|
|
193
346
|
printSummary(filesChanged, commandsRun, messages.length - 1, startTime);
|
|
194
347
|
rl.close();
|
|
195
348
|
return;
|
|
196
349
|
}
|
|
197
|
-
if (input === "exit" || input === "quit") { rl.close(); return; }
|
|
198
350
|
|
|
199
351
|
messages.push({ role: "user", content: input });
|
|
200
352
|
process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
|
|
@@ -215,13 +367,17 @@ async function codeV5(targetPath) {
|
|
|
215
367
|
}
|
|
216
368
|
|
|
217
369
|
if (reply.tool_calls && reply.tool_calls.length > 0) {
|
|
218
|
-
//
|
|
370
|
+
// v5.6.21: Akıllı onay - sadece riskli işlemlerde onay iste
|
|
219
371
|
let approved = true;
|
|
220
|
-
const dangerous = ["bash", "write_file", "edit_file", "mac_app_quit"];
|
|
221
372
|
for (const tc of reply.tool_calls) {
|
|
222
|
-
|
|
373
|
+
let args = {};
|
|
374
|
+
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
375
|
+
const risk = assessRisk(tc.function.name, args);
|
|
376
|
+
if (risk.requiresApproval) {
|
|
223
377
|
process.stdout.write("\n");
|
|
224
|
-
approved = await confirm(
|
|
378
|
+
approved = await confirm(
|
|
379
|
+
`⚠ ${tc.function.name}: ${risk.reason}\n Devam edilsin mi? (Y/n) `
|
|
380
|
+
);
|
|
225
381
|
if (!approved) break;
|
|
226
382
|
}
|
|
227
383
|
}
|
|
@@ -239,7 +395,8 @@ async function codeV5(targetPath) {
|
|
|
239
395
|
if (name === "bash" || name === "shell_command") commandsRun++;
|
|
240
396
|
if (name === "write_file" || name === "edit_file") filesChanged++;
|
|
241
397
|
const result = await executeTool(name, args, toolDefs);
|
|
242
|
-
|
|
398
|
+
// v5.6.21: Sonuç gizleme - sadece status goster, yol/size gizle
|
|
399
|
+
printToolCallSafe(name, args, result);
|
|
243
400
|
const out = result.error
|
|
244
401
|
? "ERROR: " + result.error
|
|
245
402
|
: (typeof result.result === "string" ? result.result : JSON.stringify(result.result));
|
package/src/commands/repl.js
CHANGED
|
@@ -886,7 +886,14 @@ async function startRepl(args) {
|
|
|
886
886
|
const resultStr = typeof toolEvent.result.result === 'string'
|
|
887
887
|
? toolEvent.result.result.slice(0, 200)
|
|
888
888
|
: JSON.stringify(toolEvent.result.result).slice(0, 200);
|
|
889
|
-
|
|
889
|
+
// v5.6.21: Yol gizleme
|
|
890
|
+
const cleanResult = (resultStr || '')
|
|
891
|
+
.replace(/\/?Users\/[^"\s]+/g, '~')
|
|
892
|
+
.replace(/\/?home\/[^"\s]+/g, '~')
|
|
893
|
+
.replace(/"size":\d+/g, '')
|
|
894
|
+
.replace(/"path":"[^"]*"/g, '')
|
|
895
|
+
.replace(/"fileCount":\d+/g, '');
|
|
896
|
+
console.log(tui.styled(' ✓ Sonuç: ' + cleanResult.trim(), { color: tui.PALETTE.success }));
|
|
890
897
|
}
|
|
891
898
|
process.stdout.write(tui.styled(' AI ', { color: tui.PALETTE.secondary, bold: true }));
|
|
892
899
|
}
|
package/src/tools/filesystem.js
CHANGED
package/src/tools/git.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = {
|
|
|
18
18
|
},
|
|
19
19
|
|
|
20
20
|
execute({ operation, args = '', message = '' }) {
|
|
21
|
-
|
|
21
|
+
// v5.6.22: Git repo otomatik bul - cwd'de yoksa ust dizinleri kontrol et
|
|
22
|
+
const cwd = this._findGitRepo();
|
|
22
23
|
try {
|
|
23
24
|
let cmd;
|
|
24
25
|
switch (operation) {
|
|
@@ -35,5 +36,55 @@ module.exports = {
|
|
|
35
36
|
} catch (err) {
|
|
36
37
|
return { success: false, error: err.stderr?.toString() || err.message };
|
|
37
38
|
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* v5.6.22: Git repo bul - cwd'de yoksa ~/Projects ve parent dizinleri tara
|
|
43
|
+
*/
|
|
44
|
+
_findGitRepo() {
|
|
45
|
+
const fs = require('fs');
|
|
46
|
+
const path = require('path');
|
|
47
|
+
const os = require('os');
|
|
48
|
+
const { execSync } = require('child_process');
|
|
49
|
+
|
|
50
|
+
// 1. Mevcut cwd'de .git var mi?
|
|
51
|
+
if (fs.existsSync(path.join(process.cwd(), '.git'))) {
|
|
52
|
+
return process.cwd();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Bilinen yaygin konumlari kontrol et
|
|
56
|
+
const home = os.homedir();
|
|
57
|
+
const candidates = [
|
|
58
|
+
path.join(home, 'Projects', 'natureco-cli'),
|
|
59
|
+
path.join(home, 'Projects'),
|
|
60
|
+
path.join(home, 'projects'),
|
|
61
|
+
path.join(home, 'code'),
|
|
62
|
+
path.join(home, 'dev'),
|
|
63
|
+
path.join(home, 'src'),
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
for (const dir of candidates) {
|
|
67
|
+
try {
|
|
68
|
+
if (fs.existsSync(path.join(dir, '.git'))) {
|
|
69
|
+
return dir;
|
|
70
|
+
}
|
|
71
|
+
} catch {}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 3. cwd'den yukarı dogru 5 seviye tara
|
|
75
|
+
let current = process.cwd();
|
|
76
|
+
for (let i = 0; i < 5; i++) {
|
|
77
|
+
const parent = path.dirname(current);
|
|
78
|
+
if (parent === current) break;
|
|
79
|
+
try {
|
|
80
|
+
if (fs.existsSync(path.join(parent, '.git'))) {
|
|
81
|
+
return parent;
|
|
82
|
+
}
|
|
83
|
+
} catch {}
|
|
84
|
+
current = parent;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 4. Bulamadi, cwd'yi don
|
|
88
|
+
return process.cwd();
|
|
38
89
|
}
|
|
39
90
|
};
|
package/src/tools/grep_search.js
CHANGED
|
@@ -19,7 +19,23 @@ const { spawn } = require('child_process');
|
|
|
19
19
|
async function grepSearch({ pattern, path: searchPath = null, caseSensitive = false, includePattern = null, maxResults = 50 }) {
|
|
20
20
|
if (!pattern) return { success: false, error: 'pattern gerekli' };
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// v5.6.22: ~ expansion fix
|
|
23
|
+
if (searchPath && searchPath.startsWith('~')) {
|
|
24
|
+
searchPath = path.join(require('os').homedir(), searchPath.slice(1));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// v5.6.22: Dosya yolu verildiyse, parent directory'yi kullan + filename pattern ekle
|
|
28
|
+
let cwd = searchPath || process.cwd();
|
|
29
|
+
if (searchPath && fs.existsSync(searchPath)) {
|
|
30
|
+
const stat = fs.statSync(searchPath);
|
|
31
|
+
if (stat.isFile()) {
|
|
32
|
+
// Dosya -> parent dir + includePattern
|
|
33
|
+
cwd = path.dirname(searchPath);
|
|
34
|
+
if (!includePattern) {
|
|
35
|
+
includePattern = path.basename(searchPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
23
39
|
// ripgrep varsa onu kullan, yoksa fallback grep
|
|
24
40
|
const useRipgrep = await checkCommand('rg');
|
|
25
41
|
|
|
@@ -43,9 +59,12 @@ async function grepWithRipgrep(pattern, cwd, caseSensitive, includePattern, maxR
|
|
|
43
59
|
'--json',
|
|
44
60
|
'--line-number',
|
|
45
61
|
caseSensitive ? '' : '--ignore-case',
|
|
46
|
-
includePattern ? `-g "${includePattern}"` : '',
|
|
47
62
|
'--no-heading',
|
|
48
63
|
].filter(Boolean);
|
|
64
|
+
// v5.6.22: includePattern'i -g ve glob olarak ayri ekle (tirnak hatasini onler)
|
|
65
|
+
if (includePattern) {
|
|
66
|
+
args.push('-g', includePattern);
|
|
67
|
+
}
|
|
49
68
|
args.push(pattern);
|
|
50
69
|
args.push(cwd);
|
|
51
70
|
|
|
@@ -55,7 +74,10 @@ async function grepWithRipgrep(pattern, cwd, caseSensitive, includePattern, maxR
|
|
|
55
74
|
proc.stdout.on('data', d => stdout += d.toString());
|
|
56
75
|
proc.stderr.on('data', d => stderr += d.toString());
|
|
57
76
|
|
|
58
|
-
|
|
77
|
+
let finished = false;
|
|
78
|
+
const finishOnce = () => {
|
|
79
|
+
if (finished) return;
|
|
80
|
+
finished = true;
|
|
59
81
|
const results = [];
|
|
60
82
|
const lines = stdout.split('\n').filter(Boolean);
|
|
61
83
|
for (const line of lines) {
|
|
@@ -72,7 +94,22 @@ async function grepWithRipgrep(pattern, cwd, caseSensitive, includePattern, maxR
|
|
|
72
94
|
} catch {}
|
|
73
95
|
}
|
|
74
96
|
resolve({ success: true, pattern, tool: 'ripgrep', count: results.length, results });
|
|
75
|
-
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// v5.6.22: Promise ile stream okuma (race condition fix)
|
|
100
|
+
let stderrClosed = false;
|
|
101
|
+
let stdoutClosed = false;
|
|
102
|
+
let exitCode = null;
|
|
103
|
+
const checkFinish = () => {
|
|
104
|
+
if ((stdoutClosed || stderrClosed) && exitCode !== null) {
|
|
105
|
+
setTimeout(finishOnce, 100);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
proc.stdout.on('data', d => stdout += d.toString());
|
|
109
|
+
proc.stderr.on('data', d => stderr += d.toString());
|
|
110
|
+
proc.stdout.on('end', () => { stdoutClosed = true; checkFinish(); });
|
|
111
|
+
proc.stderr.on('end', () => { stderrClosed = true; checkFinish(); });
|
|
112
|
+
proc.on('exit', (code) => { exitCode = code; checkFinish(); });
|
|
76
113
|
proc.on('error', (e) => resolve({ success: false, error: e.message }));
|
|
77
114
|
});
|
|
78
115
|
}
|
|
@@ -20,7 +20,17 @@ module.exports = {
|
|
|
20
20
|
try {
|
|
21
21
|
const config = getConfig();
|
|
22
22
|
const prompt = params.prompt || 'Describe this image in detail';
|
|
23
|
-
|
|
23
|
+
let provider = params.provider || config.visionProvider || 'openai';
|
|
24
|
+
|
|
25
|
+
// v5.6.22: MiniMax, Ollama, local provider'lar vision desteklemiyor olabilir
|
|
26
|
+
const providerUrl = (config.providerUrl || '').toLowerCase();
|
|
27
|
+
if (!params.provider && (providerUrl.includes('minimax') || providerUrl.includes('ollama') || providerUrl.includes('localhost'))) {
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
error: `Görsel analiz bu provider (${providerUrl}) için desteklenmiyor. Lütfen OpenAI, Anthropic, Gemini veya Groq provider'ı kullanın.`,
|
|
31
|
+
hint: 'natureco config set providerUrl https://api.openai.com/v1'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
24
34
|
|
|
25
35
|
if (!params.imagePath && !params.imageUrl) {
|
|
26
36
|
return { success: false, error: 'imagePath veya imageUrl gerekli' };
|
|
@@ -55,16 +55,24 @@ async function searchMemory({ query, scope = "all", username = null, maxResults
|
|
|
55
55
|
|
|
56
56
|
// Memory dosyalarini tara
|
|
57
57
|
if (scope === "all" || scope === "memory") {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
// v5.6.22: Username yoksa TÜM memory dosyalarini tara
|
|
59
|
+
const memoryDir = MEMORY_DIR;
|
|
60
|
+
if (fs.existsSync(memoryDir)) {
|
|
61
|
+
const memoryFiles = username
|
|
62
|
+
? [(username || "default") + ".json"]
|
|
63
|
+
: listFiles(memoryDir);
|
|
64
|
+
for (const fname of memoryFiles) {
|
|
65
|
+
const memoryFile = path.join(memoryDir, fname);
|
|
66
|
+
if (!fs.existsSync(memoryFile)) continue;
|
|
67
|
+
try {
|
|
68
|
+
const mem = JSON.parse(fs.readFileSync(memoryFile, "utf8"));
|
|
69
|
+
const matches = searchInObject(mem, q, "memory");
|
|
70
|
+
matches.forEach(m => {
|
|
71
|
+
results.push({ source: "memory:" + fname, ...m });
|
|
72
|
+
sources.push("memory");
|
|
73
|
+
});
|
|
74
|
+
} catch {}
|
|
75
|
+
}
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
|
package/src/tools/read_file.js
CHANGED
|
@@ -4,7 +4,7 @@ const os = require('os');
|
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
name: 'read_file',
|
|
7
|
-
description: 'Read content
|
|
7
|
+
description: 'PRIMARY TOOL: Read a specific file content. Use this when user wants to read/view/look at a single file. For listing directories use filesystem tool.',
|
|
8
8
|
inputSchema: {
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
package/src/tools/write_file.js
CHANGED
|
@@ -21,7 +21,12 @@ module.exports = {
|
|
|
21
21
|
|
|
22
22
|
async execute(params) {
|
|
23
23
|
try {
|
|
24
|
-
|
|
24
|
+
// v5.6.22: ~ expansion fix
|
|
25
|
+
let rawPath = params.path;
|
|
26
|
+
if (rawPath && rawPath.startsWith('~')) {
|
|
27
|
+
rawPath = path.join(require('os').homedir(), rawPath.slice(1));
|
|
28
|
+
}
|
|
29
|
+
const filePath = path.resolve(rawPath);
|
|
25
30
|
const dir = path.dirname(filePath);
|
|
26
31
|
|
|
27
32
|
// Create directory if it doesn't exist
|