natureco-cli 5.30.0 → 5.31.0
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/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/src/commands/repl.js +9 -3
- package/src/tools/agentic-runner.js +3 -1
- package/src/tools/workflow.js +26 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to NatureCo CLI will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [5.31.0] - 2026-07-04 — "CHAT/CODE ARAYÜZ ZENGİNLEŞTİRME (araç görünürlüğü + düşünme + input alanı)"
|
|
6
|
+
|
|
7
|
+
### ✨ Yeni (UX)
|
|
8
|
+
- **Araç görünürlugu**: agentic akista her arac ekranda gorunur — "🔧 <etiket> · <ozet> ✓/✗" (write_file/edit_file/bash/browser/mac_app_open...). Onceden streaming tool XML'ini gizlerken arac aktivitesi de gorunmuyordu; artik gorunur.
|
|
9
|
+
- **Düsünme gostergesi**: model yanit uretirken "💭 düşünüyor…", ilk token gelince temizlenir.
|
|
10
|
+
- **Gorunur input alani**: REPL prompt'u "💬 Sen ▸" + her girdiden once ince ayirici cizgi (cikti/girdi net ayrilir; readline tek-satir → satir duzenleme bozulmaz).
|
|
11
|
+
- **Gorunur acma yonlendirmesi (full mod)**: "kendi tarayicimda ac / dinlemek istiyorum" → headless `browser` yerine gorunur `open`/`start`/`mac_app_open` kullanilir.
|
|
12
|
+
|
|
13
|
+
Doğrulama: streaming UI E2E (💭 + 🔧 + ✓ gorunuyor); REPL regresyon; **492 test yeşil**.
|
|
14
|
+
|
|
5
15
|
## [5.30.0] - 2026-07-04 — "TAM KONTROL MODU (sahip opt-in: tüm araç+skill + computer-use)"
|
|
6
16
|
|
|
7
17
|
### ✨ Yeni
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.31.0",
|
|
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
|
@@ -1178,14 +1178,20 @@ async function startRepl(args) {
|
|
|
1178
1178
|
const rl = readline.createInterface({
|
|
1179
1179
|
input: createPasteSafeInput(process.stdin),
|
|
1180
1180
|
output: createOutputFilter(process.stdout),
|
|
1181
|
-
prompt: tui.styled('
|
|
1181
|
+
prompt: tui.styled(' 💬 Sen ▸ ', { color: tui.PALETTE.primary, bold: true }),
|
|
1182
1182
|
terminal: true,
|
|
1183
1183
|
});
|
|
1184
1184
|
// Pipe/script kullanımında EOF, yanıt hâlâ üretilirken gelir —
|
|
1185
1185
|
// aktif işlem varken kapanışı bekletmek için sayaç + kapalı-rl koruması
|
|
1186
1186
|
let _busy = 0;
|
|
1187
1187
|
let _rlClosed = false;
|
|
1188
|
-
|
|
1188
|
+
// Görünür input alanı: her prompttan önce ince ayırıcı çizgi (readline prompt'u tek-satır
|
|
1189
|
+
// kalir → satir duzenleme/gecmis bozulmaz). Cikti ile girdi arasini net ayirir.
|
|
1190
|
+
const safePrompt = () => {
|
|
1191
|
+
if (_rlClosed) return;
|
|
1192
|
+
try { process.stdout.write(tui.styled('\n ' + '─'.repeat(54) + '\n', { color: tui.PALETTE.muted })); } catch {}
|
|
1193
|
+
rl.prompt();
|
|
1194
|
+
};
|
|
1189
1195
|
safePrompt();
|
|
1190
1196
|
|
|
1191
1197
|
const cleanup = async (exitCode = 0) => {
|
|
@@ -1465,7 +1471,7 @@ async function startRepl(args) {
|
|
|
1465
1471
|
|
|
1466
1472
|
// Çok satırlı (paste) mesajları gönderildikten sonra ekranda göster
|
|
1467
1473
|
if (line.indexOf('\n') !== -1) {
|
|
1468
|
-
process.stdout.write(tui.styled('
|
|
1474
|
+
process.stdout.write(tui.styled(' 💬 Sen ▸ ', { color: tui.PALETTE.primary, bold: true }));
|
|
1469
1475
|
process.stdout.write(line + '\n');
|
|
1470
1476
|
}
|
|
1471
1477
|
|
|
@@ -326,7 +326,7 @@ async function executeCall(call, opts = {}) {
|
|
|
326
326
|
* callModel(messages) => Promise<{ content, toolCalls }>
|
|
327
327
|
* Donus: { records, reply, iterations }
|
|
328
328
|
*/
|
|
329
|
-
async function runAgentic({ callModel, systemPrompt, historyMessages, task, toolsDir, loadTool, allowed, execFull, maxIterations = 15 }) {
|
|
329
|
+
async function runAgentic({ callModel, systemPrompt, historyMessages, task, toolsDir, loadTool, allowed, execFull, onEvent, maxIterations = 15 }) {
|
|
330
330
|
const messages = [{ role: 'system', content: systemPrompt }];
|
|
331
331
|
for (const mm of historyMessages || []) messages.push({ role: mm.role, content: mm.content || '' });
|
|
332
332
|
messages.push({ role: 'user', content: task });
|
|
@@ -349,7 +349,9 @@ async function runAgentic({ callModel, systemPrompt, historyMessages, task, tool
|
|
|
349
349
|
messages.push({ role: 'assistant', content: content || '' });
|
|
350
350
|
const feedbacks = [];
|
|
351
351
|
for (const call of calls) {
|
|
352
|
+
if (onEvent) { try { onEvent({ phase: 'start', tool: call.tool, args: call.args }); } catch {} }
|
|
352
353
|
const { records, feedback } = await executeCall(call, { toolsDir, loadTool, allowed: allowedSet, execFull });
|
|
354
|
+
if (onEvent) { try { onEvent({ phase: 'end', tool: call.tool, args: call.args, records }); } catch {} }
|
|
353
355
|
allRecords.push(...records);
|
|
354
356
|
feedbacks.push(feedback);
|
|
355
357
|
}
|
package/src/tools/workflow.js
CHANGED
|
@@ -231,11 +231,11 @@ async function workflow(params) {
|
|
|
231
231
|
'\n\nTAM MOD ACIK — su araclara da ERISIMIN VAR; o an ne gerekiyorsa dogrudan cagir:',
|
|
232
232
|
'- mac_app_open: macOS uygulamasi ac. parametre: appName (orn. "WhatsApp", "Google Chrome", "Spotify")',
|
|
233
233
|
'- mac_app_quit: macOS uygulamasi kapat. parametre: appName',
|
|
234
|
-
'- browser: tarayici otomasyonu (
|
|
234
|
+
'- browser: HEADLESS tarayici otomasyonu (icerik cek/screenshot — kullaniciya GORUNMEZ). parametreler: action, url, script',
|
|
235
235
|
'- computer_use: GUI otomasyonu. parametreler: action ("screenshot"/"click"/"type"/"keypress"/"scroll"), x, y, text, key',
|
|
236
236
|
'- social_open: muzik/video/sosyal ac. parametreler: query, platform (spotify/youtube...)',
|
|
237
237
|
'- macos_screenshot: ekran goruntusu al',
|
|
238
|
-
'
|
|
238
|
+
'\nGORUNUR ACMA (onemli): Kullanici "kendi tarayicimda ac / gorunur ac / dinlemek/izlemek istiyorum" derse `browser` (headless, gorunmez) DEGIL, GORUNUR ac: macOS bash ile `open "https://..."` ya da `open -a "Google Chrome" "https://..."`; Windows `start "" "https://..."`. Uygulama icin `open -a WhatsApp` / mac_app_open. Muzik/video icin dogrudan YouTube/Spotify URL\'sini `open` ile ac.',
|
|
239
239
|
'\nTum arac listesi (isimle cagir; parametre yanlissa <tool_results> duzeltir): ' + allNames.join(', '),
|
|
240
240
|
].join('\n');
|
|
241
241
|
}
|
|
@@ -279,11 +279,14 @@ async function workflow(params) {
|
|
|
279
279
|
|
|
280
280
|
async function callModel(msgs) {
|
|
281
281
|
if (streamOn) {
|
|
282
|
-
|
|
282
|
+
let cleared = false;
|
|
283
|
+
const clearThinking = () => { if (!cleared) { process.stdout.write('\r\x1b[K'); cleared = true; } };
|
|
284
|
+
process.stdout.write('\x1b[2m 💭 düşünüyor…\x1b[0m');
|
|
285
|
+
const sani = makeSanitizeStream(botName, t => { clearThinking(); process.stdout.write(t); });
|
|
283
286
|
const filter = makeStreamFilter(t => sani.push(t), null);
|
|
284
287
|
const body = { model, stream: true, messages: msgs, temperature: 0.3, max_tokens: 16000 };
|
|
285
288
|
const out = await apiCallStream(providerUrl, providerApiKey, body, d => filter.push(d));
|
|
286
|
-
filter.end(); sani.end();
|
|
289
|
+
filter.end(); sani.end(); clearThinking();
|
|
287
290
|
return { content: out.content || '', toolCalls: out.toolCalls || [] };
|
|
288
291
|
}
|
|
289
292
|
const body = { model, stream: false, messages: msgs, temperature: 0.3, max_tokens: 16000 };
|
|
@@ -292,10 +295,28 @@ async function workflow(params) {
|
|
|
292
295
|
return { content: msg.content || '', toolCalls: msg.tool_calls || [] };
|
|
293
296
|
}
|
|
294
297
|
|
|
298
|
+
// Araç aktivitesi gösterimi (TTY streaming): her araç icin "🔧 label · hint ✓/✗"
|
|
299
|
+
const TOOL_LABEL = { write_file: 'dosya yaz', read_file: 'oku', edit_file: 'düzenle', bash: 'komut', file_search: 'ara', list_dir: 'listele', skill_view: 'skill', browser: 'tarayıcı', browser_use: 'tarayıcı', mac_app_open: 'uygulama aç', mac_app_quit: 'uygulama kapat', computer_use: 'GUI', social_open: 'medya aç', macos_screenshot: 'ekran görüntüsü' };
|
|
300
|
+
function briefHint(args) {
|
|
301
|
+
if (!args || typeof args !== 'object') return '';
|
|
302
|
+
const v = args.appName || args.query || args.name || args.url || args.command || args.pattern || args.path || args.action;
|
|
303
|
+
return v ? String(v).replace(/\s+/g, ' ').slice(0, 46) : '';
|
|
304
|
+
}
|
|
305
|
+
const onEvent = streamOn ? (ev) => {
|
|
306
|
+
if (ev.phase === 'start') {
|
|
307
|
+
const label = TOOL_LABEL[ev.tool] || ev.tool;
|
|
308
|
+
const hint = briefHint(ev.args);
|
|
309
|
+
process.stdout.write('\n\x1b[2m 🔧 ' + label + (hint ? ' · ' + hint : '') + '\x1b[0m');
|
|
310
|
+
} else {
|
|
311
|
+
const rec = (ev.records || [])[0] || {};
|
|
312
|
+
process.stdout.write(rec.status === 'done' ? ' \x1b[32m✓\x1b[0m' : ' \x1b[31m✗\x1b[0m');
|
|
313
|
+
}
|
|
314
|
+
} : null;
|
|
315
|
+
|
|
295
316
|
try {
|
|
296
317
|
const { records, reply } = await runAgentic({
|
|
297
318
|
callModel, systemPrompt: sysMsg, historyMessages, task,
|
|
298
|
-
toolsDir: __dirname, execFull, maxIterations: 15,
|
|
319
|
+
toolsDir: __dirname, execFull, onEvent, maxIterations: 15,
|
|
299
320
|
});
|
|
300
321
|
const fileWrites = records.filter(r => r.tool === 'write_file' && r.status === 'done');
|
|
301
322
|
let finalReply = reply || '';
|