natureco-cli 5.57.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.57.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
- 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 tui = require('../utils/tui');
3
5
  const F = require('../utils/format');
4
6
  const fs = require('fs');
@@ -40,8 +42,8 @@ function saveCrons(crons) {
40
42
 
41
43
  async function cron(action, options) {
42
44
  if (!action || !['add', 'list', 'remove', 'get', 'edit', 'enable', 'disable', 'runs', 'run'].includes(action)) {
43
- console.log(chalk.red('\n❌ Geçersiz aksiyon\n'));
44
- console.log(chalk.gray('Kullanım:'));
45
+ console.log(chalk.red(L('\n❌ Geçersiz aksiyon\n', '\n❌ Invalid action\n')));
46
+ console.log(chalk.gray(L('Kullanım:', 'Usage:')));
45
47
  console.log(chalk.cyan(' natureco cron add --name <name> --schedule <cron> --action <channel> --target <target> --prompt <prompt>'));
46
48
  console.log(chalk.cyan(' natureco cron list'));
47
49
  console.log(chalk.cyan(' natureco cron get <name>'));
@@ -51,8 +53,8 @@ async function cron(action, options) {
51
53
  console.log(chalk.cyan(' natureco cron disable <name>'));
52
54
  console.log(chalk.cyan(' natureco cron runs <name>'));
53
55
  console.log(chalk.cyan(' natureco cron run <name>'));
54
- console.log(chalk.gray('\nÖrnek:'));
55
- console.log(chalk.cyan(' natureco cron add --name "bitcoin-fiyat" --schedule "0 9 * * *" --action "whatsapp" --target "+905422842631" --prompt "Bugünkü Bitcoin fiyatını öğren ve kısaca bildir"\n'));
56
+ console.log(chalk.gray(L('\nÖrnek:', '\nExample:')));
57
+ console.log(chalk.cyan(L(' natureco cron add --name "bitcoin-fiyat" --schedule "0 9 * * *" --action "whatsapp" --target "+905422842631" --prompt "Bugünkü Bitcoin fiyatını öğren ve kısaca bildir"\n', ' natureco cron add --name "bitcoin-price" --schedule "0 9 * * *" --action "whatsapp" --target "+905422842631" --prompt "Get today\'s Bitcoin price and report briefly"\n')));
56
58
  process.exit(1);
57
59
  }
58
60
 
@@ -81,13 +83,13 @@ async function addCron(options) {
81
83
  const { name, schedule, action, target, prompt } = options;
82
84
 
83
85
  if (!name || !schedule || !action || !target || !prompt) {
84
- console.log(chalk.red('\n❌ Eksik parametre\n'));
85
- console.log(chalk.gray('Gerekli parametreler: --name, --schedule, --action, --target, --prompt\n'));
86
+ console.log(chalk.red(L('\n❌ Eksik parametre\n', '\n❌ Missing parameter\n')));
87
+ console.log(chalk.gray(L('Gerekli parametreler: --name, --schedule, --action, --target, --prompt\n', 'Required parameters: --name, --schedule, --action, --target, --prompt\n')));
86
88
  process.exit(1);
87
89
  }
88
90
 
89
91
  if (!['whatsapp', 'telegram'].includes(action)) {
90
- console.log(chalk.red('\n❌ Geçersiz action. Sadece "whatsapp" veya "telegram" kullanılabilir\n'));
92
+ console.log(chalk.red(L('\n❌ Geçersiz action. Sadece "whatsapp" veya "telegram" kullanılabilir\n', '\n❌ Invalid action. Only "whatsapp" or "telegram" can be used\n')));
91
93
  process.exit(1);
92
94
  }
93
95
 
@@ -95,13 +97,13 @@ async function addCron(options) {
95
97
  try {
96
98
  const nodeCron = require('node-cron');
97
99
  if (!nodeCron.validate(schedule)) {
98
- console.log(chalk.red('\n❌ Geçersiz cron ifadesi\n'));
99
- console.log(chalk.gray('Örnek: "0 9 * * *" (her gün saat 09:00)\n'));
100
+ console.log(chalk.red(L('\n❌ Geçersiz cron ifadesi\n', '\n❌ Invalid cron expression\n')));
101
+ console.log(chalk.gray(L('Örnek: "0 9 * * *" (her gün saat 09:00)\n', 'Example: "0 9 * * *" (every day at 09:00)\n')));
100
102
  process.exit(1);
101
103
  }
102
104
  } catch (err) {
103
- console.log(chalk.red('\n❌ node-cron yüklü değil\n'));
104
- console.log(chalk.yellow('Yüklemek için:'), chalk.cyan('npm install -g node-cron\n'));
105
+ console.log(chalk.red(L('\n❌ node-cron yüklü değil\n', '\n❌ node-cron not installed\n')));
106
+ console.log(chalk.yellow(L('Yüklemek için:', 'To install:')), chalk.cyan('npm install -g node-cron\n'));
105
107
  process.exit(1);
106
108
  }
107
109
 
@@ -109,8 +111,8 @@ async function addCron(options) {
109
111
 
110
112
  // Check if name already exists
111
113
  if (crons.find(c => c.name === name)) {
112
- console.log(chalk.red('\n❌ Bu isimde bir cron zaten var\n'));
113
- console.log(chalk.yellow('Önce silin:'), chalk.cyan(`natureco cron remove --name "${name}"\n`));
114
+ console.log(chalk.red(L('\n❌ Bu isimde bir cron zaten var\n', '\n❌ A cron with this name already exists\n')));
115
+ console.log(chalk.yellow(L('Önce silin:', 'Delete it first:')), chalk.cyan(`natureco cron remove --name "${name}"\n`));
114
116
  process.exit(1);
115
117
  }
116
118
 
@@ -127,24 +129,24 @@ async function addCron(options) {
127
129
  crons.push(newCron);
128
130
  saveCrons(crons);
129
131
 
130
- console.log(chalk.green('\n✅ Cron eklendi!\n'));
131
- console.log(chalk.cyan('İsim:'), chalk.white(name));
132
- console.log(chalk.cyan('Zamanlama:'), chalk.white(schedule));
133
- console.log(chalk.cyan('Kanal:'), chalk.white(action));
134
- console.log(chalk.cyan('Hedef:'), chalk.white(target));
132
+ console.log(chalk.green(L('\n✅ Cron eklendi!\n', '\n✅ Cron added!\n')));
133
+ console.log(chalk.cyan(L('İsim:', 'Name:')), chalk.white(name));
134
+ console.log(chalk.cyan(L('Zamanlama:', 'Schedule:')), chalk.white(schedule));
135
+ console.log(chalk.cyan(L('Kanal:', 'Channel:')), chalk.white(action));
136
+ console.log(chalk.cyan(L('Hedef:', 'Target:')), chalk.white(target));
135
137
  console.log(chalk.cyan('Prompt:'), chalk.white(prompt));
136
- console.log(chalk.gray('\nCron\'lar gateway başlatıldığında aktif olur.'));
137
- console.log(chalk.gray('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start\n'));
138
+ console.log(chalk.gray(L('\nCron\'lar gateway başlatıldığında aktif olur.', '\nCrons become active when the gateway starts.')));
139
+ console.log(chalk.gray(L('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start\n', 'If the gateway is running, restart it: natureco gateway stop && natureco gateway start\n')));
138
140
  }
139
141
 
140
142
  function listCrons() {
141
143
  const crons = loadCrons();
142
144
 
143
145
  if (crons.length === 0) {
144
- console.log('\n' + tui.styled(' ⏰ Zamanlanmış Görevler', { color: tui.PALETTE.primary, bold: true }));
146
+ console.log('\n' + tui.styled(L(' ⏰ Zamanlanmış Görevler', ' ⏰ Scheduled Tasks'), { color: tui.PALETTE.primary, bold: true }));
145
147
  console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
146
- console.log('\n ' + tui.C.muted('Henüz cron tanımlı değil. Eklemek için:'));
147
- console.log(' ' + tui.C.brand('natureco cron add --name "görev" --schedule "0 9 * * *" --action telegram --prompt "..."'));
148
+ console.log('\n ' + tui.C.muted(L('Henüz cron tanımlı değil. Eklemek için:', 'No crons defined yet. To add:')));
149
+ console.log(' ' + tui.C.brand(L('natureco cron add --name "görev" --schedule "0 9 * * *" --action telegram --prompt "..."', 'natureco cron add --name "task" --schedule "0 9 * * *" --action telegram --prompt "..."')));
148
150
  console.log('');
149
151
  return;
150
152
  }
@@ -177,16 +179,16 @@ function listCrons() {
177
179
  console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
178
180
 
179
181
  console.log('\n' + tui.table(rows, [
180
- { key: 'name', label: 'İsim', minWidth: 20, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
181
- { key: 'schedule', label: 'Zamanlama', minWidth: 18, render: r => tui.C.muted(r.schedule) },
182
+ { key: 'name', label: L('İsim', 'Name'), minWidth: 20, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
183
+ { key: 'schedule', label: L('Zamanlama', 'Schedule'), minWidth: 18, render: r => tui.C.muted(r.schedule) },
182
184
  {
183
- key: 'status', label: 'Durum', minWidth: 10,
185
+ key: 'status', label: L('Durum', 'Status'), minWidth: 10,
184
186
  render: r => r.status
185
- ? tui.styled(' ✓ Aktif ', { bg: tui.PALETTE.success, color: '#000', bold: true })
186
- : tui.styled(' ✗ Pasif ', { bg: tui.PALETTE.muted, color: '#000', bold: true }),
187
+ ? tui.styled(L(' ✓ Aktif ', ' ✓ Active '), { bg: tui.PALETTE.success, color: '#000', bold: true })
188
+ : tui.styled(L(' ✗ Pasif ', ' ✗ Inactive '), { bg: tui.PALETTE.muted, color: '#000', bold: true }),
187
189
  },
188
- { key: 'target', label: 'Hedef', minWidth: 18, render: r => tui.C.text(r.target) },
189
- { key: 'lastRun', label: 'Son Çalışma', minWidth: 18, render: r => tui.C.muted(r.lastRun) },
190
+ { key: 'target', label: L('Hedef', 'Target'), minWidth: 18, render: r => tui.C.text(r.target) },
191
+ { key: 'lastRun', label: L('Son Çalışma', 'Last Run'), minWidth: 18, render: r => tui.C.muted(r.lastRun) },
190
192
  ], { borderStyle: 'round', zebra: true }));
191
193
 
192
194
  console.log('');
@@ -196,7 +198,7 @@ function removeCron(options) {
196
198
  const { name } = options;
197
199
 
198
200
  if (!name) {
199
- F.error('--name parametresi gerekli');
201
+ F.error(L('--name parametresi gerekli', '--name parameter required'));
200
202
  process.exit(1);
201
203
  }
202
204
 
@@ -204,39 +206,39 @@ function removeCron(options) {
204
206
  const index = crons.findIndex(c => c.name === name);
205
207
 
206
208
  if (index === -1) {
207
- F.error('Bu isimde bir cron bulunamadı');
209
+ F.error(L('Bu isimde bir cron bulunamadı', 'No cron found with this name'));
208
210
  process.exit(1);
209
211
  }
210
212
 
211
213
  crons.splice(index, 1);
212
214
  saveCrons(crons);
213
215
 
214
- F.success('Cron silindi!');
215
- F.meta('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start');
216
+ F.success(L('Cron silindi!', 'Cron deleted!'));
217
+ F.meta(L('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start', 'If the gateway is running, restart it: natureco gateway stop && natureco gateway start'));
216
218
  }
217
219
 
218
220
  function getCron(options) {
219
221
  const { name } = options;
220
222
  if (!name) {
221
- F.error('Cron adı gerekli. Kullanım: natureco cron get <name>');
223
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron get <name>', 'Cron name required. Usage: natureco cron get <name>'));
222
224
  process.exit(1);
223
225
  }
224
226
 
225
227
  const crons = loadCrons();
226
228
  const cron = crons.find(c => c.name === name);
227
229
  if (!cron) {
228
- F.error('"' + name + '" isminde bir cron bulunamadı');
230
+ F.error('"' + name + L('" isminde bir cron bulunamadı', '" — no cron found with this name'));
229
231
  process.exit(1);
230
232
  }
231
233
 
232
234
  F.header('Cron: ' + cron.name);
233
- F.kv('İsim', cron.name);
234
- F.kv('Zamanlama', cron.schedule);
235
- F.kv('Kanal', cron.action);
236
- F.kv('Hedef', cron.target);
235
+ F.kv(L('İsim', 'Name'), cron.name);
236
+ F.kv(L('Zamanlama', 'Schedule'), cron.schedule);
237
+ F.kv(L('Kanal', 'Channel'), cron.action);
238
+ F.kv(L('Hedef', 'Target'), cron.target);
237
239
  F.kv('Prompt', cron.prompt);
238
- F.kv('Oluşturulma', cron.createdAt);
239
- F.kv('Durum', cron.enabled ? 'Aktif' : 'Pasif');
240
+ F.kv(L('Oluşturulma', 'Created'), cron.createdAt);
241
+ F.kv(L('Durum', 'Status'), cron.enabled ? L('Aktif', 'Active') : L('Pasif', 'Inactive'));
240
242
  }
241
243
 
242
244
  function editCron(options) {
@@ -244,14 +246,14 @@ function editCron(options) {
244
246
  const newName = options['newName'];
245
247
 
246
248
  if (!name) {
247
- F.error('Cron adı gerekli. Kullanım: natureco cron edit <name> [--name <newName>] [--schedule <cron>] [--action <channel>] [--target <target>] [--prompt <prompt>]');
249
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron edit <name> [--name <newName>] [--schedule <cron>] [--action <channel>] [--target <target>] [--prompt <prompt>]', 'Cron name required. Usage: natureco cron edit <name> [--name <newName>] [--schedule <cron>] [--action <channel>] [--target <target>] [--prompt <prompt>]'));
248
250
  process.exit(1);
249
251
  }
250
252
 
251
253
  const crons = loadCrons();
252
254
  const cron = crons.find(c => c.name === name);
253
255
  if (!cron) {
254
- F.error('"' + name + '" isminde bir cron bulunamadı');
256
+ F.error('"' + name + L('" isminde bir cron bulunamadı', '" — no cron found with this name'));
255
257
  process.exit(1);
256
258
  }
257
259
 
@@ -260,18 +262,18 @@ function editCron(options) {
260
262
  try {
261
263
  const nodeCron = require('node-cron');
262
264
  if (!nodeCron.validate(schedule)) {
263
- F.error('Geçersiz cron ifadesi');
265
+ F.error(L('Geçersiz cron ifadesi', 'Invalid cron expression'));
264
266
  process.exit(1);
265
267
  }
266
268
  } catch (err) {
267
- F.error('node-cron yüklü değil');
269
+ F.error(L('node-cron yüklü değil', 'node-cron not installed'));
268
270
  process.exit(1);
269
271
  }
270
272
  cron.schedule = schedule;
271
273
  }
272
274
  if (action) {
273
275
  if (!['whatsapp', 'telegram'].includes(action)) {
274
- F.error('Geçersiz action. Sadece "whatsapp" veya "telegram" kullanılabilir');
276
+ F.error(L('Geçersiz action. Sadece "whatsapp" veya "telegram" kullanılabilir', 'Invalid action. Only "whatsapp" or "telegram" can be used'));
275
277
  process.exit(1);
276
278
  }
277
279
  cron.action = action;
@@ -281,65 +283,65 @@ function editCron(options) {
281
283
 
282
284
  saveCrons(crons);
283
285
 
284
- F.success('Cron güncellendi!');
285
- F.kv('İsim', cron.name);
286
- F.kv('Zamanlama', cron.schedule);
287
- F.kv('Kanal', cron.action);
288
- F.kv('Hedef', cron.target);
286
+ F.success(L('Cron güncellendi!', 'Cron updated!'));
287
+ F.kv(L('İsim', 'Name'), cron.name);
288
+ F.kv(L('Zamanlama', 'Schedule'), cron.schedule);
289
+ F.kv(L('Kanal', 'Channel'), cron.action);
290
+ F.kv(L('Hedef', 'Target'), cron.target);
289
291
  F.kv('Prompt', cron.prompt);
290
- F.meta('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start');
292
+ F.meta(L('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start', 'If the gateway is running, restart it: natureco gateway stop && natureco gateway start'));
291
293
  }
292
294
 
293
295
  function enableCron(options) {
294
296
  const { name } = options;
295
297
  if (!name) {
296
- F.error('Cron adı gerekli. Kullanım: natureco cron enable <name>');
298
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron enable <name>', 'Cron name required. Usage: natureco cron enable <name>'));
297
299
  process.exit(1);
298
300
  }
299
301
 
300
302
  const crons = loadCrons();
301
303
  const cron = crons.find(c => c.name === name);
302
304
  if (!cron) {
303
- F.error('"' + name + '" isminde bir cron bulunamadı');
305
+ F.error('"' + name + L('" isminde bir cron bulunamadı', '" — no cron found with this name'));
304
306
  process.exit(1);
305
307
  }
306
308
 
307
309
  if (cron.enabled) {
308
- F.warning('"' + name + '" cron zaten aktif');
310
+ F.warning('"' + name + L('" cron zaten aktif', '" cron already active'));
309
311
  return;
310
312
  }
311
313
 
312
314
  cron.enabled = true;
313
315
  saveCrons(crons);
314
316
  F.dot(true, name);
315
- F.success('"' + name + '" cron aktifleştirildi');
316
- F.meta('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start');
317
+ F.success('"' + name + L('" cron aktifleştirildi', '" cron enabled'));
318
+ F.meta(L('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start', 'If the gateway is running, restart it: natureco gateway stop && natureco gateway start'));
317
319
  }
318
320
 
319
321
  function disableCron(options) {
320
322
  const { name } = options;
321
323
  if (!name) {
322
- F.error('Cron adı gerekli. Kullanım: natureco cron disable <name>');
324
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron disable <name>', 'Cron name required. Usage: natureco cron disable <name>'));
323
325
  process.exit(1);
324
326
  }
325
327
 
326
328
  const crons = loadCrons();
327
329
  const cron = crons.find(c => c.name === name);
328
330
  if (!cron) {
329
- F.error('"' + name + '" isminde bir cron bulunamadı');
331
+ F.error('"' + name + L('" isminde bir cron bulunamadı', '" — no cron found with this name'));
330
332
  process.exit(1);
331
333
  }
332
334
 
333
335
  if (!cron.enabled) {
334
- F.warning('"' + name + '" cron zaten pasif');
336
+ F.warning('"' + name + L('" cron zaten pasif', '" cron already inactive'));
335
337
  return;
336
338
  }
337
339
 
338
340
  cron.enabled = false;
339
341
  saveCrons(crons);
340
342
  F.dot(false, name);
341
- F.success('"' + name + '" cron pasifleştirildi');
342
- F.meta('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start');
343
+ F.success('"' + name + L('" cron pasifleştirildi', '" cron disabled'));
344
+ F.meta(L('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start', 'If the gateway is running, restart it: natureco gateway stop && natureco gateway start'));
343
345
  }
344
346
 
345
347
  function loadRuns() {
@@ -356,7 +358,7 @@ function loadRuns() {
356
358
  function showRuns(options) {
357
359
  const { name } = options;
358
360
  if (!name) {
359
- F.error('Cron adı gerekli. Kullanım: natureco cron runs <name>');
361
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron runs <name>', 'Cron name required. Usage: natureco cron runs <name>'));
360
362
  process.exit(1);
361
363
  }
362
364
 
@@ -365,7 +367,7 @@ function showRuns(options) {
365
367
  F.header('Cron Runs: ' + name);
366
368
 
367
369
  if (runs.length === 0) {
368
- F.meta('"' + name + '" için kayıtlı çalışma geçmişi yok');
370
+ F.meta('"' + name + L('" için kayıtlı çalışma geçmişi yok', '" — no run history recorded'));
369
371
  return;
370
372
  }
371
373
 
@@ -380,25 +382,25 @@ function showRuns(options) {
380
382
  function runCron(options) {
381
383
  const { name } = options;
382
384
  if (!name) {
383
- F.error('Cron adı gerekli. Kullanım: natureco cron run <name>');
385
+ F.error(L('Cron adı gerekli. Kullanım: natureco cron run <name>', 'Cron name required. Usage: natureco cron run <name>'));
384
386
  process.exit(1);
385
387
  }
386
388
 
387
389
  const crons = loadCrons();
388
390
  const cron = crons.find(c => c.name === name);
389
391
  if (!cron) {
390
- F.error('"' + name + '" isminde bir cron bulunamadı');
392
+ F.error('"' + name + L('" isminde bir cron bulunamadı', '" — no cron found with this name'));
391
393
  process.exit(1);
392
394
  }
393
395
 
394
396
  const timestamp = new Date().toISOString();
395
397
 
396
- F.info('"' + name + '" cron manuel olarak çalıştırılıyor...');
397
- F.kv('Zamanlama', cron.schedule);
398
- F.kv('Kanal', cron.action);
399
- F.kv('Hedef', cron.target);
398
+ F.info('"' + name + L('" cron manuel olarak çalıştırılıyor...', '" cron running manually...'));
399
+ F.kv(L('Zamanlama', 'Schedule'), cron.schedule);
400
+ F.kv(L('Kanal', 'Channel'), cron.action);
401
+ F.kv(L('Hedef', 'Target'), cron.target);
400
402
  F.kv('Prompt', cron.prompt);
401
- F.success('Cron tetiklendi (mock)');
403
+ F.success(L('Cron tetiklendi (mock)', 'Cron triggered (mock)'));
402
404
 
403
405
  // Log the run
404
406
  const runs = loadRuns();
@@ -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 };