natureco-cli 5.59.0 → 5.61.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/package.json +1 -1
- package/src/commands/audit.js +26 -24
- package/src/commands/code.js +95 -87
- package/src/commands/code_v5.js +58 -56
- package/src/commands/medium.js +32 -30
- package/src/commands/migrate.js +54 -52
- package/src/commands/naturehub.js +32 -30
- package/src/commands/policy.js +32 -30
- package/src/commands/security.js +24 -22
- package/src/commands/seo.js +43 -41
- package/src/commands/xp.js +42 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.61.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/audit.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const chalk = require('chalk');
|
|
15
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
16
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
15
17
|
const tui = require('../utils/tui');
|
|
16
18
|
const F = require('../utils/format');
|
|
17
19
|
const fs = require('fs');
|
|
@@ -53,11 +55,11 @@ function formatEntry(entry) {
|
|
|
53
55
|
|
|
54
56
|
function showEntries(entries, limit = 50) {
|
|
55
57
|
if (entries.length === 0) {
|
|
56
|
-
console.log(tui.C.muted('\n Kayıt yok.\n'));
|
|
58
|
+
console.log(tui.C.muted(L('\n Kayıt yok.\n', '\n No records.\n')));
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
const slice = entries.slice(-limit);
|
|
60
|
-
console.log(tui.styled(`\n 📋 ${entries.length} kayıt${limit < entries.length ? ` (son ${limit})` : ''}`, { color: tui.PALETTE.primary, bold: true }));
|
|
62
|
+
console.log(tui.styled(`\n 📋 ${entries.length} ${L('kayıt', 'records')}${limit < entries.length ? ` (${L('son', 'last')} ${limit})` : ''}`, { color: tui.PALETTE.primary, bold: true }));
|
|
61
63
|
|
|
62
64
|
// Yeni TUI tablo
|
|
63
65
|
const rows = slice.map(e => ({
|
|
@@ -69,9 +71,9 @@ function showEntries(entries, limit = 50) {
|
|
|
69
71
|
}));
|
|
70
72
|
|
|
71
73
|
console.log('\n' + tui.table(rows, [
|
|
72
|
-
{ key: 'ts', label: 'Saat', minWidth: 10, render: r => tui.C.muted(r.ts) },
|
|
74
|
+
{ key: 'ts', label: L('Saat', 'Time'), minWidth: 10, render: r => tui.C.muted(r.ts) },
|
|
73
75
|
{ key: 'action', label: 'Action', minWidth: 22, render: r => colorizeAction(r.action) },
|
|
74
|
-
{ key: 'data', label: 'Veri', minWidth: 30, render: r => tui.C.dim(r.data) },
|
|
76
|
+
{ key: 'data', label: L('Veri', 'Data'), minWidth: 30, render: r => tui.C.dim(r.data) },
|
|
75
77
|
], { borderStyle: 'round', zebra: true }));
|
|
76
78
|
console.log('');
|
|
77
79
|
}
|
|
@@ -88,10 +90,10 @@ function audit_cmd(args) {
|
|
|
88
90
|
|
|
89
91
|
if (action === 'stats') {
|
|
90
92
|
const stats = audit.stats24h();
|
|
91
|
-
console.log('\n' + tui.styled(' 📊 Son 24 Saat Audit İstatistiği', { color: tui.PALETTE.primary, bold: true }));
|
|
93
|
+
console.log('\n' + tui.styled(L(' 📊 Son 24 Saat Audit İstatistiği', ' 📊 Last 24h Audit Stats'), { color: tui.PALETTE.primary, bold: true }));
|
|
92
94
|
console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
|
|
93
|
-
console.log('\n ' + tui.C.muted('Dönem: ') + tui.C.text(stats.period));
|
|
94
|
-
console.log(' ' + tui.C.muted('Toplam kayıt: ') + tui.styled(String(stats.total), { color: tui.PALETTE.primary, bold: true }));
|
|
95
|
+
console.log('\n ' + tui.C.muted(L('Dönem: ', 'Period: ')) + tui.C.text(stats.period));
|
|
96
|
+
console.log(' ' + tui.C.muted(L('Toplam kayıt: ', 'Total records: ')) + tui.styled(String(stats.total), { color: tui.PALETTE.primary, bold: true }));
|
|
95
97
|
console.log('');
|
|
96
98
|
|
|
97
99
|
// TUI tablo ile
|
|
@@ -106,8 +108,8 @@ function audit_cmd(args) {
|
|
|
106
108
|
if (rows.length > 0) {
|
|
107
109
|
console.log(tui.table(rows, [
|
|
108
110
|
{ key: 'action', label: 'Action', minWidth: 22, render: r => colorizeAction(r.action) },
|
|
109
|
-
{ key: 'count', label: 'Sayı', minWidth: 6, render: r => tui.styled(r.count, { color: tui.PALETTE.secondary, bold: true }) },
|
|
110
|
-
{ key: 'bar', label: 'Dağılım', minWidth: 22, render: r => tui.styled(r.bar, { color: tui.PALETTE.primary }) },
|
|
111
|
+
{ key: 'count', label: L('Sayı', 'Count'), minWidth: 6, render: r => tui.styled(r.count, { color: tui.PALETTE.secondary, bold: true }) },
|
|
112
|
+
{ key: 'bar', label: L('Dağılım', 'Distribution'), minWidth: 22, render: r => tui.styled(r.bar, { color: tui.PALETTE.primary }) },
|
|
111
113
|
], { borderStyle: 'round', zebra: true }));
|
|
112
114
|
}
|
|
113
115
|
console.log('');
|
|
@@ -118,7 +120,7 @@ function audit_cmd(args) {
|
|
|
118
120
|
const date = params[0] || new Date().toISOString().slice(0, 10);
|
|
119
121
|
const entries = audit.readLog(date);
|
|
120
122
|
if (entries.length === 0) {
|
|
121
|
-
console.log(chalk.yellow(`\n ⚠️ ${date} için kayıt yok
|
|
123
|
+
console.log(chalk.yellow(`\n ⚠️ ${date} ${L('için kayıt yok.', '— no records.')}\n`));
|
|
122
124
|
return;
|
|
123
125
|
}
|
|
124
126
|
showEntries(entries, 9999);
|
|
@@ -127,18 +129,18 @@ function audit_cmd(args) {
|
|
|
127
129
|
|
|
128
130
|
if (action === 'cleanup') {
|
|
129
131
|
const removed = audit.cleanup();
|
|
130
|
-
console.log(chalk.green(`\n ✓ ${removed} eski log dosyası temizlendi (30 gün+)
|
|
132
|
+
console.log(chalk.green(`\n ✓ ${removed} ${L('eski log dosyası temizlendi (30 gün+).', 'old log files cleaned (30 days+).')}\n`));
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
if (action === 'tail') {
|
|
135
|
-
console.log(chalk.cyan('\n 📡 Canlı audit log (Ctrl+C ile çık)...\n'));
|
|
137
|
+
console.log(chalk.cyan(L('\n 📡 Canlı audit log (Ctrl+C ile çık)...\n', '\n 📡 Live audit log (Ctrl+C to exit)...\n')));
|
|
136
138
|
let lastSize = 0;
|
|
137
139
|
const todayFile = audit.listLogFiles()[0];
|
|
138
140
|
const interval = setInterval(() => {
|
|
139
141
|
const current = audit.listLogFiles()[0];
|
|
140
142
|
if (current !== todayFile) {
|
|
141
|
-
console.log(chalk.gray(`\n ── yeni gün: ${current} ──`));
|
|
143
|
+
console.log(chalk.gray(`\n ── ${L('yeni gün', 'new day')}: ${current} ──`));
|
|
142
144
|
}
|
|
143
145
|
const file = path.join(audit.AUDIT_DIR, audit.listLogFiles()[0]);
|
|
144
146
|
try {
|
|
@@ -167,7 +169,7 @@ function audit_cmd(args) {
|
|
|
167
169
|
if (action === 'search') {
|
|
168
170
|
const query = params.join(' ').toLowerCase();
|
|
169
171
|
if (!query) {
|
|
170
|
-
console.log(chalk.red('\n ❌ Arama terimi gerekli: natureco audit search <query>\n'));
|
|
172
|
+
console.log(chalk.red(L('\n ❌ Arama terimi gerekli: natureco audit search <query>\n', '\n ❌ Search term required: natureco audit search <query>\n')));
|
|
171
173
|
return;
|
|
172
174
|
}
|
|
173
175
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -183,7 +185,7 @@ function audit_cmd(args) {
|
|
|
183
185
|
|
|
184
186
|
if (action === 'files') {
|
|
185
187
|
const files = audit.listLogFiles();
|
|
186
|
-
console.log(chalk.bold('\n 📁 Audit log dosyaları:\n'));
|
|
188
|
+
console.log(chalk.bold(L('\n 📁 Audit log dosyaları:\n', '\n 📁 Audit log files:\n')));
|
|
187
189
|
for (const f of files) {
|
|
188
190
|
const stat = fs.statSync(path.join(audit.AUDIT_DIR, f));
|
|
189
191
|
const size = (stat.size / 1024).toFixed(1);
|
|
@@ -194,15 +196,15 @@ function audit_cmd(args) {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
// Yardım
|
|
197
|
-
console.log(chalk.yellow('\n Kullanım:'));
|
|
198
|
-
console.log(chalk.gray(' natureco audit Bugünkü logları göster'));
|
|
199
|
-
console.log(chalk.gray(' natureco audit today Bugünkü tüm loglar'));
|
|
200
|
-
console.log(chalk.gray(' natureco audit stats 24 saat istatistik'));
|
|
201
|
-
console.log(chalk.gray(' natureco audit show <date> Belirli gün (YYYY-MM-DD)'));
|
|
202
|
-
console.log(chalk.gray(' natureco audit search <q> Log ara'));
|
|
203
|
-
console.log(chalk.gray(' natureco audit files Dosya listesi'));
|
|
204
|
-
console.log(chalk.gray(' natureco audit cleanup 30 günden eski logları sil'));
|
|
205
|
-
console.log(chalk.gray(' natureco audit tail Canlı akış'));
|
|
199
|
+
console.log(chalk.yellow(L('\n Kullanım:', '\n Usage:')));
|
|
200
|
+
console.log(chalk.gray(L(' natureco audit Bugünkü logları göster', ' natureco audit Show today\'s logs')));
|
|
201
|
+
console.log(chalk.gray(L(' natureco audit today Bugünkü tüm loglar', ' natureco audit today All of today\'s logs')));
|
|
202
|
+
console.log(chalk.gray(L(' natureco audit stats 24 saat istatistik', ' natureco audit stats 24-hour stats')));
|
|
203
|
+
console.log(chalk.gray(L(' natureco audit show <date> Belirli gün (YYYY-MM-DD)', ' natureco audit show <date> Specific day (YYYY-MM-DD)')));
|
|
204
|
+
console.log(chalk.gray(L(' natureco audit search <q> Log ara', ' natureco audit search <q> Search logs')));
|
|
205
|
+
console.log(chalk.gray(L(' natureco audit files Dosya listesi', ' natureco audit files File list')));
|
|
206
|
+
console.log(chalk.gray(L(' natureco audit cleanup 30 günden eski logları sil', ' natureco audit cleanup Delete logs older than 30 days')));
|
|
207
|
+
console.log(chalk.gray(L(' natureco audit tail Canlı akış', ' natureco audit tail Live stream')));
|
|
206
208
|
console.log('');
|
|
207
209
|
}
|
|
208
210
|
|
package/src/commands/code.js
CHANGED
|
@@ -6,6 +6,8 @@ const { execSync } = require('child_process');
|
|
|
6
6
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
7
7
|
const TB = require('../utils/token-budget');
|
|
8
8
|
const chalk = require('chalk');
|
|
9
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
10
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
9
11
|
const { getApiKey, getConfig } = require('../utils/config');
|
|
10
12
|
const { getBots, getProviderConfig, startMcpServers, sendMessageOpenAICompatible, streamProviderCompletion } = require('../utils/api');
|
|
11
13
|
const { getMemoryPrompt, loadMemory } = require('../utils/memory');
|
|
@@ -18,9 +20,9 @@ let rl = null;
|
|
|
18
20
|
|
|
19
21
|
async function confirmAction(message) {
|
|
20
22
|
return new Promise(resolve => {
|
|
21
|
-
rl.question(chalk.yellow(`⚠ ${message}\n[? Devam edilsin mi? (Y/n) `), answer => {
|
|
23
|
+
rl.question(chalk.yellow(`⚠ ${message}\n[? ${L('Devam edilsin mi', 'Continue')}? (Y/n) `), answer => {
|
|
22
24
|
const confirmed = !answer || answer.toLowerCase() === 'y';
|
|
23
|
-
console.log(chalk.gray(` ✓ Devam edilsin mi? ${confirmed ? 'Yes' : 'No'}`));
|
|
25
|
+
console.log(chalk.gray(` ✓ ${L('Devam edilsin mi', 'Continue')}? ${confirmed ? 'Yes' : 'No'}`));
|
|
24
26
|
resolve(confirmed);
|
|
25
27
|
});
|
|
26
28
|
});
|
|
@@ -169,24 +171,24 @@ function loadProjectMemory(workDir) {
|
|
|
169
171
|
|
|
170
172
|
async function generateSummary(messages, providerConfig) {
|
|
171
173
|
const recent = messages.filter(m => m.role !== 'system').slice(-12);
|
|
172
|
-
if (!recent.length) return 'Bu session boş geçti.';
|
|
173
|
-
const prompt =
|
|
174
|
+
if (!recent.length) return L('Bu session boş geçti.', 'This session was empty.');
|
|
175
|
+
const prompt = `${L("Bu kod session'ını 3-5 madde halinde Türkçe özetle. Ne yapıldı, hangi dosyalar değiştirildi, hangi sorunlar çözüldü", 'Summarize this code session in 3-5 bullet points in English. What was done, which files changed, which issues were solved')}:\n${JSON.stringify(recent).slice(0, 3000)}`;
|
|
174
176
|
try {
|
|
175
177
|
const result = await sendMessageOpenAICompatible(providerConfig, [{ role: 'user', content: prompt }], []);
|
|
176
|
-
return result.content || 'Özet oluşturulamadı.';
|
|
178
|
+
return result.content || L('Özet oluşturulamadı.', 'Could not generate summary.');
|
|
177
179
|
} catch {
|
|
178
|
-
return 'Özet oluşturulamadı.';
|
|
180
|
+
return L('Özet oluşturulamadı.', 'Could not generate summary.');
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
async function saveProjectMemory(messages, providerConfig, workDir) {
|
|
183
|
-
const sp = startSpinner('Proje hafızası güncelleniyor...');
|
|
185
|
+
const sp = startSpinner(L('Proje hafızası güncelleniyor...', 'Updating project memory...'));
|
|
184
186
|
const summary = await generateSummary(messages, providerConfig);
|
|
185
|
-
stopSpinner(sp, 'Proje hafızası güncellendi', true);
|
|
187
|
+
stopSpinner(sp, L('Proje hafızası güncellendi', 'Project memory updated'), true);
|
|
186
188
|
const memPath = getProjectMemoryPath(workDir);
|
|
187
189
|
const dir = path.dirname(memPath);
|
|
188
190
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
189
|
-
const existing = fs.existsSync(memPath) ? fs.readFileSync(memPath, 'utf8') : '# Proje Hafızası\n';
|
|
191
|
+
const existing = fs.existsSync(memPath) ? fs.readFileSync(memPath, 'utf8') : L('# Proje Hafızası\n', '# Project Memory\n');
|
|
190
192
|
const entry = `\n## ${new Date().toLocaleDateString('tr-TR')} — ${new Date().toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' })}\n${summary}\n`;
|
|
191
193
|
fs.writeFileSync(memPath, existing + entry);
|
|
192
194
|
}
|
|
@@ -195,8 +197,8 @@ async function saveProjectMemory(messages, providerConfig, workDir) {
|
|
|
195
197
|
async function generateCommitMessage(diff, providerConfig) {
|
|
196
198
|
try {
|
|
197
199
|
const result = await sendMessageOpenAICompatible(providerConfig, [
|
|
198
|
-
{ role: 'system', content: 'Sen bir git commit mesajı üreticisin. Conventional Commits formatında (feat/fix/refactor/chore vb.) kısa ve açıklayıcı bir commit mesajı yaz. Sadece mesajı yaz, başka hiçbir şey yazma.' },
|
|
199
|
-
{ role: 'user', content:
|
|
200
|
+
{ role: 'system', content: L('Sen bir git commit mesajı üreticisin. Conventional Commits formatında (feat/fix/refactor/chore vb.) kısa ve açıklayıcı bir commit mesajı yaz. Sadece mesajı yaz, başka hiçbir şey yazma.', 'You are a git commit message generator. Write a short, descriptive commit message in Conventional Commits format (feat/fix/refactor/chore etc.). Write only the message, nothing else.') },
|
|
201
|
+
{ role: 'user', content: `${L('Bu diff için commit mesajı üret', 'Generate a commit message for this diff')}:\n\n${diff}` },
|
|
200
202
|
], []);
|
|
201
203
|
return (result.content || 'chore: update files').trim().replace(/^["']|["']$/g, '');
|
|
202
204
|
} catch {
|
|
@@ -243,19 +245,19 @@ async function runToolCall(toolCall, stats, dryRun = false) {
|
|
|
243
245
|
oldLines.forEach(line => {
|
|
244
246
|
if (line && !newLines.includes(line)) console.log(chalk.red(' - ' + line));
|
|
245
247
|
});
|
|
246
|
-
console.log(chalk.yellow('\n ⚠️ DRY RUN — dosya değiştirilmedi\n'));
|
|
248
|
+
console.log(chalk.yellow(L('\n ⚠️ DRY RUN — dosya değiştirilmedi\n', '\n ⚠️ DRY RUN — no file changed\n')));
|
|
247
249
|
stats.filesChanged++;
|
|
248
250
|
stats.changedFiles.push(toolCall.input.path || '?');
|
|
249
251
|
stats.toolCallCount++;
|
|
250
|
-
return { success: true, output: '[DRY RUN] Değişiklik gösterildi, uygulanmadı' };
|
|
252
|
+
return { success: true, output: L('[DRY RUN] Değişiklik gösterildi, uygulanmadı', '[DRY RUN] Change shown, not applied') };
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
if (needsConfirm) {
|
|
254
256
|
console.log(chalk.yellow(`\n ⚠️ ${toolCall.name}: ${inputPreview}`));
|
|
255
|
-
const ok = await confirmAction('Devam edilsin mi?');
|
|
257
|
+
const ok = await confirmAction(L('Devam edilsin mi?', 'Continue?'));
|
|
256
258
|
if (!ok) {
|
|
257
|
-
console.log(chalk.gray(' İptal edildi.\n'));
|
|
258
|
-
return { success: false, output: 'Kullanıcı iptal etti.' };
|
|
259
|
+
console.log(chalk.gray(L(' İptal edildi.\n', ' Cancelled.\n')));
|
|
260
|
+
return { success: false, output: L('Kullanıcı iptal etti.', 'User cancelled.') };
|
|
259
261
|
}
|
|
260
262
|
}
|
|
261
263
|
|
|
@@ -267,9 +269,9 @@ async function runToolCall(toolCall, stats, dryRun = false) {
|
|
|
267
269
|
if (toolCall.name === 'write_file') {
|
|
268
270
|
stats.filesChanged++;
|
|
269
271
|
stats.changedFiles.push(toolCall.input.path || '?');
|
|
270
|
-
console.log(chalk.green(` ✓ ${toolCall.input.path} güncellendi`));
|
|
272
|
+
console.log(chalk.green(` ✓ ${toolCall.input.path} ${L('güncellendi', 'updated')}`));
|
|
271
273
|
if (stats.changedFiles.length === 1) {
|
|
272
|
-
console.log(chalk.gray(` 💡 git add . && /commit ile kaydet`));
|
|
274
|
+
console.log(chalk.gray(` 💡 git add . && /commit ${L('ile kaydet', 'to save')}`));
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
if (toolCall.name === 'bash') stats.commandsRun++;
|
|
@@ -284,24 +286,24 @@ async function runTests(projectIndex, conversationMessages, tools, providerConfi
|
|
|
284
286
|
const testScript = projectIndex.packageJson?.scripts?.test;
|
|
285
287
|
if (!testScript || testScript.includes('no test')) return;
|
|
286
288
|
|
|
287
|
-
const confirmed = await confirmAction('🧪 Testleri çalıştıralım mı?');
|
|
289
|
+
const confirmed = await confirmAction(L('🧪 Testleri çalıştıralım mı?', '🧪 Run the tests?'));
|
|
288
290
|
if (!confirmed) return;
|
|
289
291
|
|
|
290
|
-
console.log(chalk.gray('\n npm test çalışıyor...\n'));
|
|
292
|
+
console.log(chalk.gray(L('\n npm test çalışıyor...\n', '\n npm test running...\n')));
|
|
291
293
|
try {
|
|
292
294
|
const output = execSync('npm test', {
|
|
293
295
|
cwd: workDir, timeout: 30000, stdio: 'pipe',
|
|
294
296
|
}).toString();
|
|
295
|
-
console.log(chalk.green(' ✅ Testler geçti!\n'));
|
|
297
|
+
console.log(chalk.green(L(' ✅ Testler geçti!\n', ' ✅ Tests passed!\n')));
|
|
296
298
|
} catch (err) {
|
|
297
299
|
const errOutput = (err.stdout?.toString() || err.message || '').slice(0, 500);
|
|
298
|
-
console.log(chalk.red(' ❌ Test hatası:\n'));
|
|
300
|
+
console.log(chalk.red(L(' ❌ Test hatası:\n', ' ❌ Test error:\n')));
|
|
299
301
|
console.log(chalk.gray(' ' + errOutput.split('\n').join('\n ')));
|
|
300
302
|
console.log();
|
|
301
303
|
|
|
302
|
-
const fix = await confirmAction('Agent test hatasını düzeltsin mi?');
|
|
304
|
+
const fix = await confirmAction(L('Agent test hatasını düzeltsin mi?', 'Let the agent fix the test error?'));
|
|
303
305
|
if (fix) {
|
|
304
|
-
return
|
|
306
|
+
return `${L('Test hatası oluştu', 'A test error occurred')}:\n${errOutput}\n${L('Bu hatayı düzelt.', 'Fix this error.')}`;
|
|
305
307
|
}
|
|
306
308
|
}
|
|
307
309
|
return null;
|
|
@@ -335,7 +337,7 @@ async function code(targetFile, options = {}) {
|
|
|
335
337
|
if (!bot) {
|
|
336
338
|
process.stdin.resume();
|
|
337
339
|
const { selectedBot } = await inquirer.prompt([{
|
|
338
|
-
type: 'list', name: 'selectedBot', message: 'Bot seçin:',
|
|
340
|
+
type: 'list', name: 'selectedBot', message: L('Bot seçin:', 'Select bot:'),
|
|
339
341
|
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
340
342
|
}]);
|
|
341
343
|
bot = botList.bots.find(b => b.id === selectedBot);
|
|
@@ -347,29 +349,35 @@ async function code(targetFile, options = {}) {
|
|
|
347
349
|
const providerConfig = getProviderConfig();
|
|
348
350
|
|
|
349
351
|
if (!providerConfig) {
|
|
350
|
-
console.log(chalk.red('\n❌ Provider yapılandırılmamış. natureco config set providerUrl ...\n'));
|
|
352
|
+
console.log(chalk.red(L('\n❌ Provider yapılandırılmamış. natureco config set providerUrl ...\n', '\n❌ Provider not configured. natureco config set providerUrl ...\n')));
|
|
351
353
|
process.exit(1);
|
|
352
354
|
}
|
|
353
355
|
|
|
354
356
|
const shortModel = providerConfig.model.split('/').pop().split('-').slice(0, 3).join('-');
|
|
355
357
|
|
|
356
358
|
// ── Proje indexing ───────────────────────────────────────────────────────────
|
|
357
|
-
const indexSpinner = startSpinner('Proje indexleniyor...');
|
|
359
|
+
const indexSpinner = startSpinner(L('Proje indexleniyor...', 'Indexing project...'));
|
|
358
360
|
const projectIndex = await indexProject(workDir);
|
|
359
|
-
stopSpinner(indexSpinner, `${projectIndex.type.toUpperCase()} projesi — ${projectIndex.files.length} dosya`, true);
|
|
361
|
+
stopSpinner(indexSpinner, `${projectIndex.type.toUpperCase()} ${L('projesi', 'project')} — ${projectIndex.files.length} ${L('dosya', 'files')}`, true);
|
|
360
362
|
|
|
361
363
|
// ── Sistem prompt ────────────────────────────────────────────────────────────
|
|
362
364
|
const agentsPrompt = getAgentsPrompt();
|
|
363
365
|
const memoryPrompt = getMemoryPrompt(bot.id);
|
|
364
366
|
const indexPrompt = buildIndexPrompt(projectIndex);
|
|
365
367
|
|
|
366
|
-
let systemPrompt = `
|
|
368
|
+
let systemPrompt = (_gl() === 'en' ? `You are the NatureCo Code Agent — a powerful AI coding assistant.
|
|
369
|
+
Actually work in the user's project: read files, change them, run commands.
|
|
370
|
+
ALWAYS explain every step in English. Say what you'll do before making changes.
|
|
371
|
+
Catch and fix errors. Give a summary when done.
|
|
372
|
+
User: ${userName}
|
|
373
|
+
|
|
374
|
+
${indexPrompt}` : `Sen NatureCo Code Agent'sın — güçlü bir AI coding asistanı.
|
|
367
375
|
Kullanıcının projesinde gerçekten çalış: dosyaları oku, değiştir, komutları çalıştır.
|
|
368
376
|
Her adımı Türkçe açıkla. Değişiklik yapmadan önce ne yapacağını söyle.
|
|
369
377
|
Hataları yakala ve düzelt. İş bitince özet sun.
|
|
370
378
|
Kullanıcı: ${userName}
|
|
371
379
|
|
|
372
|
-
${indexPrompt}
|
|
380
|
+
${indexPrompt}`);
|
|
373
381
|
|
|
374
382
|
if (agentsPrompt) systemPrompt += `\n\n## Project Instructions\n${agentsPrompt}`;
|
|
375
383
|
if (memoryPrompt) systemPrompt += '\n\n' + memoryPrompt;
|
|
@@ -384,9 +392,9 @@ ${indexPrompt}`;
|
|
|
384
392
|
if (targetFile) {
|
|
385
393
|
try {
|
|
386
394
|
const content = fs.readFileSync(path.resolve(targetFile), 'utf-8');
|
|
387
|
-
systemPrompt += `\n\n## Odak
|
|
395
|
+
systemPrompt += `\n\n## ${L('Odak Dosyası', 'Focus File')}: ${targetFile}\n\`\`\`\n${TB.trimFileContent(content)}\n\`\`\``;
|
|
388
396
|
} catch {
|
|
389
|
-
console.log(chalk.yellow(` ⚠️ ${targetFile}
|
|
397
|
+
console.log(chalk.yellow(` ⚠️ ${targetFile} ${L('okunamadı', 'could not be read')}\n`));
|
|
390
398
|
}
|
|
391
399
|
}
|
|
392
400
|
|
|
@@ -422,16 +430,16 @@ ${indexPrompt}`;
|
|
|
422
430
|
].join('\n');
|
|
423
431
|
console.log(centerText(chalk.green(codeLogo)));
|
|
424
432
|
console.log();
|
|
425
|
-
console.log(centerText(chalk.cyan(`(\\_/) ${displayBotName} hazır`) + chalk.gray(` · v${version}`)));
|
|
433
|
+
console.log(centerText(chalk.cyan(`(\\_/) ${displayBotName} ${L('hazır', 'ready')}`) + chalk.gray(` · v${version}`)));
|
|
426
434
|
console.log(sep());
|
|
427
|
-
console.log(centerText(chalk.gray(`📁 ${projectIndex.type.toUpperCase()} projesi · ${projectIndex.files.length} dosya`)));
|
|
435
|
+
console.log(centerText(chalk.gray(`📁 ${projectIndex.type.toUpperCase()} ${L('projesi', 'project')} · ${projectIndex.files.length} ${L('dosya', 'files')}`)));
|
|
428
436
|
if (projectIndex.gitBranch) {
|
|
429
437
|
const changes = projectIndex.gitStatus?.length || 0;
|
|
430
|
-
console.log(centerText(chalk.gray(`🌿 ${projectIndex.gitBranch} · ${changes} değişiklik`)));
|
|
438
|
+
console.log(centerText(chalk.gray(`🌿 ${projectIndex.gitBranch} · ${changes} ${L('değişiklik', 'changes')}`)));
|
|
431
439
|
}
|
|
432
440
|
if (targetFile) console.log(centerText(chalk.gray(`📄 ${targetFile}`)));
|
|
433
|
-
if (projectMemory) console.log(centerText(chalk.gray(`📋 Proje hafızası yüklendi`)));
|
|
434
|
-
console.log(centerText(chalk.gray(`${shortModel} · /help · Ctrl+C
|
|
441
|
+
if (projectMemory) console.log(centerText(chalk.gray(`📋 ${L('Proje hafızası yüklendi', 'Project memory loaded')}`)));
|
|
442
|
+
console.log(centerText(chalk.gray(`${shortModel} · /help · Ctrl+C ${L('çıkış', 'exit')}`)));
|
|
435
443
|
console.log(sep());
|
|
436
444
|
console.log();
|
|
437
445
|
|
|
@@ -439,16 +447,16 @@ ${indexPrompt}`;
|
|
|
439
447
|
function showSummary() {
|
|
440
448
|
const w = process.stdout.columns || 120;
|
|
441
449
|
console.log(chalk.gray('\n' + '─'.repeat(w)));
|
|
442
|
-
console.log(chalk.gray(' Agent Session Özeti'));
|
|
443
|
-
if (options.dryRun) console.log(chalk.yellow(' ⚠️ DRY RUN — hiçbir dosya değiştirilmedi'));
|
|
450
|
+
console.log(chalk.gray(L(' Agent Session Özeti', ' Agent Session Summary')));
|
|
451
|
+
if (options.dryRun) console.log(chalk.yellow(L(' ⚠️ DRY RUN — hiçbir dosya değiştirilmedi', ' ⚠️ DRY RUN — no files changed')));
|
|
444
452
|
console.log(chalk.gray('─'.repeat(w)));
|
|
445
|
-
console.log(` ${chalk.green('✓')} ${stats.filesChanged} dosya değiştirildi`);
|
|
446
|
-
console.log(` ${chalk.green('✓')} ${stats.commandsRun} komut
|
|
447
|
-
console.log(` ${chalk.green('✓')} ${stats.toolCallCount} tool çağrısı
|
|
448
|
-
console.log(` ${chalk.cyan('◉')} ${stats.messageCount} mesaj`);
|
|
453
|
+
console.log(` ${chalk.green('✓')} ${stats.filesChanged} ${L('dosya değiştirildi', 'files changed')}`);
|
|
454
|
+
console.log(` ${chalk.green('✓')} ${stats.commandsRun} ${L('komut çalıştırıldı', 'commands run')}`);
|
|
455
|
+
console.log(` ${chalk.green('✓')} ${stats.toolCallCount} ${L('tool çağrısı yapıldı', 'tool calls made')}`);
|
|
456
|
+
console.log(` ${chalk.cyan('◉')} ${stats.messageCount} ${L('mesaj', 'messages')}`);
|
|
449
457
|
if (stats.changedFiles.length > 0) {
|
|
450
458
|
console.log();
|
|
451
|
-
console.log(chalk.cyan(` 📝 Değiştirilen dosyalar (${stats.changedFiles.length}):`));
|
|
459
|
+
console.log(chalk.cyan(` 📝 ${L('Değiştirilen dosyalar', 'Changed files')} (${stats.changedFiles.length}):`));
|
|
452
460
|
stats.changedFiles.forEach(f => console.log(chalk.white(` ${f}`)));
|
|
453
461
|
}
|
|
454
462
|
console.log(chalk.gray('─'.repeat(w)));
|
|
@@ -457,24 +465,24 @@ ${indexPrompt}`;
|
|
|
457
465
|
|
|
458
466
|
// ── Komut çalıştır + hata döngüsü ───────────────────────────────────────────
|
|
459
467
|
async function runAndFix(cmd) {
|
|
460
|
-
console.log(chalk.gray(`\n ▶ ${cmd} çalıştırılıyor
|
|
468
|
+
console.log(chalk.gray(`\n ▶ ${cmd} ${L('çalıştırılıyor...', 'running...')}\n`));
|
|
461
469
|
try {
|
|
462
470
|
const output = execSync(cmd, {
|
|
463
471
|
cwd: workDir, timeout: 30000, stdio: 'pipe',
|
|
464
472
|
}).toString();
|
|
465
|
-
console.log(chalk.green(' ✓ Başarılı:'));
|
|
473
|
+
console.log(chalk.green(L(' ✓ Başarılı:', ' ✓ Success:')));
|
|
466
474
|
console.log(chalk.gray(' ' + output.slice(0, 500).split('\n').join('\n ')));
|
|
467
475
|
console.log();
|
|
468
476
|
} catch (err) {
|
|
469
477
|
const errorOutput = (err.stderr?.toString() || err.stdout?.toString() || err.message || '').slice(0, 500);
|
|
470
|
-
console.log(chalk.red(' ✗ Hata:'));
|
|
478
|
+
console.log(chalk.red(L(' ✗ Hata:', ' ✗ Error:')));
|
|
471
479
|
console.log(chalk.gray(' ' + errorOutput.split('\n').join('\n ')));
|
|
472
480
|
console.log();
|
|
473
481
|
|
|
474
|
-
const fix = await confirmAction('Hatayı otomatik düzeltmemi ister misin?');
|
|
482
|
+
const fix = await confirmAction(L('Hatayı otomatik düzeltmemi ister misin?', 'Want me to auto-fix the error?'));
|
|
475
483
|
if (fix) {
|
|
476
|
-
const fixMessage =
|
|
477
|
-
console.log(chalk.cyan('\n Düzeltiliyor...\n'));
|
|
484
|
+
const fixMessage = `${L('Şu komut çalıştırıldı', 'This command was run')}: ${cmd}\n${L('Hata oluştu', 'An error occurred')}:\n${errorOutput}\n${L('Bu hatayı analiz et ve düzelt.', 'Analyze and fix this error.')}`;
|
|
485
|
+
console.log(chalk.cyan(L('\n Düzeltiliyor...\n', '\n Fixing...\n')));
|
|
478
486
|
await handleMessage(fixMessage);
|
|
479
487
|
}
|
|
480
488
|
}
|
|
@@ -489,20 +497,20 @@ ${indexPrompt}`;
|
|
|
489
497
|
const [cmd] = userMessage.slice(1).split(' ');
|
|
490
498
|
switch (cmd.toLowerCase()) {
|
|
491
499
|
case 'help':
|
|
492
|
-
console.log(chalk.yellow('Code Agent Komutları:'));
|
|
500
|
+
console.log(chalk.yellow(L('Code Agent Komutları:', 'Code Agent Commands:')));
|
|
493
501
|
[
|
|
494
|
-
['/clear', 'Ekranı temizle'],
|
|
495
|
-
['/summary', 'Session özetini göster ve kaydet'],
|
|
496
|
-
['/memory', 'Proje hafızasını göster'],
|
|
497
|
-
['/done', 'Bitir ve özet göster'],
|
|
498
|
-
['/index', 'Projeyi yeniden indexle'],
|
|
499
|
-
['/run <cmd>','Komutu çalıştır, hata varsa düzelt'],
|
|
500
|
-
['/test', 'Testleri çalıştır, hata varsa düzelt'],
|
|
501
|
-
['/git', 'Git durumu ve son commitler'],
|
|
502
|
-
['/commit', 'Staged değişiklikleri AI ile commit et'],
|
|
503
|
-
['/help', 'Bu yardım'],
|
|
502
|
+
['/clear', L('Ekranı temizle', 'Clear the screen')],
|
|
503
|
+
['/summary', L('Session özetini göster ve kaydet', 'Show and save session summary')],
|
|
504
|
+
['/memory', L('Proje hafızasını göster', 'Show project memory')],
|
|
505
|
+
['/done', L('Bitir ve özet göster', 'Finish and show summary')],
|
|
506
|
+
['/index', L('Projeyi yeniden indexle', 'Re-index the project')],
|
|
507
|
+
['/run <cmd>',L('Komutu çalıştır, hata varsa düzelt', 'Run command, fix errors if any')],
|
|
508
|
+
['/test', L('Testleri çalıştır, hata varsa düzelt', 'Run tests, fix errors if any')],
|
|
509
|
+
['/git', L('Git durumu ve son commitler', 'Git status and recent commits')],
|
|
510
|
+
['/commit', L('Staged değişiklikleri AI ile commit et', 'Commit staged changes with AI')],
|
|
511
|
+
['/help', L('Bu yardım', 'This help')],
|
|
504
512
|
].forEach(([c, d]) => console.log(' ' + chalk.cyan(c.padEnd(12)) + chalk.gray(d)));
|
|
505
|
-
console.log(chalk.gray(' Ctrl+C'.padEnd(14) + 'Çıkış'));
|
|
513
|
+
console.log(chalk.gray(' Ctrl+C'.padEnd(14) + L('Çıkış', 'Exit')));
|
|
506
514
|
console.log();
|
|
507
515
|
return;
|
|
508
516
|
case 'clear':
|
|
@@ -511,7 +519,7 @@ ${indexPrompt}`;
|
|
|
511
519
|
case 'summary':
|
|
512
520
|
case 'done': {
|
|
513
521
|
const sum = await generateSummary(conversationMessages, providerConfig);
|
|
514
|
-
console.log(chalk.yellow('\n 📝 Session Özeti:'));
|
|
522
|
+
console.log(chalk.yellow(L('\n 📝 Session Özeti:', '\n 📝 Session Summary:')));
|
|
515
523
|
console.log(chalk.white(' ' + sum.split('\n').join('\n ')));
|
|
516
524
|
console.log();
|
|
517
525
|
showSummary();
|
|
@@ -521,17 +529,17 @@ ${indexPrompt}`;
|
|
|
521
529
|
case 'memory': {
|
|
522
530
|
const mem = loadProjectMemory();
|
|
523
531
|
if (mem) {
|
|
524
|
-
console.log(chalk.yellow('\n 📋 Proje Hafızası:'));
|
|
532
|
+
console.log(chalk.yellow(L('\n 📋 Proje Hafızası:', '\n 📋 Project Memory:')));
|
|
525
533
|
console.log(chalk.gray(' ' + mem.slice(0, 1500).split('\n').join('\n ')));
|
|
526
534
|
} else {
|
|
527
|
-
console.log(chalk.gray('\n Henüz proje hafızası yok. /done ile kaydet.\n'));
|
|
535
|
+
console.log(chalk.gray(L('\n Henüz proje hafızası yok. /done ile kaydet.\n', '\n No project memory yet. Save with /done.\n')));
|
|
528
536
|
}
|
|
529
537
|
return;
|
|
530
538
|
}
|
|
531
539
|
case 'index': {
|
|
532
|
-
const sp = startSpinner('Proje yeniden indexleniyor...');
|
|
540
|
+
const sp = startSpinner(L('Proje yeniden indexleniyor...', 'Re-indexing project...'));
|
|
533
541
|
const newIndex = await indexProject(workDir);
|
|
534
|
-
stopSpinner(sp, `${newIndex.files.length} dosya indexlendi`, true);
|
|
542
|
+
stopSpinner(sp, `${newIndex.files.length} ${L('dosya indexlendi', 'files indexed')}`, true);
|
|
535
543
|
// Sistem prompt'u güncelle
|
|
536
544
|
conversationMessages[0].content = conversationMessages[0].content.replace(
|
|
537
545
|
/Proje Bilgisi:[\s\S]*?(?=\n\n|$)/,
|
|
@@ -549,7 +557,7 @@ ${indexPrompt}`;
|
|
|
549
557
|
? 'npm test'
|
|
550
558
|
: projectIndex.type === 'python' ? 'python -m pytest' : null;
|
|
551
559
|
if (!testCmd) {
|
|
552
|
-
console.log(chalk.red(' Test komutu bulunamadı.\n'));
|
|
560
|
+
console.log(chalk.red(L(' Test komutu bulunamadı.\n', ' Test command not found.\n')));
|
|
553
561
|
return;
|
|
554
562
|
}
|
|
555
563
|
await runAndFix(testCmd);
|
|
@@ -559,13 +567,13 @@ ${indexPrompt}`;
|
|
|
559
567
|
try {
|
|
560
568
|
const status = execSync('git status --short', { cwd: workDir, stdio: 'pipe' }).toString().trim();
|
|
561
569
|
const log = execSync('git log --oneline -5', { cwd: workDir, stdio: 'pipe' }).toString().trim();
|
|
562
|
-
console.log(chalk.yellow('\n Git Durumu:'));
|
|
563
|
-
console.log(status ? chalk.gray(' ' + status.split('\n').join('\n ')) : chalk.gray(' temiz'));
|
|
564
|
-
console.log(chalk.yellow('\n Son Commitler:'));
|
|
570
|
+
console.log(chalk.yellow(L('\n Git Durumu:', '\n Git Status:')));
|
|
571
|
+
console.log(status ? chalk.gray(' ' + status.split('\n').join('\n ')) : chalk.gray(L(' temiz', ' clean')));
|
|
572
|
+
console.log(chalk.yellow(L('\n Son Commitler:', '\n Recent Commits:')));
|
|
565
573
|
console.log(chalk.gray(' ' + log.split('\n').join('\n ')));
|
|
566
574
|
console.log();
|
|
567
575
|
} catch (e) {
|
|
568
|
-
console.log(chalk.red(' Git bulunamadı veya bu dizin bir git repo değil.\n'));
|
|
576
|
+
console.log(chalk.red(L(' Git bulunamadı veya bu dizin bir git repo değil.\n', ' Git not found or this is not a git repo.\n')));
|
|
569
577
|
}
|
|
570
578
|
return;
|
|
571
579
|
}
|
|
@@ -573,28 +581,28 @@ ${indexPrompt}`;
|
|
|
573
581
|
try {
|
|
574
582
|
const diff = execSync('git diff --staged', { cwd: workDir, stdio: 'pipe' }).toString();
|
|
575
583
|
if (!diff.trim()) {
|
|
576
|
-
console.log(chalk.red('\n Staged değişiklik yok.'));
|
|
577
|
-
console.log(chalk.gray(' Önce: git add .\n'));
|
|
584
|
+
console.log(chalk.red(L('\n Staged değişiklik yok.', '\n No staged changes.')));
|
|
585
|
+
console.log(chalk.gray(L(' Önce: git add .\n', ' First: git add .\n')));
|
|
578
586
|
return;
|
|
579
587
|
}
|
|
580
|
-
const sp = startSpinner('Commit mesajı üretiliyor...');
|
|
588
|
+
const sp = startSpinner(L('Commit mesajı üretiliyor...', 'Generating commit message...'));
|
|
581
589
|
const commitMsg = await generateCommitMessage(diff.slice(0, 2000), providerConfig);
|
|
582
|
-
stopSpinner(sp, 'Commit mesajı hazır', true);
|
|
583
|
-
console.log(chalk.cyan(`\n Önerilen: ${chalk.white(commitMsg)}\n`));
|
|
584
|
-
const ok = await confirmAction('Commit edilsin mi?');
|
|
590
|
+
stopSpinner(sp, L('Commit mesajı hazır', 'Commit message ready'), true);
|
|
591
|
+
console.log(chalk.cyan(`\n ${L('Önerilen', 'Suggested')}: ${chalk.white(commitMsg)}\n`));
|
|
592
|
+
const ok = await confirmAction(L('Commit edilsin mi?', 'Commit?'));
|
|
585
593
|
if (ok) {
|
|
586
594
|
execSync(`git commit -m "${commitMsg.replace(/"/g, '\\"')}"`, { cwd: workDir, stdio: 'pipe' });
|
|
587
|
-
console.log(chalk.green(' ✓ Commit yapıldı!\n'));
|
|
595
|
+
console.log(chalk.green(L(' ✓ Commit yapıldı!\n', ' ✓ Committed!\n')));
|
|
588
596
|
} else {
|
|
589
|
-
console.log(chalk.gray(' İptal edildi.\n'));
|
|
597
|
+
console.log(chalk.gray(L(' İptal edildi.\n', ' Cancelled.\n')));
|
|
590
598
|
}
|
|
591
599
|
} catch (e) {
|
|
592
|
-
console.log(chalk.red(` Git
|
|
600
|
+
console.log(chalk.red(` ${L('Git hatası', 'Git error')}: ${e.message}\n`));
|
|
593
601
|
}
|
|
594
602
|
return;
|
|
595
603
|
}
|
|
596
604
|
default:
|
|
597
|
-
console.log(chalk.red(
|
|
605
|
+
console.log(chalk.red(`${L('Bilinmeyen komut', 'Unknown command')}: /${cmd}\n`));
|
|
598
606
|
return;
|
|
599
607
|
}
|
|
600
608
|
}
|
|
@@ -638,19 +646,19 @@ ${indexPrompt}`;
|
|
|
638
646
|
|
|
639
647
|
if (!streamResult.toolCalls?.length) {
|
|
640
648
|
if (!streamResult.text) {
|
|
641
|
-
console.log(chalk.yellow('\n ⚠️ Model cevap vermedi, tekrar deneyin.\n'));
|
|
649
|
+
console.log(chalk.yellow(L('\n ⚠️ Model cevap vermedi, tekrar deneyin.\n', '\n ⚠️ Model did not respond, try again.\n')));
|
|
642
650
|
}
|
|
643
651
|
break;
|
|
644
652
|
}
|
|
645
653
|
|
|
646
|
-
console.log(chalk.yellow(`\n🔧 ${streamResult?.toolCalls?.length ?? 0} tool çalıştırılıyor
|
|
654
|
+
console.log(chalk.yellow(`\n🔧 ${streamResult?.toolCalls?.length ?? 0} ${L('tool çalıştırılıyor...', 'running tools...')}\n`));
|
|
647
655
|
|
|
648
656
|
for (let ti = 0; ti < streamResult.toolCalls.length; ti++) {
|
|
649
657
|
const toolCall = streamResult.toolCalls[ti];
|
|
650
658
|
const result = await runToolCall(toolCall, stats, options.dryRun);
|
|
651
659
|
const resultStr = result.success !== false
|
|
652
660
|
? (result.output || JSON.stringify(result))
|
|
653
|
-
:
|
|
661
|
+
: `${L('Hata', 'Error')}: ${result.error}`;
|
|
654
662
|
|
|
655
663
|
const matchedId = assistantMsg.tool_calls?.[ti]?.id || toolCall.id;
|
|
656
664
|
conversationMessages.push({
|
|
@@ -678,7 +686,7 @@ ${indexPrompt}`;
|
|
|
678
686
|
}
|
|
679
687
|
}
|
|
680
688
|
} catch (err) {
|
|
681
|
-
console.log(chalk.red(`\n ❌ Kayıt
|
|
689
|
+
console.log(chalk.red(`\n ❌ ${L('Kayıt hatası', 'Save error')}: ${err.message}\n`));
|
|
682
690
|
}
|
|
683
691
|
}
|
|
684
692
|
|
|
@@ -699,7 +707,7 @@ ${indexPrompt}`;
|
|
|
699
707
|
rl.pause();
|
|
700
708
|
if (conversationMessages.filter(m => m.role === 'user').length > 0) {
|
|
701
709
|
try {
|
|
702
|
-
const save = await confirmAction("Bu session'ı proje hafızasına kaydet?");
|
|
710
|
+
const save = await confirmAction(L("Bu session'ı proje hafızasına kaydet?", 'Save this session to project memory?'));
|
|
703
711
|
if (save) await saveProjectMemory(conversationMessages, providerConfig, workDir);
|
|
704
712
|
} catch {}
|
|
705
713
|
}
|