natureco-cli 5.58.0 → 5.59.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.58.0",
3
+ "version": "5.59.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"
@@ -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 tui = require('../utils/tui');
3
5
  const F = require('../utils/format');
4
6
  const { getConfig, saveConfig } = require('../utils/config');
@@ -297,9 +299,9 @@ function listChannels() {
297
299
  F.header('Channels');
298
300
 
299
301
  if (channels.length === 0) {
300
- console.log('\n' + tui.styled(' 📡 Bağlı Kanal Yok', { color: tui.PALETTE.warning, bold: true }));
302
+ console.log('\n' + tui.styled(L(' 📡 Bağlı Kanal Yok', ' 📡 No Connected Channels'), { color: tui.PALETTE.warning, bold: true }));
301
303
  console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
302
- console.log('\n ' + tui.C.muted('Bağlamak için:'));
304
+ console.log('\n ' + tui.C.muted(L('Bağlamak için:', 'To connect:')));
303
305
  const connectCmds = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage', 'sms', 'webhooks'];
304
306
  for (const c of connectCmds) {
305
307
  console.log(' ' + tui.C.brand('natureco ' + c + ' connect'));
@@ -308,23 +310,23 @@ function listChannels() {
308
310
  return;
309
311
  }
310
312
 
311
- console.log('\n' + tui.styled(' 📡 Bağlı Kanallar (' + channels.length + ')', { color: tui.PALETTE.primary, bold: true }));
313
+ console.log('\n' + tui.styled(L(' 📡 Bağlı Kanallar (', ' 📡 Connected Channels (') + channels.length + ')', { color: tui.PALETTE.primary, bold: true }));
312
314
  console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
313
315
  console.log('\n' + tui.table(channels, [
314
316
  {
315
- key: 'name', label: 'Kanal', minWidth: 14,
317
+ key: 'name', label: L('Kanal', 'Channel'), minWidth: 14,
316
318
  render: r => tui.styled(r.type + ' ' + r.name, { color: tui.PALETTE.primary, bold: true })
317
319
  },
318
320
  {
319
- key: 'status', label: 'Durum', minWidth: 14,
321
+ key: 'status', label: L('Durum', 'Status'), minWidth: 14,
320
322
  render: r => r.status === 'connected'
321
- ? tui.styled(' ✓ Bağlı ', { bg: tui.PALETTE.success, color: '#000', bold: true })
322
- : tui.styled(' ✗ Kopuk ', { bg: tui.PALETTE.muted, color: '#000', bold: true })
323
+ ? tui.styled(L(' ✓ Bağlı ', ' ✓ Linked '), { bg: tui.PALETTE.success, color: '#000', bold: true })
324
+ : tui.styled(L(' ✗ Kopuk ', ' ✗ Down '), { bg: tui.PALETTE.muted, color: '#000', bold: true })
323
325
  },
324
- { key: 'detail', label: 'Detay', minWidth: 30, render: r => tui.C.muted(r.detail) },
326
+ { key: 'detail', label: L('Detay', 'Detail'), minWidth: 30, render: r => tui.C.muted(r.detail) },
325
327
  ], { borderStyle: 'round', zebra: true }));
326
328
 
327
- console.log('\n ' + tui.C.muted('Kaldırmak için: ') + tui.C.brand('natureco channels remove <kanal>'));
329
+ console.log('\n ' + tui.C.muted(L('Kaldırmak için: ', 'To remove: ')) + tui.C.brand(L('natureco channels remove <kanal>', 'natureco channels remove <channel>')));
328
330
  console.log('');
329
331
  }
330
332
 
@@ -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 F = require('../utils/format');
3
5
  const tui = require('../utils/tui');
4
6
  const fs = require('fs');
@@ -98,19 +100,19 @@ function cmdCheck(name) {
98
100
  }
99
101
 
100
102
  function cmdRun(opts = {}) {
101
- F.header(opts.fix ? 'System Doctor · Otomatik Düzeltme (--fix)' : 'System Doctor · Tüm Sistem Kontrolleri', { icon: opts.fix ? '🔧' : '🩺' });
103
+ F.header(opts.fix ? L('System Doctor · Otomatik Düzeltme (--fix)', 'System Doctor · Auto-Fix (--fix)') : L('System Doctor · Tüm Sistem Kontrolleri', 'System Doctor · All System Checks'), { icon: opts.fix ? '🔧' : '🩺' });
102
104
 
103
105
  // v5.43.2: --fix modunda önce düzeltilebilir sorunları onar, sonra kontrolleri çalıştır.
104
106
  if (opts.fix) {
105
107
  const { applied, failed } = applyFixes();
106
108
  if (applied.length) {
107
- console.log('\n' + tui.C.green(' 🔧 Düzeltildi:'));
109
+ console.log('\n' + tui.C.green(L(' 🔧 Düzeltildi:', ' 🔧 Fixed:')));
108
110
  applied.forEach(a => console.log(' ' + tui.C.text('• ' + a)));
109
111
  } else {
110
- console.log('\n' + tui.C.muted(' 🔧 Düzeltilecek bir şey yok — sistem zaten düzgün.'));
112
+ console.log('\n' + tui.C.muted(L(' 🔧 Düzeltilecek bir şey yok — sistem zaten düzgün.', ' 🔧 Nothing to fix — system is already fine.')));
111
113
  }
112
114
  if (failed.length) {
113
- console.log('\n' + tui.C.amber(' ⚠️ Otomatik düzeltilemedi:'));
115
+ console.log('\n' + tui.C.amber(L(' ⚠️ Otomatik düzeltilemedi:', ' ⚠️ Could not auto-fix:')));
114
116
  failed.forEach(f => console.log(' ' + tui.C.muted('• ' + f)));
115
117
  }
116
118
  console.log('');
@@ -133,14 +135,14 @@ function cmdRun(opts = {}) {
133
135
 
134
136
  // Yeni TUI tablo
135
137
  console.log('\n' + tui.table(rows, [
136
- { key: 'check', label: 'Kontrol', minWidth: 28 },
138
+ { key: 'check', label: L('Kontrol', 'Check'), minWidth: 28 },
137
139
  {
138
- key: 'status', label: 'Durum', minWidth: 9,
140
+ key: 'status', label: L('Durum', 'Status'), minWidth: 9,
139
141
  render: r => r.status
140
142
  ? tui.styled(' ✓ PASS ', { bg: tui.PALETTE.success, color: '#000000', bold: true })
141
143
  : tui.styled(' ✗ FAIL ', { bg: tui.PALETTE.danger, color: '#000000', bold: true }),
142
144
  },
143
- { key: 'message', label: 'Mesaj', minWidth: 20 },
145
+ { key: 'message', label: L('Mesaj', 'Message'), minWidth: 20 },
144
146
  ], { borderStyle: 'round', zebra: true }));
145
147
 
146
148
  const total = passed + failed;
@@ -148,17 +150,17 @@ function cmdRun(opts = {}) {
148
150
 
149
151
  // Özet kartı
150
152
  console.log('\n' + tui.box(60, 5, {
151
- title: 'Özet',
153
+ title: L('Özet', 'Summary'),
152
154
  borderColor: failed > 0 ? tui.PALETTE.warning : tui.PALETTE.success,
153
155
  }).split('\n').map((line, i) => {
154
- if (i === 2) return line.replace(' '.repeat(58), ` ${tui.C.text(`${passed}/${total} kontrol geçti`)} · ${tui.C.muted(duration + 'ms')}`);
156
+ if (i === 2) return line.replace(' '.repeat(58), ` ${tui.C.text(`${passed}/${total} ${L('kontrol geçti', 'checks passed')}`)} · ${tui.C.muted(duration + 'ms')}`);
155
157
  return line;
156
158
  }).join('\n'));
157
159
 
158
160
  if (failed > 0) {
159
- console.log('\n' + tui.C.amber(' ⚠️ Bazı kontroller başarısız. Detay için: ') + tui.C.brand('natureco doctor check <name>'));
161
+ console.log('\n' + tui.C.amber(L(' ⚠️ Bazı kontroller başarısız. Detay için: ', ' ⚠️ Some checks failed. For details: ')) + tui.C.brand('natureco doctor check <name>'));
160
162
  } else {
161
- console.log('\n' + tui.C.green(' ✨ Tüm kontroller geçti! Sistem sağlıklı.'));
163
+ console.log('\n' + tui.C.green(L(' ✨ Tüm kontroller geçti! Sistem sağlıklı.', ' ✨ All checks passed! System healthy.')));
162
164
  }
163
165
  console.log('');
164
166
  }
@@ -209,7 +211,7 @@ function runCheck(name) {
209
211
  }
210
212
  return {
211
213
  pass: freeGB > 0.5,
212
- message: freeGB > 0.5 ? `${freeGB.toFixed(1)} GB free` : `Sadece ${(freeGB * 1024).toFixed(0)} MB kaldı — gerekli: 500 MB`,
214
+ message: freeGB > 0.5 ? `${freeGB.toFixed(1)} GB free` : `${L('Sadece', 'Only')} ${(freeGB * 1024).toFixed(0)} ${L('MB kaldı — gerekli: 500 MB', 'MB left — need: 500 MB')}`,
213
215
  };
214
216
  } catch (e) {
215
217
  return { pass: true, message: 'Unable to check disk space' };
@@ -233,9 +235,9 @@ function runCheck(name) {
233
235
  if (!fs.existsSync(CONFIG_FILE)) return { pass: false, message: 'Config missing — run `natureco setup`' };
234
236
  const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
235
237
  const key = cfg.providerApiKey || cfg.apiKey;
236
- if (!key) return { pass: false, message: 'API key tanımlı değil' };
237
- if (key.length < 10) return { pass: false, message: 'API key çok kısa — yanlış kopyalanmış olabilir' };
238
- return { pass: true, message: `Key uzunluğu: ${key.length} karakter` };
238
+ if (!key) return { pass: false, message: L('API key tanımlı değil', 'API key not set') };
239
+ if (key.length < 10) return { pass: false, message: L('API key çok kısa — yanlış kopyalanmış olabilir', 'API key too short — may be copied wrong') };
240
+ return { pass: true, message: `${L('Key uzunluğu', 'Key length')}: ${key.length} ${L('karakter', 'chars')}` };
239
241
  } catch (e) {
240
242
  return { pass: false, message: e.message };
241
243
  }
@@ -246,10 +248,10 @@ function runCheck(name) {
246
248
  if (!fs.existsSync(CONFIG_FILE)) return { pass: false, message: 'Config missing' };
247
249
  const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
248
250
  const url = cfg.providerUrl;
249
- if (!url) return { pass: false, message: 'Provider URL tanımlı değil' };
251
+ if (!url) return { pass: false, message: L('Provider URL tanımlı değil', 'Provider URL not set') };
250
252
  // URL format geçerli mi?
251
253
  const parsed = new URL(url);
252
- return { pass: true, message: `URL geçerli: ${parsed.host}` };
254
+ return { pass: true, message: `${L('URL geçerli', 'URL valid')}: ${parsed.host}` };
253
255
  } catch (e) {
254
256
  return { pass: false, message: e.message };
255
257
  }
@@ -261,13 +263,13 @@ function runCheck(name) {
261
263
  const REQUIRED = ['sources', 'concepts', 'cache', 'skills', 'memory', 'sessions', 'backups', 'hooks', 'audit'];
262
264
  const missing = REQUIRED.filter(d => !fs.existsSync(path.join(BASE_DIR, d)));
263
265
  if (missing.length === 0) {
264
- return { pass: true, message: `${REQUIRED.length} dizin hazır` };
266
+ return { pass: true, message: `${REQUIRED.length} ${L('dizin hazır', 'directories ready')}` };
265
267
  }
266
268
  // Otomatik oluştur
267
269
  for (const d of missing) {
268
270
  try { fs.mkdirSync(path.join(BASE_DIR, d), { recursive: true }); } catch {}
269
271
  }
270
- return { pass: true, message: `Eksik dizinler oluşturuldu: ${missing.join(', ')}` };
272
+ return { pass: true, message: `${L('Eksik dizinler oluşturuldu', 'Created missing directories')}: ${missing.join(', ')}` };
271
273
  } catch (e) {
272
274
  return { pass: false, message: e.message };
273
275
  }
@@ -278,7 +280,7 @@ function runCheck(name) {
278
280
  // Audit log yazma testi
279
281
  audit.logSync(audit.ACTIONS.INFO, { source: 'doctor', check: 'auditLog' });
280
282
  const files = audit.listLogFiles();
281
- return { pass: true, message: `${files.length} log dosyası, en son: ${files[0] || 'yok'}` };
283
+ return { pass: true, message: `${files.length} ${L('log dosyası, en son', 'log files, latest')}: ${files[0] || L('yok', 'none')}` };
282
284
  } catch (e) {
283
285
  return { pass: false, message: e.message };
284
286
  }
@@ -307,12 +309,12 @@ function runCheck(name) {
307
309
  return false;
308
310
  });
309
311
  if (realSecrets.length === 0) {
310
- return { pass: true, message: 'Çalışma dizininde gerçek secret bulunamadı ✓' };
312
+ return { pass: true, message: L('Çalışma dizininde gerçek secret bulunamadı ✓', 'No real secrets found in working directory ✓') };
311
313
  }
312
314
  const sample = realSecrets.slice(0, 3).map(f => `${f.type}@${path.basename(f.file || '?')}`).join(', ');
313
315
  return {
314
316
  pass: false,
315
- message: `${realSecrets.length} gerçek secret: ${sample}${realSecrets.length > 3 ? '...' : ''}`,
317
+ message: `${realSecrets.length} ${L('gerçek secret', 'real secrets')}: ${sample}${realSecrets.length > 3 ? '...' : ''}`,
316
318
  };
317
319
  } catch (e) {
318
320
  return { pass: false, message: e.message };
@@ -1,49 +1,51 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const inquirer = require('../utils/inquirer-wrapper');
4
- const chalk = require('chalk');
4
+ const chalk = require('chalk');
5
+ const { getLang: _gl } = require('../utils/i18n');
6
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
5
7
  const { getApiKey } = require('../utils/config');
6
8
  const { getBots } = require('../utils/api');
7
9
 
8
10
  async function init() {
9
- console.log(chalk.green.bold('\n╭─ NatureCo Proje Başlatma ─╮\n'));
11
+ console.log(chalk.green.bold(L('\n╭─ NatureCo Proje Başlatma ─╮\n', '\n╭─ NatureCo Project Init ─╮\n')));
10
12
 
11
13
  const apiKey = getApiKey();
12
14
  if (!apiKey) {
13
- console.log(chalk.red('❌ Giriş yapılmadı. Önce "natureco login" çalıştırın.\n'));
15
+ console.log(chalk.red(L('❌ Giriş yapılmadı. Önce "natureco login" çalıştırın.\n', '❌ Not logged in. Run "natureco login" first.\n')));
14
16
  process.exit(1);
15
17
  }
16
18
 
17
19
  // Mevcut klasörde .natureco var mı kontrol et
18
20
  const projectDir = path.join(process.cwd(), '.natureco');
19
21
  if (fs.existsSync(projectDir)) {
20
- console.log(chalk.yellow('⚠️ Bu klasörde zaten .natureco/ mevcut.\n'));
22
+ console.log(chalk.yellow(L('⚠️ Bu klasörde zaten .natureco/ mevcut.\n', '⚠️ This folder already has .natureco/.\n')));
21
23
  const { overwrite } = await inquirer.prompt([
22
24
  {
23
25
  type: 'confirm',
24
26
  name: 'overwrite',
25
- message: 'Üzerine yazmak ister misiniz?',
27
+ message: L('Üzerine yazmak ister misiniz?', 'Overwrite?'),
26
28
  default: false,
27
29
  },
28
30
  ]);
29
31
  if (!overwrite) {
30
- console.log(chalk.gray('İptal edildi.\n'));
32
+ console.log(chalk.gray(L('İptal edildi.\n', 'Cancelled.\n')));
31
33
  process.exit(0);
32
34
  }
33
35
  }
34
36
 
35
37
  // Botları çek
36
- console.log(chalk.yellow('⏳ Botlar yükleniyor...\n'));
38
+ console.log(chalk.yellow(L('⏳ Botlar yükleniyor...\n', '⏳ Loading bots...\n')));
37
39
  let botList;
38
40
  try {
39
41
  botList = await getBots(apiKey);
40
42
  } catch (err) {
41
- console.log(chalk.red(`❌ Hata: ${err.message}\n`));
43
+ console.log(chalk.red(`❌ ${L('Hata', 'Error')}: ${err.message}\n`));
42
44
  process.exit(1);
43
45
  }
44
46
 
45
47
  if (!botList || !botList.bots || botList.bots.length === 0) {
46
- console.log(chalk.gray('Bot bulunamadı. Önce https://developers.natureco.me adresinden bot oluşturun.\n'));
48
+ console.log(chalk.gray(L('Bot bulunamadı. Önce https://developers.natureco.me adresinden bot oluşturun.\n', 'No bots found. Create a bot at https://developers.natureco.me first.\n')));
47
49
  process.exit(1);
48
50
  }
49
51
 
@@ -52,7 +54,7 @@ async function init() {
52
54
  {
53
55
  type: 'list',
54
56
  name: 'defaultBot',
55
- message: 'Varsayılan bot:',
57
+ message: L('Varsayılan bot:', 'Default bot:'),
56
58
  choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
57
59
  },
58
60
  ]);
@@ -64,11 +66,11 @@ async function init() {
64
66
  {
65
67
  type: 'checkbox',
66
68
  name: 'skills',
67
- message: 'Hangi skill\'ler eklensin?',
69
+ message: L('Hangi skill\'ler eklensin?', 'Which skills to add?'),
68
70
  choices: [
69
- { name: 'code-review (Kod inceleme)', value: 'code-review', checked: true },
70
- { name: 'summarize (Özetleme)', value: 'summarize', checked: true },
71
- { name: 'translate (Çeviri)', value: 'translate', checked: false },
71
+ { name: L('code-review (Kod inceleme)', 'code-review (Code review)'), value: 'code-review', checked: true },
72
+ { name: L('summarize (Özetleme)', 'summarize (Summarize)'), value: 'summarize', checked: true },
73
+ { name: L('translate (Çeviri)', 'translate (Translate)'), value: 'translate', checked: false },
72
74
  ],
73
75
  },
74
76
  ]);
@@ -95,24 +97,24 @@ async function init() {
95
97
  );
96
98
 
97
99
  // AGENTS.md
98
- const agentsMd = `# ${selectedBot.name} Talimatları
100
+ const agentsMd = `# ${selectedBot.name} ${L('Talimatları', 'Instructions')}
99
101
 
100
- Bu dosya projeye özel bot talimatlarını içerir.
101
- Chat başladığında bu içerik sistem promptuna eklenir.
102
+ ${L('Bu dosya projeye özel bot talimatlarını içerir.', 'This file contains project-specific bot instructions.')}
103
+ ${L('Chat başladığında bu içerik sistem promptuna eklenir.', 'This content is added to the system prompt when chat starts.')}
102
104
 
103
- ## Proje Hakkında
105
+ ## ${L('Proje Hakkında', 'About the Project')}
104
106
 
105
- [Projenizi tanımlayın]
107
+ ${L('[Projenizi tanımlayın]', '[Describe your project]')}
106
108
 
107
- ## Bot Görevleri
109
+ ## ${L('Bot Görevleri', 'Bot Tasks')}
108
110
 
109
- - [Görev 1]
110
- - [Görev 2]
111
+ - ${L('[Görev 1]', '[Task 1]')}
112
+ - ${L('[Görev 2]', '[Task 2]')}
111
113
 
112
- ## Kurallar
114
+ ## ${L('Kurallar', 'Rules')}
113
115
 
114
- - [Kural 1]
115
- - [Kural 2]
116
+ - ${L('[Kural 1]', '[Rule 1]')}
117
+ - ${L('[Kural 2]', '[Rule 2]')}
116
118
  `;
117
119
  fs.writeFileSync(path.join(projectDir, 'AGENTS.md'), agentsMd, 'utf8');
118
120
 
@@ -122,13 +124,13 @@ Chat başladığında bu içerik sistem promptuna eklenir.
122
124
  fs.mkdirSync(skillsDir, { recursive: true });
123
125
  }
124
126
 
125
- console.log(chalk.green('\n✅ Proje başlatıldı!\n'));
126
- console.log(chalk.cyan('Oluşturulan dosyalar:'));
127
+ console.log(chalk.green(L('\n✅ Proje başlatıldı!\n', '\n✅ Project initialized!\n')));
128
+ console.log(chalk.cyan(L('Oluşturulan dosyalar:', 'Created files:')));
127
129
  console.log(chalk.gray(` .natureco/config.json`));
128
130
  console.log(chalk.gray(` .natureco/AGENTS.md`));
129
131
  console.log(chalk.gray(` .natureco/skills/`));
130
132
  console.log('');
131
- console.log(chalk.yellow('Sonraki adım:'), chalk.white(`natureco chat "${selectedBot.name}"`));
133
+ console.log(chalk.yellow(L('Sonraki adım:', 'Next step:')), chalk.white(`natureco chat "${selectedBot.name}"`));
132
134
  console.log('');
133
135
  }
134
136
 
@@ -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');
@@ -109,7 +111,7 @@ const PROVIDER_PRESETS = {
109
111
  default: 'gemini-2.0-flash',
110
112
  },
111
113
  groq: {
112
- name: 'Groq (hızlı + ücretsiz)',
114
+ name: L('Groq (hızlı + ücretsiz)', 'Groq (fast + free)'),
113
115
  url: 'https://api.groq.com/openai/v1',
114
116
  models: [
115
117
  { id: 'llama-3.3-70b-versatile', label: 'Llama 3.3 70B Versatile', tier: 'flagship', desc: 'En güçlü açık', cost: 'FREE' },
@@ -305,8 +307,8 @@ async function cmdWizard() {
305
307
  // Tam NatureCo logosu — brand kimliği
306
308
  for (const line of FULL_LOGO) console.log(COLORS.primary(line));
307
309
  console.log('');
308
- console.log(COLORS.secondary.bold(' ⚡ Setup Wizard — 60 saniyede hazır'));
309
- console.log(COLORS.muted(' Provider seç, API key gir, hemen başla.\n'));
310
+ console.log(COLORS.secondary.bold(L(' ⚡ Setup Wizard — 60 saniyede hazır', ' ⚡ Setup Wizard — ready in 60 seconds')));
311
+ console.log(COLORS.muted(L(' Provider seç, API key gir, hemen başla.\n', ' Pick a provider, enter an API key, start now.\n')));
310
312
 
311
313
  // Ensure directories
312
314
  if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
@@ -350,46 +352,46 @@ async function cmdWizard() {
350
352
  const { modelId } = await inquirer.prompt([{
351
353
  type: 'list',
352
354
  name: 'modelId',
353
- message: ` Model sec (${preset.models.length} secenek):`,
355
+ message: ` ${L('Model sec', 'Select model')} (${preset.models.length} ${L('secenek', 'options')}):`,
354
356
  choices: [
355
357
  { name: '─────────────────────', disabled: true },
356
- { name: '🟢 GÜÇLÜ / REASONING (en iyi)', disabled: true },
358
+ { name: L('🟢 GÜÇLÜ / REASONING (en iyi)', '🟢 POWERFUL / REASONING (best)'), disabled: true },
357
359
  ...preset.models.filter(m => m.tier === 'flagship' || m.tier === 'reasoning').map(m => ({
358
360
  name: ` ${m.label} (${m.cost})`,
359
361
  value: m.id,
360
362
  })),
361
363
  { name: '─────────────────────', disabled: true },
362
- { name: '🟡 ORTA (dengeli)', disabled: true },
364
+ { name: L('🟡 ORTA (dengeli)', '🟡 MID (balanced)'), disabled: true },
363
365
  ...preset.models.filter(m => m.tier === 'balanced').map(m => ({
364
366
  name: ` ${m.label} (${m.cost})`,
365
367
  value: m.id,
366
368
  })),
367
369
  { name: '─────────────────────', disabled: true },
368
- { name: '🔵 HIZLI / UCUZ', disabled: true },
370
+ { name: L('🔵 HIZLI / UCUZ', '🔵 FAST / CHEAP'), disabled: true },
369
371
  ...preset.models.filter(m => m.tier === 'fast').map(m => ({
370
372
  name: ` ${m.label} (${m.cost})`,
371
373
  value: m.id,
372
374
  })),
373
375
  { name: '─────────────────────', disabled: true },
374
- { name: '⚪ KLASİK (legacy)', disabled: true },
376
+ { name: L('⚪ KLASİK (legacy)', '⚪ CLASSIC (legacy)'), disabled: true },
375
377
  ...preset.models.filter(m => m.tier === 'classic').map(m => ({
376
378
  name: ` ${m.label} (${m.cost})`,
377
379
  value: m.id,
378
380
  })),
379
381
  { name: '─────────────────────', disabled: true },
380
- { name: '🔊 ÖZEL (audio/vision/embedding)', disabled: true },
382
+ { name: L('🔊 ÖZEL (audio/vision/embedding)', '🔊 SPECIAL (audio/vision/embedding)'), disabled: true },
381
383
  ...preset.models.filter(m => ['audio', 'vision', 'embedding', 'custom'].includes(m.tier)).map(m => ({
382
384
  name: ` ${m.label} (${m.cost})`,
383
385
  value: m.id,
384
386
  })),
385
387
  { name: '─────────────────────', disabled: true },
386
- { name: '✏️ Custom model adı (ileri düzey)', value: '__custom__' },
388
+ { name: L('✏️ Custom model adı (ileri düzey)', '✏️ Custom model name (advanced)'), value: '__custom__' },
387
389
  ],
388
390
  pageSize: 20,
389
391
  }]);
390
392
 
391
393
  if (modelId === '__custom__') {
392
- providerModel = await rlQuestion(` Model adı: `) || preset.default;
394
+ providerModel = await rlQuestion(` ${L('Model adı', 'Model name')}: `) || preset.default;
393
395
  } else {
394
396
  providerModel = modelId;
395
397
  }
@@ -407,11 +409,11 @@ async function cmdWizard() {
407
409
  const currentKey = cfg.providerApiKey || '';
408
410
  if (currentKey) {
409
411
  console.log('');
410
- console.log(chalk.yellow(' ⚠️ Mevcut API key tespit edildi (son 4 karakter: ' + currentKey.slice(-4) + ')'));
412
+ console.log(chalk.yellow(L(' ⚠️ Mevcut API key tespit edildi (son 4 karakter: ', ' ⚠️ Existing API key detected (last 4 chars: ') + currentKey.slice(-4) + ')'));
411
413
  const reset = await inquirer.prompt([{
412
414
  type: 'confirm',
413
415
  name: 'fresh',
414
- message: 'Sıfırdan yeni kurulum mu yapacaksın? (N = mevcut korunur)',
416
+ message: L('Sıfırdan yeni kurulum mu yapacaksın? (N = mevcut korunur)', 'Start a fresh setup? (N = keep existing)'),
415
417
  default: false,
416
418
  }]);
417
419
  if (reset.fresh) {
@@ -424,39 +426,39 @@ async function cmdWizard() {
424
426
  delete cfg.mattermostBot;
425
427
  delete cfg.smsTwilioSid;
426
428
  delete cfg.webhooks;
427
- console.log(chalk.green(' ✓ Eski ayarlar temizlendi'));
429
+ console.log(chalk.green(L(' ✓ Eski ayarlar temizlendi', ' ✓ Old settings cleared')));
428
430
  }
429
431
  }
430
432
  const apiKey = await rlQuestion(` API Key ${currentKey ? '(leave blank to keep current)' : ''}: `);
431
433
  if (apiKey) {
432
434
  cfg.providerApiKey = apiKey;
433
435
  // v5.6.0: API key dogrula
434
- console.log('\n Doğrulanıyor...');
436
+ console.log(L('\n Doğrulanıyor...', '\n Validating...'));
435
437
  const isValid = await validateApiKey(providerUrl, apiKey);
436
438
  if (!isValid) {
437
- console.log(' ❌ API key gecersiz! Lutfen kontrol edin.');
439
+ console.log(L(' ❌ API key gecersiz! Lutfen kontrol edin.', ' ❌ API key invalid! Please check.'));
438
440
  const retry = await inquirer.prompt([{
439
441
  type: 'confirm',
440
442
  name: 'continue',
441
- message: 'Yine de devam etmek istiyor musunuz? (key sonra duzeltilebilir)',
443
+ message: L('Yine de devam etmek istiyor musunuz? (key sonra duzeltilebilir)', 'Continue anyway? (you can fix the key later)'),
442
444
  default: false,
443
445
  }]);
444
446
  if (!retry.continue) {
445
- console.log(' Setup iptal edildi. Tekrar deneyin: natureco setup');
447
+ console.log(L(' Setup iptal edildi. Tekrar deneyin: natureco setup', ' Setup cancelled. Try again: natureco setup'));
446
448
  process.exit(1);
447
449
  }
448
450
  } else {
449
- console.log(' ✓ API key gecerli!');
451
+ console.log(L(' ✓ API key gecerli!', ' ✓ API key valid!'));
450
452
  }
451
453
  }
452
454
 
453
455
  // Step 3: Bot & User identity
454
456
  console.log('');
455
- console.log(chalk.white(' Step 3: Bot & Kullanıcı'));
457
+ console.log(chalk.white(L(' Step 3: Bot & Kullanıcı', ' Step 3: Bot & User')));
456
458
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
457
- const userName = await rlQuestion(` Sizin adınız: `);
459
+ const userName = await rlQuestion(` ${L('Sizin adınız', 'Your name')}: `);
458
460
  if (userName) cfg.userName = userName;
459
- const botName = await rlQuestion(` Bot adı: `);
461
+ const botName = await rlQuestion(` ${L('Bot adı', 'Bot name')}: `);
460
462
  if (botName) cfg.botName = botName;
461
463
 
462
464
  // v5.6.7: Memory dosyasi yoksa olustur, varsa guncelle
@@ -475,43 +477,43 @@ async function cmdWizard() {
475
477
  if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
476
478
  if (!fs.existsSync(path.dirname(memFile))) fs.mkdirSync(path.dirname(memFile), { recursive: true });
477
479
  fs.writeFileSync(memFile, JSON.stringify(mem, null, 2), 'utf8');
478
- console.log(chalk.gray(' ✓ Memory ' + (memExists ? 'guncellendi' : 'olusturuldu') + ': ' + memFile));
480
+ console.log(chalk.gray(' ✓ Memory ' + (memExists ? L('guncellendi', 'updated') : L('olusturuldu', 'created')) + ': ' + memFile));
479
481
  }
480
482
  } catch (e) {
481
- console.log(chalk.gray(' ! Memory yazilamadi: ' + e.message));
483
+ console.log(chalk.gray(L(' ! Memory yazilamadi: ', ' ! Could not write memory: ') + e.message));
482
484
  }
483
485
 
484
486
  // Step 4: Kanal Entegrasyonları (isteğe bağlı, isteyen atlayabilir)
485
487
  console.log('');
486
- console.log(chalk.white(' Step 4: Kanal Entegrasyonları (opsiyonel)'));
488
+ console.log(chalk.white(L(' Step 4: Kanal Entegrasyonları (opsiyonel)', ' Step 4: Channel Integrations (optional)')));
487
489
  console.log(chalk.gray(' ─────────────────────────────────────────────'));
488
- console.log(chalk.gray(' Telegram, WhatsApp, Discord, Slack bağlamak ister misiniz?'));
489
- console.log(chalk.gray(' Atlamak için hepsini boş bırakın, sonra: natureco <kanal> connect\n'));
490
+ console.log(chalk.gray(L(' Telegram, WhatsApp, Discord, Slack bağlamak ister misiniz?', ' Connect Telegram, WhatsApp, Discord, Slack?')));
491
+ console.log(chalk.gray(L(' Atlamak için hepsini boş bırakın, sonra: natureco <kanal> connect\n', ' To skip, leave all blank, then: natureco <channel> connect\n')));
490
492
 
491
493
  const integrations = [
492
- { key: 'telegramToken', name: 'Telegram', hint: 'BotFather\'dan al (@BotFather → /newbot → token)' },
493
- { key: 'whatsappPhone', name: 'WhatsApp', hint: 'Telefon numaranızı girin (örn: +905422842631)' },
494
+ { key: 'telegramToken', name: 'Telegram', hint: L('BotFather\'dan al (@BotFather → /newbot → token)', 'Get it from BotFather (@BotFather → /newbot → token)') },
495
+ { key: 'whatsappPhone', name: 'WhatsApp', hint: L('Telefon numaranızı girin (örn: +905422842631)', 'Enter your phone number (e.g. +905422842631)') },
494
496
  { key: 'discordToken', name: 'Discord', hint: 'Discord bot token (Discord Developer Portal)' },
495
497
  { key: 'slackToken', name: 'Slack', hint: 'Slack bot token (api.slack.com/apps)' },
496
- { key: 'signalBotId', name: 'Signal', hint: 'Signal bot numarası veya ID' },
497
- { key: 'ircBotId', name: 'IRC', hint: 'IRC bot kullanıcı adı (örn: NatureCoBot)' },
498
- { key: 'mattermostBotId', name: 'Mattermost', hint: 'Mattermost bot kullanıcı adı' },
499
- { key: 'imessageBotId', name: 'iMessage', hint: 'iMessage bridge endpoint veya ad' },
500
- { key: 'smsBotId', name: 'SMS (Twilio)', hint: 'Twilio hesap SID veya bot ID' },
501
- { key: 'webhooks', name: 'Webhooks', hint: 'Webhook URL (veya boş bırakın, sonra: natureco webhooks add)' },
498
+ { key: 'signalBotId', name: 'Signal', hint: L('Signal bot numarası veya ID', 'Signal bot number or ID') },
499
+ { key: 'ircBotId', name: 'IRC', hint: L('IRC bot kullanıcı adı (örn: NatureCoBot)', 'IRC bot username (e.g. NatureCoBot)') },
500
+ { key: 'mattermostBotId', name: 'Mattermost', hint: L('Mattermost bot kullanıcı adı', 'Mattermost bot username') },
501
+ { key: 'imessageBotId', name: 'iMessage', hint: L('iMessage bridge endpoint veya ad', 'iMessage bridge endpoint or name') },
502
+ { key: 'smsBotId', name: 'SMS (Twilio)', hint: L('Twilio hesap SID veya bot ID', 'Twilio account SID or bot ID') },
503
+ { key: 'webhooks', name: 'Webhooks', hint: L('Webhook URL (veya boş bırakın, sonra: natureco webhooks add)', 'Webhook URL (or leave blank, then: natureco webhooks add)') },
502
504
  ];
503
505
 
504
506
  for (const integ of integrations) {
505
507
  const current = cfg[integ.key] || '';
506
508
  if (current) {
507
- console.log(chalk.gray(` ${integ.name}: zaten ayarlı, boş bırakırsanız korunur`));
509
+ console.log(chalk.gray(` ${integ.name}: ${L('zaten ayarlı, boş bırakırsanız korunur', 'already set, leave blank to keep')}`));
508
510
  } else {
509
511
  console.log(chalk.gray(` ${integ.hint}`));
510
512
  }
511
- const val = await rlQuestion(` ${integ.name} ${current ? '(mevcut - boş bırakın)' : '(boş = atla)'}: `);
513
+ const val = await rlQuestion(` ${integ.name} ${current ? L('(mevcut - boş bırakın)', '(current - leave blank)') : L('(boş = atla)', '(blank = skip)')}: `);
512
514
  if (val) {
513
515
  cfg[integ.key] = val;
514
- console.log(chalk.green(` ✓ ${integ.name} ayarlandı`));
516
+ console.log(chalk.green(` ✓ ${integ.name} ${L('ayarlandı', 'set')}`));
515
517
  }
516
518
  }
517
519
 
@@ -533,8 +535,8 @@ async function cmdWizard() {
533
535
  console.log('');
534
536
  console.log(chalk.white(' Next steps:'));
535
537
  console.log(chalk.cyan(' natureco chat Start chatting'));
536
- console.log(chalk.cyan(' natureco repl İnteraktif REPL (persistent memory)'));
537
- console.log(chalk.cyan(' natureco telegram connect Telegram bot bağla (henüz yapılmadıysa)'));
538
+ console.log(chalk.cyan(L(' natureco repl İnteraktif REPL (persistent memory)', ' natureco repl Interactive REPL (persistent memory)')));
539
+ console.log(chalk.cyan(L(' natureco telegram connect Telegram bot bağla (henüz yapılmadıysa)', ' natureco telegram connect Connect Telegram bot (if not done yet)')));
538
540
  console.log(chalk.cyan(' natureco help View all commands'));
539
541
  console.log('');
540
542
  }
@@ -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 F = require('../utils/format');
3
5
  const tui = require('../utils/tui');
4
6
  const fs = require('fs');
@@ -40,8 +42,8 @@ function cmdRun() {
40
42
  const pidFile = path.join(os.homedir(), '.natureco', 'gateway.pid');
41
43
  const gatewayRunning = fs.existsSync(pidFile);
42
44
  const gatewayStatus = gatewayRunning
43
- ? tui.styled(' ✓ Çalışıyor ', { bg: tui.PALETTE.success, color: '#000', bold: true })
44
- : tui.styled(' ✗ Durmuş ', { bg: tui.PALETTE.muted, color: '#000', bold: true });
45
+ ? tui.styled(L(' ✓ Çalışıyor ', ' ✓ Running '), { bg: tui.PALETTE.success, color: '#000', bold: true })
46
+ : tui.styled(L(' ✗ Durmuş ', ' ✗ Stopped '), { bg: tui.PALETTE.muted, color: '#000', bold: true });
45
47
  lines.push(tui.styled(' │ ', { color: tui.PALETTE.border }) + tui.C.muted('Gateway ') + gatewayStatus + ' '.repeat(23) + tui.styled(' │', { color: tui.PALETTE.border }));
46
48
 
47
49
  if (cfg.providerUrl) {
@@ -70,7 +72,7 @@ function cmdRun() {
70
72
  const all = getSkills();
71
73
  const builtin = all.filter(s => s.source === 'builtin').length;
72
74
  const user = all.length - builtin;
73
- skillInfo = `${all.length} (${builtin} yerleşik` + (user > 0 ? ` + ${user} kullanıcı` : '') + ')';
75
+ skillInfo = `${all.length} (${builtin} ${L('yerleşik', 'built-in')}` + (user > 0 ? ` + ${user} ${L('kullanıcı', 'user')}` : '') + ')';
74
76
  }
75
77
  } catch {}
76
78
  lines.push(tui.styled(' │ ', { color: tui.PALETTE.border }) + tui.C.muted('Skills ') + tui.styled(skillInfo.padEnd(36), { color: tui.PALETTE.text }) + tui.styled(' │', { color: tui.PALETTE.border }));
@@ -83,7 +85,7 @@ function cmdRun() {
83
85
  lines.push(tui.styled(' │ ', { color: tui.PALETTE.border }) + tui.C.muted('Tools ') + tui.styled(String(toolCount).padEnd(36), { color: tui.PALETTE.text }) + tui.styled(' │', { color: tui.PALETTE.border }));
84
86
 
85
87
  lines.push(tui.styled(' ╰' + '─'.repeat(cardW) + '╯', { color: tui.PALETTE.border }));
86
- console.log('\n' + tui.styled(' 🩺 Sistem Durumu', { color: tui.PALETTE.primary, bold: true }));
88
+ console.log('\n' + tui.styled(L(' 🩺 Sistem Durumu', ' 🩺 System Status'), { color: tui.PALETTE.primary, bold: true }));
87
89
  console.log(lines.join('\n'));
88
90
  console.log('');
89
91
  }
@@ -113,7 +115,7 @@ function cmdUsage() {
113
115
  const cfg = config ? config.getConfig() : {};
114
116
 
115
117
  if (!cfg.providerUrl) {
116
- console.log('\n' + tui.C.muted(' Provider tanımlı değil.'));
118
+ console.log('\n' + tui.C.muted(L(' Provider tanımlı değil.', ' Provider not set.')));
117
119
  return;
118
120
  }
119
121
 
@@ -126,10 +128,10 @@ function cmdUsage() {
126
128
  { key: 'session', label: 'Session', value: String(usage.sessionTokens || '—') },
127
129
  ];
128
130
 
129
- console.log('\n' + tui.styled(' 📊 Provider Kullanımı', { color: tui.PALETTE.primary, bold: true }));
131
+ console.log('\n' + tui.styled(L(' 📊 Provider Kullanımı', ' 📊 Provider Usage'), { color: tui.PALETTE.primary, bold: true }));
130
132
  console.log('\n' + tui.table(rows, [
131
- { key: 'key', label: 'Anahtar', minWidth: 12, render: r => tui.C.muted(r.key) },
132
- { key: 'value', label: 'Değer', minWidth: 30, render: r => tui.C.text(r.value) },
133
+ { key: 'key', label: L('Anahtar', 'Key'), minWidth: 12, render: r => tui.C.muted(r.key) },
134
+ { key: 'value', label: L('Değer', 'Value'), minWidth: 30, render: r => tui.C.text(r.value) },
133
135
  ], { borderStyle: 'round', zebra: true }));
134
136
  console.log('');
135
137
  }