natureco-cli 5.60.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.60.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
  }
@@ -18,6 +18,8 @@ const path = require("path");
18
18
  const os = require("os");
19
19
  const readline = require("readline");
20
20
  const chalk = require("chalk");
21
+ const { getLang: _gl } = require("../utils/i18n");
22
+ const L = (tr, en) => (_gl() === "en" ? en : tr);
21
23
  const tui = require("../utils/tui");
22
24
  const { getConfig } = require("../utils/config");
23
25
  const { loadToolDefinitions, executeTool, toOpenAIFormat } = require("../utils/tools");
@@ -56,7 +58,7 @@ async function apiRequest(url, key, body) {
56
58
  res.on("data", c => body += c);
57
59
  res.on("end", () => {
58
60
  if (res.statusCode === 200) {
59
- try { resolve(JSON.parse(body)); } catch (e) { reject(new Error("Parse hatasi")); }
61
+ try { resolve(JSON.parse(body)); } catch (e) { reject(new Error(L("Parse hatasi", "Parse error"))); }
60
62
  } else reject(new Error("HTTP " + res.statusCode + ": " + body.slice(0, 200)));
61
63
  });
62
64
  });
@@ -92,7 +94,7 @@ async function sendMessageWithTools(providerUrl, providerKey, model, messages, t
92
94
  } catch (err) {
93
95
  const fb = fallbackChain.recordError(body.model, err);
94
96
  if (fb.fallback) {
95
- console.log(tui.C.yellow(`\n ⚠ ${body.model} başarısız → ${fb.nextModel} deneniyor...\n`));
97
+ console.log(tui.C.yellow(`\n ⚠ ${body.model} ${L('başarısız', 'failed')} → ${fb.nextModel} ${L('deneniyor...', 'trying...')}\n`));
96
98
  return sendMessageWithTools(providerUrl, providerKey, fb.nextModel, messages, toolDefs);
97
99
  }
98
100
  throw err;
@@ -128,24 +130,24 @@ function assessRisk(tool, args) {
128
130
 
129
131
  // Dosya/klasör silme
130
132
  if (/\brm\s+(-[rf]+\s+)*/.test(cmd) || /rmdir/.test(cmd)) {
131
- return { requiresApproval: true, level: "high", reason: `Dosya silme komutu: ${args.command}` };
133
+ return { requiresApproval: true, level: "high", reason: `${L('Dosya silme komutu', 'File deletion command')}: ${args.command}` };
132
134
  }
133
135
  if (cmd.includes("sudo ") || cmd.includes("doas ")) {
134
- return { requiresApproval: true, level: "high", reason: `Yetki yükseltme: ${args.command}` };
136
+ return { requiresApproval: true, level: "high", reason: `${L('Yetki yükseltme', 'Privilege escalation')}: ${args.command}` };
135
137
  }
136
138
  if (cmd.includes("dd if=") || cmd.includes("mkfs") || cmd.includes("fdisk")) {
137
- return { requiresApproval: true, level: "high", reason: `Disk işlemi: ${args.command}` };
139
+ return { requiresApproval: true, level: "high", reason: `${L('Disk işlemi', 'Disk operation')}: ${args.command}` };
138
140
  }
139
141
  if (cmd.match(/^\s*mv\s+.*\/(?:\.|\.\.)/)) {
140
- return { requiresApproval: true, level: "medium", reason: `Üzerine yazma riski: ${args.command}` };
142
+ return { requiresApproval: true, level: "medium", reason: `${L('Üzerine yazma riski', 'Overwrite risk')}: ${args.command}` };
141
143
  }
142
144
  // chmod 777 veya chown -R
143
145
  if (/chmod\s+(-[rR]+\s+)*777/.test(cmd) || /chown\s+-R/.test(cmd)) {
144
- return { requiresApproval: true, level: "medium", reason: `İzin değişikliği: ${args.command}` };
146
+ return { requiresApproval: true, level: "medium", reason: `${L('İzin değişikliği', 'Permission change')}: ${args.command}` };
145
147
  }
146
148
  // git push --force
147
149
  if (/git\s+push.*--force/.test(cmd) || /git\s+push.*-f\s/.test(cmd)) {
148
- return { requiresApproval: true, level: "high", reason: `Zorla push: ${args.command}` };
150
+ return { requiresApproval: true, level: "high", reason: `${L('Zorla push', 'Force push')}: ${args.command}` };
149
151
  }
150
152
  // git reset --hard
151
153
  if (/git\s+reset\s+--hard/.test(cmd)) {
@@ -153,19 +155,19 @@ function assessRisk(tool, args) {
153
155
  }
154
156
  // Üretim/kök dizin
155
157
  if (cmd.includes("/etc/") || cmd.includes("/usr/") || cmd.includes("/var/") || cmd.includes("/System/")) {
156
- return { requiresApproval: true, level: "high", reason: `Sistem dizinine erişim: ${args.command}` };
158
+ return { requiresApproval: true, level: "high", reason: `${L('Sistem dizinine erişim', 'System directory access')}: ${args.command}` };
157
159
  }
158
160
  // curl/wget internet download
159
161
  if (/curl.*\|\s*(bash|sh)/.test(cmd) || /wget.*\|\s*(bash|sh)/.test(cmd)) {
160
- return { requiresApproval: true, level: "high", reason: `İnternet üzerinden script çalıştırma: ${args.command}` };
162
+ return { requiresApproval: true, level: "high", reason: `${L('İnternet üzerinden script çalıştırma', 'Running a script from the internet')}: ${args.command}` };
161
163
  }
162
164
  // mac_app_quit veya killall
163
165
  if (cmd.includes("killall") || cmd.includes("pkill") || cmd.includes("kill -9")) {
164
- return { requiresApproval: true, level: "high", reason: `Süreç sonlandırma: ${args.command}` };
166
+ return { requiresApproval: true, level: "high", reason: `${L('Süreç sonlandırma', 'Process termination')}: ${args.command}` };
165
167
  }
166
168
  // .natureco veya önemli dosyalara dokunma
167
169
  if (cmd.includes(".natureco") && (cmd.includes("rm") || cmd.includes("mv"))) {
168
- return { requiresApproval: true, level: "high", reason: `NatureCo dizininde tehlikeli işlem: ${args.command}` };
170
+ return { requiresApproval: true, level: "high", reason: `${L('NatureCo dizininde tehlikeli işlem', 'Dangerous operation in the NatureCo directory')}: ${args.command}` };
169
171
  }
170
172
  }
171
173
 
@@ -175,7 +177,7 @@ function assessRisk(tool, args) {
175
177
 
176
178
  // mac_app_quit - uygulama kapatma
177
179
  if (tool === "mac_app_quit") {
178
- return { requiresApproval: true, level: "medium", reason: `Uygulama kapatma: ${args.app || args.name || "?"}` };
180
+ return { requiresApproval: true, level: "medium", reason: `${L('Uygulama kapatma', 'App quit')}: ${args.app || args.name || "?"}` };
179
181
  }
180
182
 
181
183
  // write_file / edit_file - kritik yollara yazma
@@ -183,13 +185,13 @@ function assessRisk(tool, args) {
183
185
  const path = (args.path || args.file || "").toLowerCase();
184
186
  // Hassas dosyalar
185
187
  if (path.includes(".env") || path.includes("credentials") || path.includes("secret")) {
186
- return { requiresApproval: true, level: "high", reason: `Hassas dosya: ${args.path}` };
188
+ return { requiresApproval: true, level: "high", reason: `${L('Hassas dosya', 'Sensitive file')}: ${args.path}` };
187
189
  }
188
190
  if (path.includes("/etc/") || path.includes("/usr/") || path.includes("~/.ssh/")) {
189
- return { requiresApproval: true, level: "high", reason: `Sistem dosyası: ${args.path}` };
191
+ return { requiresApproval: true, level: "high", reason: `${L('Sistem dosyası', 'System file')}: ${args.path}` };
190
192
  }
191
193
  if (path.includes(".natureco/config.json") || path.includes(".natureco/soul/")) {
192
- return { requiresApproval: true, level: "medium", reason: `NatureCo config dosyası: ${args.path}` };
194
+ return { requiresApproval: true, level: "medium", reason: `${L('NatureCo config dosyası', 'NatureCo config file')}: ${args.path}` };
193
195
  }
194
196
  }
195
197
 
@@ -216,7 +218,7 @@ function printToolCallSafe(name, args, result) {
216
218
  // Result'tan sadece status goster, yol/size gizle
217
219
  if (!result) return;
218
220
  if (result.error) {
219
- console.log(tui.styled(" ✗ Hata: " + result.error.slice(0, 100), { color: tui.PALETTE.danger }));
221
+ console.log(tui.styled(L(" ✗ Hata: ", " ✗ Error: ") + result.error.slice(0, 100), { color: tui.PALETTE.danger }));
220
222
  } else {
221
223
  const success = result.success !== false;
222
224
  const resultStr = typeof result.result === "string"
@@ -232,7 +234,7 @@ function printToolCallSafe(name, args, result) {
232
234
  .replace(/"fileCount":\d+/g, "");
233
235
  const statusIcon = success ? "✓" : "✗";
234
236
  const statusColor = success ? tui.PALETTE.success : tui.PALETTE.danger;
235
- console.log(tui.styled(` ${statusIcon} Sonuç: ${cleanResult.trim()}`, { color: statusColor }));
237
+ console.log(tui.styled(` ${statusIcon} ${L('Sonuç', 'Result')}: ${cleanResult.trim()}`, { color: statusColor }));
236
238
  }
237
239
  }
238
240
 
@@ -261,10 +263,10 @@ function printToolCall(name, args, result) {
261
263
  console.log(" " + tui.styled(" Args: " + argsStr, { color: tui.PALETTE.muted }));
262
264
  if (result) {
263
265
  if (result.error) {
264
- console.log(" " + tui.styled(" ✗ Hata: " + result.error.slice(0, 200), { color: tui.PALETTE.danger }));
266
+ console.log(" " + tui.styled(L(" ✗ Hata: ", " ✗ Error: ") + result.error.slice(0, 200), { color: tui.PALETTE.danger }));
265
267
  } else if (result.success !== false) {
266
268
  const out = typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200);
267
- console.log(" " + tui.styled(" ✓ Sonuç: " + out, { color: tui.PALETTE.success }));
269
+ console.log(" " + tui.styled(L(" ✓ Sonuç: ", " ✓ Result: ") + out, { color: tui.PALETTE.success }));
268
270
  }
269
271
  }
270
272
  }
@@ -298,7 +300,7 @@ function scanProject(cwd) {
298
300
  async function codeV5(targetPath) {
299
301
  const config = getConfig();
300
302
  if (!config.providerUrl || !config.providerApiKey) {
301
- console.log(tui.C.red("\n ❌ Provider ayarlı değil. Önce: natureco setup\n"));
303
+ console.log(tui.C.red(L("\n ❌ Provider ayarlı değil. Önce: natureco setup\n", "\n ❌ Provider not configured. First: natureco setup\n")));
302
304
  return;
303
305
  }
304
306
 
@@ -347,7 +349,7 @@ async function codeV5(targetPath) {
347
349
  execute: async (args) => {
348
350
  const ok = planMode.exit(args.plan);
349
351
  if (!ok) return { error: 'Not in plan mode.' };
350
- console.log(tui.C.cyan('\n 📋 Plan sunuldu. Onay için /plan approve yazın, red için /plan reject.\n'));
352
+ console.log(tui.C.cyan(L('\n 📋 Plan sunuldu. Onay için /plan approve yazın, red için /plan reject.\n', '\n 📋 Plan submitted. Type /plan approve to approve, /plan reject to reject.\n')));
351
353
  return { result: `Plan submitted.\n\n${args.plan}` };
352
354
  },
353
355
  },
@@ -437,22 +439,22 @@ async function codeV5(targetPath) {
437
439
 
438
440
  // Project context
439
441
  if (projectCtx) {
440
- console.log("\n " + tui.C.muted("📂 Proje bağlamı:"));
442
+ console.log("\n " + tui.C.muted(L("📂 Proje bağlamı:", "📂 Project context:")));
441
443
  if (projectCtx.readme) console.log(" " + tui.C.muted("• README: ") + tui.C.text(projectCtx.readme));
442
444
  if (projectCtx.configFiles.length) {
443
445
  console.log(" " + tui.C.muted("• Config: ") + tui.C.text(projectCtx.configFiles.join(", ")));
444
446
  }
445
447
  if (projectCtx.dirs.length) {
446
- console.log(" " + tui.C.muted("• Klasörler: ") + tui.C.text(projectCtx.dirs.slice(0, 8).join(", ")));
448
+ console.log(" " + tui.C.muted(L("• Klasörler: ", "• Folders: ")) + tui.C.text(projectCtx.dirs.slice(0, 8).join(", ")));
447
449
  }
448
- console.log(" " + tui.C.muted("• Toplam dosya: ") + tui.C.text(String(projectCtx.totalFiles)));
450
+ console.log(" " + tui.C.muted(L("• Toplam dosya: ", "• Total files: ")) + tui.C.text(String(projectCtx.totalFiles)));
449
451
  }
450
452
 
451
- console.log("\n " + tui.C.muted("Komutlar:"));
452
- console.log(" " + tui.C.amber("/plan on|approve|reject|show") + tui.C.muted(" — Plan modu"));
453
- console.log(" " + tui.C.amber("/summary") + tui.C.muted(" — Oturum özeti"));
454
- console.log(" " + tui.C.amber("/done") + tui.C.muted(" — Özet + çıkış"));
455
- console.log(" " + tui.C.amber("Ctrl+C") + tui.C.muted(" — Çıkış"));
453
+ console.log("\n " + tui.C.muted(L("Komutlar:", "Commands:")));
454
+ console.log(" " + tui.C.amber("/plan on|approve|reject|show") + tui.C.muted(L(" — Plan modu", " — Plan mode")));
455
+ console.log(" " + tui.C.amber("/summary") + tui.C.muted(L(" — Oturum özeti", " — Session summary")));
456
+ console.log(" " + tui.C.amber("/done") + tui.C.muted(L(" — Özet + çıkış", " — Summary + exit")));
457
+ console.log(" " + tui.C.amber("Ctrl+C") + tui.C.muted(L(" — Çıkış", " — Exit")));
456
458
  console.log("");
457
459
 
458
460
  // Three-tier system prompt (Hermes-style)
@@ -461,7 +463,7 @@ async function codeV5(targetPath) {
461
463
  const projectRules = discoverProjectRules(cwd);
462
464
  const promptOpts = {
463
465
  botName: 'Code Agent',
464
- userName: cfg.userName || 'kullanıcı',
466
+ userName: cfg.userName || L('kullanıcı', 'user'),
465
467
  skillsIndexBlock,
466
468
  projectRules,
467
469
  hasHistory: false,
@@ -497,19 +499,19 @@ async function codeV5(targetPath) {
497
499
  const arg = input.slice(6).trim();
498
500
  const pm = getPlanMode();
499
501
  if (arg === "on" || arg === "enter") {
500
- if (pm.enter()) console.log(tui.C.cyan('\n 📋 Plan modu aktif.\n'));
501
- else console.log(tui.C.yellow(' Zaten plan modunda.'));
502
+ if (pm.enter()) console.log(tui.C.cyan(L('\n 📋 Plan modu aktif.\n', '\n 📋 Plan mode active.\n')));
503
+ else console.log(tui.C.yellow(L(' Zaten plan modunda.', ' Already in plan mode.')));
502
504
  } else if (arg === "approve") {
503
- if (pm.inReview()) { pm.approve(); console.log(tui.C.green(' ✓ Plan onaylandı.\n')); }
504
- else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
505
+ if (pm.inReview()) { pm.approve(); console.log(tui.C.green(L(' ✓ Plan onaylandı.\n', ' ✓ Plan approved.\n'))); }
506
+ else console.log(tui.C.yellow(L(' Onay bekleyen plan yok.', ' No plan awaiting approval.')));
505
507
  } else if (arg === "reject") {
506
- if (pm.inReview()) { pm.reject(); console.log(tui.C.amber(' ⨯ Plan reddedildi.\n')); }
507
- else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
508
+ if (pm.inReview()) { pm.reject(); console.log(tui.C.amber(L(' ⨯ Plan reddedildi.\n', ' ⨯ Plan rejected.\n'))); }
509
+ else console.log(tui.C.yellow(L(' Onay bekleyen plan yok.', ' No plan awaiting approval.')));
508
510
  } else if (arg === "show") {
509
- if (pm.planHistory.length > 0) console.log(tui.C.cyan('\n 📋 Son Plan:\n ' + pm.planHistory[pm.planHistory.length - 1].plan.replace(/\n/g, '\n ') + '\n'));
510
- else console.log(tui.C.yellow(' Henüz plan yok.'));
511
+ if (pm.planHistory.length > 0) console.log(tui.C.cyan(L('\n 📋 Son Plan:\n ', '\n 📋 Last Plan:\n ') + pm.planHistory[pm.planHistory.length - 1].plan.replace(/\n/g, '\n ') + '\n'));
512
+ else console.log(tui.C.yellow(L(' Henüz plan yok.', ' No plan yet.')));
511
513
  } else {
512
- console.log(tui.C.yellow(' Kullanım: /plan on|approve|reject|show'));
514
+ console.log(tui.C.yellow(L(' Kullanım: /plan on|approve|reject|show', ' Usage: /plan on|approve|reject|show')));
513
515
  }
514
516
  process.stdout.write("\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
515
517
  return ask();
@@ -548,12 +550,12 @@ async function codeV5(targetPath) {
548
550
  return ` ${s} ${t}: ${summary}`;
549
551
  }).join('\n');
550
552
  const skillInfo = wf.skillsLoaded && wf.skillsLoaded.length > 0
551
- ? `\n\nKullanilan skill'ler: ${wf.skillsLoaded.join(', ')}`
553
+ ? `\n\n${L("Kullanilan skill'ler", 'Skills used')}: ${wf.skillsLoaded.join(', ')}`
552
554
  : '';
553
555
  const preWfLen = messages.length;
554
556
  messages.push({
555
557
  role: 'system',
556
- content: `=== WORKFLOW SONUCLARI ===\nSu araclar calisti:\n${report}${skillInfo}\n\nKullaniciya bu sonuclari anlamli bir sekilde ozetle.\n=== SONUC BITTI ===`,
558
+ content: `=== ${L('WORKFLOW SONUÇLARI', 'WORKFLOW RESULTS')} ===\n${L('Şu araçlar çalıştı', 'These tools ran')}:\n${report}${skillInfo}\n\n${L('Kullanıcıya bu sonuçları anlamlı bir şekilde özetle.', 'Summarize these results for the user in a meaningful way.')}\n=== ${L('SONUÇ BİTTİ', 'END RESULT')} ===`,
557
559
  });
558
560
 
559
561
  process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
@@ -631,10 +633,10 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
631
633
  if (risk.requiresApproval) {
632
634
  process.stdout.write("\n");
633
635
  const approved = await confirm(
634
- `⚠ ${tc.function.name}: ${risk.reason}\n Devam edilsin mi? (Y/n) `
636
+ `⚠ ${tc.function.name}: ${risk.reason}\n ${L('Devam edilsin mi', 'Continue')}? (Y/n) `
635
637
  );
636
638
  if (!approved) {
637
- console.log("\n " + tui.C.yellow("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı."));
639
+ console.log("\n " + tui.C.yellow(L("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı.", "⚠ User declined approval, tool not run.")));
638
640
  return;
639
641
  }
640
642
  }
@@ -643,7 +645,7 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
643
645
  const pm = getPlanMode();
644
646
  const planCheck = pm.checkTool(tc.function.name, args);
645
647
  if (!planCheck.allowed) {
646
- console.log("\n " + tui.C.red("⛔ Plan modunda engellendi: " + planCheck.reason));
648
+ console.log("\n " + tui.C.red(L("⛔ Plan modunda engellendi: ", "⛔ Blocked in plan mode: ") + planCheck.reason));
647
649
  return;
648
650
  }
649
651
  pm.recordTool(tc.function.name, args);
@@ -651,18 +653,18 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
651
653
  // Permission check
652
654
  const perm = checkPermission(tc.function.name, args);
653
655
  if (perm.action === 'deny') {
654
- console.log("\n " + tui.C.red("⛔ İzin engelledi: " + perm.reason));
656
+ console.log("\n " + tui.C.red(L("⛔ İzin engelledi: ", "⛔ Permission denied: ") + perm.reason));
655
657
  return;
656
658
  }
657
659
  if (perm.action === 'ask') {
658
660
  const permKey = `${perm.rule.raw}:${JSON.stringify(args)}`;
659
661
  if (!isApproved(permKey)) {
660
662
  process.stdout.write("\n");
661
- const ok = await confirm(`İzin gerekli: ${formatPermissionPrompt(tc.function.name, args, perm.reason)}\n İzin ver? [y=once, Y=session, p=persistent, n=no] `);
663
+ const ok = await confirm(`${L('İzin gerekli', 'Permission required')}: ${formatPermissionPrompt(tc.function.name, args, perm.reason)}\n ${L('İzin ver', 'Grant')}? [y=once, Y=session, p=persistent, n=no] `);
662
664
  if (ok === 'persistent') markApproved(permKey, true);
663
665
  else if (ok === 'session' || ok === true) markApproved(permKey, false);
664
666
  else {
665
- console.log("\n " + tui.C.yellow("⛔ İzin reddedildi"));
667
+ console.log("\n " + tui.C.yellow(L("⛔ İzin reddedildi", "⛔ Permission rejected")));
666
668
  return;
667
669
  }
668
670
  }
@@ -671,13 +673,13 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
671
673
  // Pre-hook check
672
674
  const hook = checkPreHooks(tc.function.name, args);
673
675
  if (hook.action === 'deny') {
674
- console.log("\n " + tui.C.red("⛔ Hook engelledi: " + hook.rule.raw));
676
+ console.log("\n " + tui.C.red(L("⛔ Hook engelledi: ", "⛔ Hook blocked: ") + hook.rule.raw));
675
677
  return;
676
678
  }
677
679
  if (hook.action === 'ask') {
678
- const ok = await confirm(`Hook onayı: ${permissionSummary(hook.rule, tc.function.name, args)}\n İzin verilsin mi? (y/N) `);
680
+ const ok = await confirm(`${L('Hook onayı', 'Hook approval')}: ${permissionSummary(hook.rule, tc.function.name, args)}\n ${L('İzin verilsin mi', 'Grant permission')}? (y/N) `);
679
681
  if (!ok) {
680
- console.log("\n " + tui.C.yellow("⛔ Hook reddetti: " + hook.rule.raw));
682
+ console.log("\n " + tui.C.yellow(L("⛔ Hook reddetti: ", "⛔ Hook rejected: ") + hook.rule.raw));
681
683
  return;
682
684
  }
683
685
  }
@@ -729,11 +731,11 @@ function printSummary(files, cmds, msgs, startTime) {
729
731
  const elapsed = Math.floor((Date.now() - startTime) / 1000);
730
732
  const min = Math.floor(elapsed / 60);
731
733
  const sec = elapsed % 60;
732
- console.log("\n " + tui.styled("─── Session Özeti ───", { color: tui.PALETTE.primary, bold: true }));
733
- console.log(" " + tui.C.green(" ✓ " + files + " dosya değiştirildi"));
734
- console.log(" " + tui.C.green(" ✓ " + cmds + " komut çalıştırıldı"));
735
- console.log(" " + tui.C.amber(" ✓ " + msgs + " mesaj değişimi"));
736
- console.log(" " + tui.C.muted(" ⏱ " + min + "dk " + sec + "sn"));
734
+ console.log("\n " + tui.styled(L("─── Session Özeti ───", "─── Session Summary ───"), { color: tui.PALETTE.primary, bold: true }));
735
+ console.log(" " + tui.C.green(" ✓ " + files + L(" dosya değiştirildi", " files changed")));
736
+ console.log(" " + tui.C.green(" ✓ " + cmds + L(" komut çalıştırıldı", " commands run")));
737
+ console.log(" " + tui.C.amber(" ✓ " + msgs + L(" mesaj değişimi", " message exchanges")));
738
+ console.log(" " + tui.C.muted(" ⏱ " + min + L("dk ", "min ") + sec + L("sn", "s")));
737
739
  console.log("");
738
740
  }
739
741
 
@@ -1,4 +1,6 @@
1
1
  const chalk = require('chalk');
2
+ const { getLang: _gl } = require('../utils/i18n');
3
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
2
4
  const fs = require('fs');
3
5
  const path = require('path');
4
6
  const os = require('os');
@@ -12,35 +14,35 @@ function policy(args) {
12
14
  if (action === 'list') return listPolicies();
13
15
  if (action === 'remove') return removePolicy(params[0]);
14
16
 
15
- console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
16
- console.log(chalk.gray(' Kullanım: natureco policy [check|set|list|remove]\n'));
17
+ console.log(chalk.red(`\n ❌ ${L('Bilinmeyen komut', 'Unknown command')}: ${action}\n`));
18
+ console.log(chalk.gray(L(' Kullanım: natureco policy [check|set|list|remove]\n', ' Usage: natureco policy [check|set|list|remove]\n')));
17
19
  process.exit(1);
18
20
  }
19
21
 
20
22
  const POLICY_CHECKS = [
21
23
  {
22
24
  id: 'node-version',
23
- name: 'Node.js Versiyonu',
25
+ name: L('Node.js Versiyonu', 'Node.js Version'),
24
26
  check: () => {
25
27
  const v = process.version.slice(1).split('.')[0];
26
28
  return parseInt(v) >= 18
27
29
  ? { status: 'pass', message: `Node.js ${process.version}` }
28
- : { status: 'fail', message: `Node.js ${process.version} (18+ gerekli)`, fix: 'Node.js güncelleyin' };
30
+ : { status: 'fail', message: `Node.js ${process.version} (18+ ${L('gerekli', 'required')})`, fix: L('Node.js güncelleyin', 'Update Node.js') };
29
31
  }
30
32
  },
31
33
  {
32
34
  id: 'config-exists',
33
- name: 'Config Dosyası',
35
+ name: L('Config Dosyası', 'Config File'),
34
36
  check: () => {
35
37
  const configFile = path.join(os.homedir(), '.natureco', 'config.json');
36
38
  if (!fs.existsSync(configFile)) {
37
- return { status: 'fail', message: 'config.json bulunamadı', fix: 'natureco setup çalıştırın' };
39
+ return { status: 'fail', message: L('config.json bulunamadı', 'config.json not found'), fix: L('natureco setup çalıştırın', 'run natureco setup') };
38
40
  }
39
41
  try {
40
42
  JSON.parse(fs.readFileSync(configFile, 'utf-8'));
41
- return { status: 'pass', message: 'Config geçerli JSON' };
43
+ return { status: 'pass', message: L('Config geçerli JSON', 'Config valid JSON') };
42
44
  } catch {
43
- return { status: 'fail', message: 'Config bozuk JSON', fix: '~/.natureco/config.json düzeltin' };
45
+ return { status: 'fail', message: L('Config bozuk JSON', 'Config broken JSON'), fix: L('~/.natureco/config.json düzeltin', 'fix ~/.natureco/config.json') };
44
46
  }
45
47
  }
46
48
  },
@@ -50,9 +52,9 @@ const POLICY_CHECKS = [
50
52
  check: () => {
51
53
  const config = getConfig();
52
54
  if (config.providerApiKey || config.apiKey || process.env.GROQ_API_KEY) {
53
- return { status: 'pass', message: 'API key mevcut' };
55
+ return { status: 'pass', message: L('API key mevcut', 'API key present') };
54
56
  }
55
- return { status: 'warn', message: 'API key eksik', fix: 'natureco login veya GROQ_API_KEY env' };
57
+ return { status: 'warn', message: L('API key eksik', 'API key missing'), fix: L('natureco login veya GROQ_API_KEY env', 'natureco login or GROQ_API_KEY env') };
56
58
  }
57
59
  },
58
60
  {
@@ -63,46 +65,46 @@ const POLICY_CHECKS = [
63
65
  if (config.providerUrl) {
64
66
  return { status: 'pass', message: config.providerUrl };
65
67
  }
66
- return { status: 'warn', message: 'Provider ayarlanmamış', fix: 'natureco setup' };
68
+ return { status: 'warn', message: L('Provider ayarlanmamış', 'Provider not set'), fix: 'natureco setup' };
67
69
  }
68
70
  },
69
71
  {
70
72
  id: 'git-config',
71
- name: 'Git Yapılandırması',
73
+ name: L('Git Yapılandırması', 'Git Configuration'),
72
74
  check: () => {
73
75
  try {
74
76
  const { execSync } = require('child_process');
75
77
  const name = execSync('git config user.name', { encoding: 'utf-8', stdio: 'pipe' }).trim();
76
78
  const email = execSync('git config user.email', { encoding: 'utf-8', stdio: 'pipe' }).trim();
77
79
  if (name && email) return { status: 'pass', message: `${name} <${email}>` };
78
- return { status: 'warn', message: 'Git user.name/email eksik', fix: 'git config --global user.name "Adınız"' };
80
+ return { status: 'warn', message: L('Git user.name/email eksik', 'Git user.name/email missing'), fix: L('git config --global user.name "Adınız"', 'git config --global user.name "Your Name"') };
79
81
  } catch {
80
- return { status: 'warn', message: 'Git repo değil', fix: 'git init' };
82
+ return { status: 'warn', message: L('Git repo değil', 'Not a git repo'), fix: 'git init' };
81
83
  }
82
84
  }
83
85
  },
84
86
  {
85
87
  id: 'disk-space',
86
- name: 'Disk Alanı',
88
+ name: L('Disk Alanı', 'Disk Space'),
87
89
  check: () => {
88
90
  try {
89
91
  const drive = path.parse(os.homedir()).root.replace(':', '');
90
92
  const { execSync } = require('child_process');
91
93
  const output = execSync(`powershell -Command "Get-PSDrive -Name ${drive} | Select-Object -ExpandProperty Free"`, { encoding: 'utf-8' }).trim();
92
94
  const free = parseInt(output);
93
- if (isNaN(free)) return { status: 'pass', message: 'Kontrol edilemedi' };
95
+ if (isNaN(free)) return { status: 'pass', message: L('Kontrol edilemedi', 'Could not check') };
94
96
  const freeGB = free / 1e9;
95
- if (freeGB < 0.5) return { status: 'fail', message: `Sadece ${freeGB.toFixed(1)}GB boş`, fix: 'Disk temizliği yapın' };
96
- return { status: 'pass', message: `${freeGB.toFixed(1)}GB boş alan` };
97
+ if (freeGB < 0.5) return { status: 'fail', message: `${L('Sadece', 'Only')} ${freeGB.toFixed(1)}GB ${L('boş', 'free')}`, fix: L('Disk temizliği yapın', 'Free up disk space') };
98
+ return { status: 'pass', message: `${freeGB.toFixed(1)}GB ${L('boş alan', 'free')}` };
97
99
  } catch {
98
- return { status: 'pass', message: 'Kontrol edilemedi' };
100
+ return { status: 'pass', message: L('Kontrol edilemedi', 'Could not check') };
99
101
  }
100
102
  }
101
103
  }
102
104
  ];
103
105
 
104
106
  function checkPolicy() {
105
- console.log(chalk.cyan.bold('\n Workspace Uyumluluk Politikası\n'));
107
+ console.log(chalk.cyan.bold(L('\n Workspace Uyumluluk Politikası\n', '\n Workspace Compliance Policy\n')));
106
108
  console.log(chalk.gray(' ' + '─'.repeat(48)));
107
109
 
108
110
  let passed = 0;
@@ -116,29 +118,29 @@ function checkPolicy() {
116
118
  passed++;
117
119
  } else if (result.status === 'fail') {
118
120
  console.log(` ${chalk.red('✗')} ${check.name}: ${chalk.white(result.message)}`);
119
- console.log(chalk.gray(` Düzeltme: ${result.fix}`));
121
+ console.log(chalk.gray(` ${L('Düzeltme', 'Fix')}: ${result.fix}`));
120
122
  failed++;
121
123
  } else {
122
124
  console.log(` ${chalk.yellow('⚠')} ${check.name}: ${chalk.white(result.message)}`);
123
- if (result.fix) console.log(chalk.gray(` Öneri: ${result.fix}`));
125
+ if (result.fix) console.log(chalk.gray(` ${L('Öneri', 'Tip')}: ${result.fix}`));
124
126
  warnings++;
125
127
  }
126
128
  }
127
129
 
128
130
  console.log(chalk.gray(' ' + '─'.repeat(48)));
129
- console.log(chalk.gray(` Geçti: ${passed} | Uyarı: ${warnings} | Hata: ${failed}\n`));
131
+ console.log(chalk.gray(` ${L('Geçti', 'Passed')}: ${passed} | ${L('Uyarı', 'Warnings')}: ${warnings} | ${L('Hata', 'Errors')}: ${failed}\n`));
130
132
  }
131
133
 
132
134
  function setPolicy(key, value) {
133
135
  if (!key) {
134
- console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
136
+ console.log(chalk.red(L('\n ❌ Politika adı gerekli\n', '\n ❌ Policy name required\n')));
135
137
  return;
136
138
  }
137
139
  const config = getConfig();
138
140
  if (!config.policies) config.policies = {};
139
141
  config.policies[key] = value;
140
142
  saveConfig(config);
141
- console.log(chalk.green(`\n ✓ Politika ayarlandı: ${key} = ${value}\n`));
143
+ console.log(chalk.green(`\n ✓ ${L('Politika ayarlandı', 'Policy set')}: ${key} = ${value}\n`));
142
144
  }
143
145
 
144
146
  function listPolicies() {
@@ -146,11 +148,11 @@ function listPolicies() {
146
148
  const policies = config.policies || {};
147
149
 
148
150
  if (Object.keys(policies).length === 0) {
149
- console.log(chalk.gray('\n Tanımlı politika yok.\n'));
151
+ console.log(chalk.gray(L('\n Tanımlı politika yok.\n', '\n No policies defined.\n')));
150
152
  return;
151
153
  }
152
154
 
153
- console.log(chalk.cyan.bold('\n Tanımlı Politikalar\n'));
155
+ console.log(chalk.cyan.bold(L('\n Tanımlı Politikalar\n', '\n Defined Policies\n')));
154
156
  console.log(chalk.gray(' ' + '─'.repeat(48)));
155
157
  for (const [key, value] of Object.entries(policies)) {
156
158
  console.log(` ${chalk.white(key)}: ${chalk.cyan(value)}`);
@@ -160,16 +162,16 @@ function listPolicies() {
160
162
 
161
163
  function removePolicy(key) {
162
164
  if (!key) {
163
- console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
165
+ console.log(chalk.red(L('\n ❌ Politika adı gerekli\n', '\n ❌ Policy name required\n')));
164
166
  return;
165
167
  }
166
168
  const config = getConfig();
167
169
  if (config.policies?.[key]) {
168
170
  delete config.policies[key];
169
171
  saveConfig(config);
170
- console.log(chalk.green(`\n ✓ Politika silindi: ${key}\n`));
172
+ console.log(chalk.green(`\n ✓ ${L('Politika silindi', 'Policy deleted')}: ${key}\n`));
171
173
  } else {
172
- console.log(chalk.yellow(`\n ⚠ Politika bulunamadı: ${key}\n`));
174
+ console.log(chalk.yellow(`\n ⚠ ${L('Politika bulunamadı', 'Policy not found')}: ${key}\n`));
173
175
  }
174
176
  }
175
177
 
@@ -1,4 +1,6 @@
1
- const chalk = require('chalk');
1
+ const chalk = require('chalk');
2
+ const { getLang: _gl } = require('../utils/i18n');
3
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
2
4
  const fs = require('fs');
3
5
  const path = require('path');
4
6
  const os = require('os');
@@ -17,8 +19,8 @@ async function security(args) {
17
19
 
18
20
  if (action === 'secrets') return scanSecrets(args);
19
21
 
20
- console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
21
- console.log(chalk.gray(' Kullanım: natureco security [audit|allowlist|policy|secrets]\n'));
22
+ console.log(chalk.red(`\n ❌ ${L('Bilinmeyen komut', 'Unknown command')}: ${action}\n`));
23
+ console.log(chalk.gray(L(' Kullanım: natureco security [audit|allowlist|policy|secrets]\n', ' Usage: natureco security [audit|allowlist|policy|secrets]\n')));
22
24
  process.exit(1);
23
25
  }
24
26
 
@@ -58,7 +60,7 @@ async function allowlistAction(args) {
58
60
  return;
59
61
  }
60
62
 
61
- console.log(chalk.gray('\n Kullanım:'));
63
+ console.log(chalk.gray(L('\n Kullanım:', '\n Usage:')));
62
64
  console.log(chalk.gray(' natureco security allowlist list'));
63
65
  console.log(chalk.gray(' natureco security allowlist add "<command>"'));
64
66
  console.log(chalk.gray(' natureco security allowlist remove <id>\n'));
@@ -79,7 +81,7 @@ async function policyAction(args) {
79
81
  return;
80
82
  }
81
83
 
82
- console.log(chalk.gray('\n Kullanım:'));
84
+ console.log(chalk.gray(L('\n Kullanım:', '\n Usage:')));
83
85
  console.log(chalk.gray(' natureco security policy set deny|allowlist|full'));
84
86
  console.log(chalk.gray('\n Policy levels:'));
85
87
  console.log(chalk.gray(' deny - Block all command execution'));
@@ -140,11 +142,11 @@ async function audit(args) {
140
142
  if (process.platform !== 'win32' && mode !== '600' && mode !== '644') {
141
143
  issues.push({
142
144
  id: 'config-permissions',
143
- msg: `Config dosyası izinleri geniş: ${mode} (önerilen: 600)`,
145
+ msg: `${L('Config dosyası izinleri geniş', 'Config file permissions too broad')}: ${mode} ${L('(önerilen: 600)', '(recommended: 600)')}`,
144
146
  fix: () => fs.chmodSync(CONFIG_FILE, 0o600),
145
147
  });
146
148
  } else {
147
- ok.push('Config dosyası izinleri');
149
+ ok.push(L('Config dosyası izinleri', 'Config file permissions'));
148
150
  }
149
151
  } catch {}
150
152
  }
@@ -153,7 +155,7 @@ async function audit(args) {
153
155
  const config = getConfig();
154
156
  if (config.providerApiKey) {
155
157
  if (config.providerApiKey.length < 10) {
156
- issues.push({ id: 'weak-api-key', msg: 'API key çok kısa görünüyor' });
158
+ issues.push({ id: 'weak-api-key', msg: L('API key çok kısa görünüyor', 'API key looks too short') });
157
159
  } else {
158
160
  ok.push('API key formatı');
159
161
  }
@@ -161,9 +163,9 @@ async function audit(args) {
161
163
 
162
164
  // 3. Debug mode
163
165
  if (config.debug === true) {
164
- warnings.push({ id: 'debug-mode', msg: 'Debug modu açık — API key\'ler loglara yazılabilir' });
166
+ warnings.push({ id: 'debug-mode', msg: L('Debug modu açık — API key\'ler loglara yazılabilir', 'Debug mode on — API keys may be written to logs') });
165
167
  } else {
166
- ok.push('Debug modu kapalı');
168
+ ok.push(L('Debug modu kapalı', 'Debug mode off'));
167
169
  }
168
170
 
169
171
  // 4. WhatsApp session dosyaları
@@ -171,9 +173,9 @@ async function audit(args) {
171
173
  if (fs.existsSync(waDir)) {
172
174
  const sessions = fs.readdirSync(waDir);
173
175
  if (sessions.length > 3) {
174
- warnings.push({ id: 'old-wa-sessions', msg: `${sessions.length} WhatsApp session var — eskiler temizlenebilir` });
176
+ warnings.push({ id: 'old-wa-sessions', msg: `${sessions.length} WhatsApp ${L('session var — eskiler temizlenebilir', 'sessions — old ones can be cleaned')}` });
175
177
  } else {
176
- ok.push('WhatsApp session sayısı');
178
+ ok.push(L('WhatsApp session sayısı', 'WhatsApp session count'));
177
179
  }
178
180
  }
179
181
 
@@ -183,9 +185,9 @@ async function audit(args) {
183
185
  const stat = fs.statSync(logFile);
184
186
  const sizeMB = stat.size / (1024 * 1024);
185
187
  if (sizeMB > 50) {
186
- warnings.push({ id: 'large-log', msg: `Gateway log dosyası büyük: ${sizeMB.toFixed(1)}MB` });
188
+ warnings.push({ id: 'large-log', msg: `${L('Gateway log dosyası büyük', 'Gateway log file large')}: ${sizeMB.toFixed(1)}MB` });
187
189
  } else {
188
- ok.push('Gateway log boyutu');
190
+ ok.push(L('Gateway log boyutu', 'Gateway log size'));
189
191
  }
190
192
  }
191
193
 
@@ -194,9 +196,9 @@ async function audit(args) {
194
196
  if (fs.existsSync(convDir)) {
195
197
  const convFiles = fs.readdirSync(convDir).filter(f => f.endsWith('.json'));
196
198
  if (convFiles.length > 20) {
197
- warnings.push({ id: 'old-conversations', msg: `${convFiles.length} konuşma dosyası var — eskiler temizlenebilir` });
199
+ warnings.push({ id: 'old-conversations', msg: `${convFiles.length} ${L('konuşma dosyası var — eskiler temizlenebilir', 'conversation files — old ones can be cleaned')}` });
198
200
  } else {
199
- ok.push('Konuşma dosyası sayısı');
201
+ ok.push(L('Konuşma dosyası sayısı', 'Conversation file count'));
200
202
  }
201
203
  }
202
204
 
@@ -245,7 +247,7 @@ async function audit(args) {
245
247
 
246
248
  console.log('');
247
249
  console.log(chalk.gray(' ' + '─'.repeat(48)));
248
- console.log(chalk.cyan.bold('\n Güvenlik Denetimi\n'));
250
+ console.log(chalk.cyan.bold(L('\n Güvenlik Denetimi\n', '\n Security Audit\n')));
249
251
 
250
252
  ok.forEach(msg => console.log(chalk.green(' ✓ ') + chalk.gray(msg)));
251
253
 
@@ -263,11 +265,11 @@ async function audit(args) {
263
265
  console.log(chalk.gray(' ' + '─'.repeat(48)));
264
266
 
265
267
  if (issues.length === 0 && warnings.length === 0) {
266
- console.log(chalk.green(' ✓ Güvenlik sorunu bulunamadı\n'));
268
+ console.log(chalk.green(L(' ✓ Güvenlik sorunu bulunamadı\n', ' ✓ No security issues found\n')));
267
269
  return;
268
270
  }
269
271
 
270
- console.log(chalk.gray(` ${ok.length} geçti · ${warnings.length} uyarı · ${issues.length} sorun`));
272
+ console.log(chalk.gray(` ${ok.length} ${L('geçti', 'passed')} · ${warnings.length} ${L('uyarı', 'warnings')} · ${issues.length} ${L('sorun', 'issues')}`));
271
273
 
272
274
  if (fix && issues.length > 0) {
273
275
  console.log('');
@@ -275,14 +277,14 @@ async function audit(args) {
275
277
  if (i.fix) {
276
278
  try {
277
279
  i.fix();
278
- console.log(chalk.green(` ✓ Düzeltildi: ${i.id}`));
280
+ console.log(chalk.green(` ✓ ${L('Düzeltildi', 'Fixed')}: ${i.id}`));
279
281
  } catch (e) {
280
- console.log(chalk.red(` ❌ Düzeltilemedi: ${i.id} — ${e.message}`));
282
+ console.log(chalk.red(` ❌ ${L('Düzeltilemedi', 'Could not fix')}: ${i.id} — ${e.message}`));
281
283
  }
282
284
  }
283
285
  });
284
286
  } else if (issues.length > 0) {
285
- console.log(chalk.gray('\n Otomatik düzeltmek için: ') + chalk.cyan('natureco security audit --fix'));
287
+ console.log(chalk.gray(L('\n Otomatik düzeltmek için: ', '\n To auto-fix: ')) + chalk.cyan('natureco security audit --fix'));
286
288
  }
287
289
  console.log('');
288
290
  }