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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.59.0",
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"
@@ -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.\n`));
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+).\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
 
@@ -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 = `Bu kod session'ını 3-5 madde halinde Türkçe özetle. Ne yapıldı, hangi dosyalar değiştirildi, hangi sorunlar çözüldü:\n${JSON.stringify(recent).slice(0, 3000)}`;
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: `Bu diff için commit mesajı üret:\n\n${diff}` },
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 `Test hatası oluştu:\n${errOutput}\nBu hatayı düzelt.`;
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 = `Sen NatureCo Code Agent'sıngüçlü bir AI coding asistanı.
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 Dosyası: ${targetFile}\n\`\`\`\n${TB.trimFileContent(content)}\n\`\`\``;
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} okunamadı\n`));
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 çıkış`)));
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 çalıştırıldı`);
447
- console.log(` ${chalk.green('✓')} ${stats.toolCallCount} tool çağrısı yapıldı`);
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...\n`));
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 = `Şu komut çalıştırıldı: ${cmd}\nHata oluştu:\n${errorOutput}\nBu hatayı analiz et ve düzelt.`;
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 hatası: ${e.message}\n`));
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(`Bilinmeyen komut: /${cmd}\n`));
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...\n`));
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
- : `Hata: ${result.error}`;
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 hatası: ${err.message}\n`));
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
  }