natureco-cli 5.58.0 → 5.60.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.60.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
 
@@ -14,6 +14,8 @@
14
14
  */
15
15
 
16
16
  const chalk = require('chalk');
17
+ const { getLang: _gl } = require('../utils/i18n');
18
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
17
19
  const fs = require('fs');
18
20
  const path = require('path');
19
21
  const os = require('os');
@@ -30,7 +32,7 @@ function getToken() {
30
32
 
31
33
  async function apiCall(endpoint, options = {}) {
32
34
  const token = getToken();
33
- if (!token) throw new Error('Medium integration token tanımlı değil');
35
+ if (!token) throw new Error(L('Medium integration token tanımlı değil', 'Medium integration token not set'));
34
36
  return new Promise((resolve, reject) => {
35
37
  const url = new URL(endpoint, API_BASE);
36
38
  const req = https.request({
@@ -74,68 +76,68 @@ function parseMarkdown(content) {
74
76
  }
75
77
  body.push(line);
76
78
  }
77
- return { title: title || 'Başlıksız', content: body.join('\n').trim() };
79
+ return { title: title || L('Başlıksız', 'Untitled'), content: body.join('\n').trim() };
78
80
  }
79
81
 
80
82
  async function cmdDraft(args) {
81
83
  const filePath = args[0];
82
84
  if (!filePath) {
83
- console.log(chalk.red('\n Kullanım: natureco medium draft <dosya.md>\n'));
85
+ console.log(chalk.red(L('\n Kullanım: natureco medium draft <dosya.md>\n', '\n Usage: natureco medium draft <file.md>\n')));
84
86
  return;
85
87
  }
86
88
  if (!fs.existsSync(filePath)) {
87
- console.log(chalk.red(`\n Dosya bulunamadı: ${filePath}\n`));
89
+ console.log(chalk.red(`\n ${L('Dosya bulunamadı', 'File not found')}: ${filePath}\n`));
88
90
  return;
89
91
  }
90
92
 
91
93
  const content = fs.readFileSync(filePath, 'utf8');
92
94
  const { title, content: body } = parseMarkdown(content);
93
95
 
94
- console.log(chalk.cyan('\n 📝 Taslak hazırlanıyor...\n'));
95
- console.log(chalk.gray(` Başlık: ${title}`));
96
- console.log(chalk.gray(` Uzunluk: ${body.length} karakter, ${body.split(/\s+/).length} kelime`));
96
+ console.log(chalk.cyan(L('\n 📝 Taslak hazırlanıyor...\n', '\n 📝 Preparing draft...\n')));
97
+ console.log(chalk.gray(` ${L('Başlık', 'Title')}: ${title}`));
98
+ console.log(chalk.gray(` ${L('Uzunluk', 'Length')}: ${body.length} ${L('karakter', 'chars')}, ${body.split(/\s+/).length} ${L('kelime', 'words')}`));
97
99
 
98
100
  const token = getToken();
99
101
  if (!token) {
100
- console.log(chalk.yellow('\n ⚠️ Medium token tanımlı değil.'));
101
- console.log(chalk.gray(' Ayarlamak için: ') + chalk.cyan('natureco config set mediumIntegrationToken <token>'));
102
- console.log(chalk.gray('\n Token almak için: ') + chalk.cyan('https://medium.com/me/settings/tokens'));
102
+ console.log(chalk.yellow(L('\n ⚠️ Medium token tanımlı değil.', '\n ⚠️ Medium token not set.')));
103
+ console.log(chalk.gray(L(' Ayarlamak için: ', ' To set: ')) + chalk.cyan('natureco config set mediumIntegrationToken <token>'));
104
+ console.log(chalk.gray(L('\n Token almak için: ', '\n To get a token: ')) + chalk.cyan('https://medium.com/me/settings/tokens'));
103
105
  console.log('');
104
106
  // Yerel taslak kaydet
105
107
  const draftDir = path.join(os.homedir(), '.natureco', 'medium-drafts');
106
108
  if (!fs.existsSync(draftDir)) fs.mkdirSync(draftDir, { recursive: true });
107
109
  const draftFile = path.join(draftDir, `${Date.now()}-${path.basename(filePath, '.md')}.json`);
108
110
  fs.writeFileSync(draftFile, JSON.stringify({ title, body, source: filePath, createdAt: new Date().toISOString() }, null, 2));
109
- console.log(chalk.green(` ✓ Taslak yerel olarak kaydedildi: ${draftFile}\n`));
111
+ console.log(chalk.green(` ✓ ${L('Taslak yerel olarak kaydedildi', 'Draft saved locally')}: ${draftFile}\n`));
110
112
  return;
111
113
  }
112
114
 
113
115
  try {
114
116
  const user = await apiCall('/me');
115
117
  const userId = user.data?.id;
116
- if (!userId) throw new Error('User ID alınamadı');
118
+ if (!userId) throw new Error(L('User ID alınamadı', 'Could not get User ID'));
117
119
 
118
120
  const result = await apiCall(`/users/${userId}/posts`, {
119
121
  method: 'POST',
120
122
  body: { title, contentFormat: 'markdown', content: body, publishStatus: 'draft' },
121
123
  });
122
- console.log(chalk.green('\n ✓ Medium\'a taslak yüklendi!'));
124
+ console.log(chalk.green(L('\n ✓ Medium\'a taslak yüklendi!', '\n ✓ Draft uploaded to Medium!')));
123
125
  if (result.data?.url) console.log(chalk.cyan(` 🔗 ${result.data.url}\n`));
124
126
  audit.log(audit.ACTIONS.INFO, { source: 'medium', action: 'draft', url: result.data?.url });
125
127
  } catch (e) {
126
- console.log(chalk.yellow(`\n ⚠️ API hatası: ${e.message}`));
127
- console.log(chalk.gray(' Token\'ı kontrol et veya mediumIntegrationToken ayarla.\n'));
128
+ console.log(chalk.yellow(`\n ⚠️ ${L('API hatası', 'API error')}: ${e.message}`));
129
+ console.log(chalk.gray(L(' Token\'ı kontrol et veya mediumIntegrationToken ayarla.\n', ' Check the token or set mediumIntegrationToken.\n')));
128
130
  }
129
131
  }
130
132
 
131
133
  async function cmdPublish(args) {
132
134
  const filePath = args[0];
133
135
  if (!filePath) {
134
- console.log(chalk.red('\n Kullanım: natureco medium publish <dosya.md>\n'));
136
+ console.log(chalk.red(L('\n Kullanım: natureco medium publish <dosya.md>\n', '\n Usage: natureco medium publish <file.md>\n')));
135
137
  return;
136
138
  }
137
139
  if (!fs.existsSync(filePath)) {
138
- console.log(chalk.red(`\n Dosya bulunamadı: ${filePath}\n`));
140
+ console.log(chalk.red(`\n ${L('Dosya bulunamadı', 'File not found')}: ${filePath}\n`));
139
141
  return;
140
142
  }
141
143
 
@@ -144,12 +146,12 @@ async function cmdPublish(args) {
144
146
 
145
147
  const token = getToken();
146
148
  if (!token) {
147
- console.log(chalk.red('\n ❌ Medium token tanımlı değil.\n'));
148
- console.log(chalk.gray(' Yayınlamak için mediumIntegrationToken gerekli.\n'));
149
+ console.log(chalk.red(L('\n ❌ Medium token tanımlı değil.\n', '\n ❌ Medium token not set.\n')));
150
+ console.log(chalk.gray(L(' Yayınlamak için mediumIntegrationToken gerekli.\n', ' mediumIntegrationToken required to publish.\n')));
149
151
  return;
150
152
  }
151
153
 
152
- console.log(chalk.yellow(`\n ⚠️ "${title}" Medium'da YAYINLANACAK.\n`));
154
+ console.log(chalk.yellow(`\n ⚠️ "${title}" ${L("Medium'da YAYINLANACAK.", 'WILL BE PUBLISHED on Medium.')}\n`));
153
155
 
154
156
  try {
155
157
  const user = await apiCall('/me');
@@ -158,22 +160,22 @@ async function cmdPublish(args) {
158
160
  method: 'POST',
159
161
  body: { title, contentFormat: 'markdown', content: body, publishStatus: 'public' },
160
162
  });
161
- console.log(chalk.green('\n ✓ Yayınlandı!'));
163
+ console.log(chalk.green(L('\n ✓ Yayınlandı!', '\n ✓ Published!')));
162
164
  if (result.data?.url) console.log(chalk.cyan(` 🔗 ${result.data.url}\n`));
163
165
  audit.log(audit.ACTIONS.INFO, { source: 'medium', action: 'publish', url: result.data?.url });
164
166
  } catch (e) {
165
- console.log(chalk.red(`\n ❌ Yayınlama başarısız: ${e.message}\n`));
167
+ console.log(chalk.red(`\n ❌ ${L('Yayınlama başarısız', 'Publish failed')}: ${e.message}\n`));
166
168
  }
167
169
  }
168
170
 
169
171
  function cmdList() {
170
172
  const draftDir = path.join(os.homedir(), '.natureco', 'medium-drafts');
171
173
  if (!fs.existsSync(draftDir)) {
172
- console.log(chalk.gray('\n Henüz taslak yok.\n'));
174
+ console.log(chalk.gray(L('\n Henüz taslak yok.\n', '\n No drafts yet.\n')));
173
175
  return;
174
176
  }
175
177
  const files = fs.readdirSync(draftDir).sort().reverse();
176
- console.log(chalk.cyan('\n 📚 Medium Taslakları\n'));
178
+ console.log(chalk.cyan(L('\n 📚 Medium Taslakları\n', '\n 📚 Medium Drafts\n')));
177
179
  for (const f of files) {
178
180
  const filePath = path.join(draftDir, f);
179
181
  try {
@@ -189,18 +191,18 @@ function cmdList() {
189
191
  async function medium(args) {
190
192
  const [action, ...params] = args || [];
191
193
  if (!action || action === 'help') {
192
- console.log(chalk.yellow('\n Kullanım:'));
193
- console.log(chalk.gray(' natureco medium draft <file.md> Taslak oluştur'));
194
- console.log(chalk.gray(' natureco medium publish <file.md> Doğrudan yayınla'));
195
- console.log(chalk.gray(' natureco medium list Taslaklar'));
196
- console.log(chalk.gray('\n Token ayarla: ') + chalk.cyan('natureco config set mediumIntegrationToken <token>'));
194
+ console.log(chalk.yellow(L('\n Kullanım:', '\n Usage:')));
195
+ console.log(chalk.gray(L(' natureco medium draft <file.md> Taslak oluştur', ' natureco medium draft <file.md> Create draft')));
196
+ console.log(chalk.gray(L(' natureco medium publish <file.md> Doğrudan yayınla', ' natureco medium publish <file.md> Publish directly')));
197
+ console.log(chalk.gray(L(' natureco medium list Taslaklar', ' natureco medium list Drafts')));
198
+ console.log(chalk.gray(L('\n Token ayarla: ', '\n Set token: ')) + chalk.cyan('natureco config set mediumIntegrationToken <token>'));
197
199
  console.log('');
198
200
  return;
199
201
  }
200
202
  if (action === 'draft') return cmdDraft(params);
201
203
  if (action === 'publish') return cmdPublish(params);
202
204
  if (action === 'list') return cmdList();
203
- console.log(chalk.red(`\n Bilinmeyen: ${action}\n`));
205
+ console.log(chalk.red(`\n ${L('Bilinmeyen', 'Unknown')}: ${action}\n`));
204
206
  }
205
207
 
206
208
  module.exports = medium;