natureco-cli 5.60.0 → 5.62.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.
@@ -18,6 +18,8 @@ const path = require("path");
18
18
  const os = require("os");
19
19
  const readline = require("readline");
20
20
  const chalk = require("chalk");
21
+ const { getLang: _gl } = require("../utils/i18n");
22
+ const L = (tr, en) => (_gl() === "en" ? en : tr);
21
23
  const tui = require("../utils/tui");
22
24
  const { getConfig } = require("../utils/config");
23
25
  const { loadToolDefinitions, executeTool, toOpenAIFormat } = require("../utils/tools");
@@ -56,7 +58,7 @@ async function apiRequest(url, key, body) {
56
58
  res.on("data", c => body += c);
57
59
  res.on("end", () => {
58
60
  if (res.statusCode === 200) {
59
- try { resolve(JSON.parse(body)); } catch (e) { reject(new Error("Parse hatasi")); }
61
+ try { resolve(JSON.parse(body)); } catch (e) { reject(new Error(L("Parse hatasi", "Parse error"))); }
60
62
  } else reject(new Error("HTTP " + res.statusCode + ": " + body.slice(0, 200)));
61
63
  });
62
64
  });
@@ -92,7 +94,7 @@ async function sendMessageWithTools(providerUrl, providerKey, model, messages, t
92
94
  } catch (err) {
93
95
  const fb = fallbackChain.recordError(body.model, err);
94
96
  if (fb.fallback) {
95
- console.log(tui.C.yellow(`\n ⚠ ${body.model} başarısız → ${fb.nextModel} deneniyor...\n`));
97
+ console.log(tui.C.yellow(`\n ⚠ ${body.model} ${L('başarısız', 'failed')} → ${fb.nextModel} ${L('deneniyor...', 'trying...')}\n`));
96
98
  return sendMessageWithTools(providerUrl, providerKey, fb.nextModel, messages, toolDefs);
97
99
  }
98
100
  throw err;
@@ -128,24 +130,24 @@ function assessRisk(tool, args) {
128
130
 
129
131
  // Dosya/klasör silme
130
132
  if (/\brm\s+(-[rf]+\s+)*/.test(cmd) || /rmdir/.test(cmd)) {
131
- return { requiresApproval: true, level: "high", reason: `Dosya silme komutu: ${args.command}` };
133
+ return { requiresApproval: true, level: "high", reason: `${L('Dosya silme komutu', 'File deletion command')}: ${args.command}` };
132
134
  }
133
135
  if (cmd.includes("sudo ") || cmd.includes("doas ")) {
134
- return { requiresApproval: true, level: "high", reason: `Yetki yükseltme: ${args.command}` };
136
+ return { requiresApproval: true, level: "high", reason: `${L('Yetki yükseltme', 'Privilege escalation')}: ${args.command}` };
135
137
  }
136
138
  if (cmd.includes("dd if=") || cmd.includes("mkfs") || cmd.includes("fdisk")) {
137
- return { requiresApproval: true, level: "high", reason: `Disk işlemi: ${args.command}` };
139
+ return { requiresApproval: true, level: "high", reason: `${L('Disk işlemi', 'Disk operation')}: ${args.command}` };
138
140
  }
139
141
  if (cmd.match(/^\s*mv\s+.*\/(?:\.|\.\.)/)) {
140
- return { requiresApproval: true, level: "medium", reason: `Üzerine yazma riski: ${args.command}` };
142
+ return { requiresApproval: true, level: "medium", reason: `${L('Üzerine yazma riski', 'Overwrite risk')}: ${args.command}` };
141
143
  }
142
144
  // chmod 777 veya chown -R
143
145
  if (/chmod\s+(-[rR]+\s+)*777/.test(cmd) || /chown\s+-R/.test(cmd)) {
144
- return { requiresApproval: true, level: "medium", reason: `İzin değişikliği: ${args.command}` };
146
+ return { requiresApproval: true, level: "medium", reason: `${L('İzin değişikliği', 'Permission change')}: ${args.command}` };
145
147
  }
146
148
  // git push --force
147
149
  if (/git\s+push.*--force/.test(cmd) || /git\s+push.*-f\s/.test(cmd)) {
148
- return { requiresApproval: true, level: "high", reason: `Zorla push: ${args.command}` };
150
+ return { requiresApproval: true, level: "high", reason: `${L('Zorla push', 'Force push')}: ${args.command}` };
149
151
  }
150
152
  // git reset --hard
151
153
  if (/git\s+reset\s+--hard/.test(cmd)) {
@@ -153,19 +155,19 @@ function assessRisk(tool, args) {
153
155
  }
154
156
  // Üretim/kök dizin
155
157
  if (cmd.includes("/etc/") || cmd.includes("/usr/") || cmd.includes("/var/") || cmd.includes("/System/")) {
156
- return { requiresApproval: true, level: "high", reason: `Sistem dizinine erişim: ${args.command}` };
158
+ return { requiresApproval: true, level: "high", reason: `${L('Sistem dizinine erişim', 'System directory access')}: ${args.command}` };
157
159
  }
158
160
  // curl/wget internet download
159
161
  if (/curl.*\|\s*(bash|sh)/.test(cmd) || /wget.*\|\s*(bash|sh)/.test(cmd)) {
160
- return { requiresApproval: true, level: "high", reason: `İnternet üzerinden script çalıştırma: ${args.command}` };
162
+ return { requiresApproval: true, level: "high", reason: `${L('İnternet üzerinden script çalıştırma', 'Running a script from the internet')}: ${args.command}` };
161
163
  }
162
164
  // mac_app_quit veya killall
163
165
  if (cmd.includes("killall") || cmd.includes("pkill") || cmd.includes("kill -9")) {
164
- return { requiresApproval: true, level: "high", reason: `Süreç sonlandırma: ${args.command}` };
166
+ return { requiresApproval: true, level: "high", reason: `${L('Süreç sonlandırma', 'Process termination')}: ${args.command}` };
165
167
  }
166
168
  // .natureco veya önemli dosyalara dokunma
167
169
  if (cmd.includes(".natureco") && (cmd.includes("rm") || cmd.includes("mv"))) {
168
- return { requiresApproval: true, level: "high", reason: `NatureCo dizininde tehlikeli işlem: ${args.command}` };
170
+ return { requiresApproval: true, level: "high", reason: `${L('NatureCo dizininde tehlikeli işlem', 'Dangerous operation in the NatureCo directory')}: ${args.command}` };
169
171
  }
170
172
  }
171
173
 
@@ -175,7 +177,7 @@ function assessRisk(tool, args) {
175
177
 
176
178
  // mac_app_quit - uygulama kapatma
177
179
  if (tool === "mac_app_quit") {
178
- return { requiresApproval: true, level: "medium", reason: `Uygulama kapatma: ${args.app || args.name || "?"}` };
180
+ return { requiresApproval: true, level: "medium", reason: `${L('Uygulama kapatma', 'App quit')}: ${args.app || args.name || "?"}` };
179
181
  }
180
182
 
181
183
  // write_file / edit_file - kritik yollara yazma
@@ -183,13 +185,13 @@ function assessRisk(tool, args) {
183
185
  const path = (args.path || args.file || "").toLowerCase();
184
186
  // Hassas dosyalar
185
187
  if (path.includes(".env") || path.includes("credentials") || path.includes("secret")) {
186
- return { requiresApproval: true, level: "high", reason: `Hassas dosya: ${args.path}` };
188
+ return { requiresApproval: true, level: "high", reason: `${L('Hassas dosya', 'Sensitive file')}: ${args.path}` };
187
189
  }
188
190
  if (path.includes("/etc/") || path.includes("/usr/") || path.includes("~/.ssh/")) {
189
- return { requiresApproval: true, level: "high", reason: `Sistem dosyası: ${args.path}` };
191
+ return { requiresApproval: true, level: "high", reason: `${L('Sistem dosyası', 'System file')}: ${args.path}` };
190
192
  }
191
193
  if (path.includes(".natureco/config.json") || path.includes(".natureco/soul/")) {
192
- return { requiresApproval: true, level: "medium", reason: `NatureCo config dosyası: ${args.path}` };
194
+ return { requiresApproval: true, level: "medium", reason: `${L('NatureCo config dosyası', 'NatureCo config file')}: ${args.path}` };
193
195
  }
194
196
  }
195
197
 
@@ -216,7 +218,7 @@ function printToolCallSafe(name, args, result) {
216
218
  // Result'tan sadece status goster, yol/size gizle
217
219
  if (!result) return;
218
220
  if (result.error) {
219
- console.log(tui.styled(" ✗ Hata: " + result.error.slice(0, 100), { color: tui.PALETTE.danger }));
221
+ console.log(tui.styled(L(" ✗ Hata: ", " ✗ Error: ") + result.error.slice(0, 100), { color: tui.PALETTE.danger }));
220
222
  } else {
221
223
  const success = result.success !== false;
222
224
  const resultStr = typeof result.result === "string"
@@ -232,7 +234,7 @@ function printToolCallSafe(name, args, result) {
232
234
  .replace(/"fileCount":\d+/g, "");
233
235
  const statusIcon = success ? "✓" : "✗";
234
236
  const statusColor = success ? tui.PALETTE.success : tui.PALETTE.danger;
235
- console.log(tui.styled(` ${statusIcon} Sonuç: ${cleanResult.trim()}`, { color: statusColor }));
237
+ console.log(tui.styled(` ${statusIcon} ${L('Sonuç', 'Result')}: ${cleanResult.trim()}`, { color: statusColor }));
236
238
  }
237
239
  }
238
240
 
@@ -261,10 +263,10 @@ function printToolCall(name, args, result) {
261
263
  console.log(" " + tui.styled(" Args: " + argsStr, { color: tui.PALETTE.muted }));
262
264
  if (result) {
263
265
  if (result.error) {
264
- console.log(" " + tui.styled(" ✗ Hata: " + result.error.slice(0, 200), { color: tui.PALETTE.danger }));
266
+ console.log(" " + tui.styled(L(" ✗ Hata: ", " ✗ Error: ") + result.error.slice(0, 200), { color: tui.PALETTE.danger }));
265
267
  } else if (result.success !== false) {
266
268
  const out = typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200);
267
- console.log(" " + tui.styled(" ✓ Sonuç: " + out, { color: tui.PALETTE.success }));
269
+ console.log(" " + tui.styled(L(" ✓ Sonuç: ", " ✓ Result: ") + out, { color: tui.PALETTE.success }));
268
270
  }
269
271
  }
270
272
  }
@@ -298,7 +300,7 @@ function scanProject(cwd) {
298
300
  async function codeV5(targetPath) {
299
301
  const config = getConfig();
300
302
  if (!config.providerUrl || !config.providerApiKey) {
301
- console.log(tui.C.red("\n ❌ Provider ayarlı değil. Önce: natureco setup\n"));
303
+ console.log(tui.C.red(L("\n ❌ Provider ayarlı değil. Önce: natureco setup\n", "\n ❌ Provider not configured. First: natureco setup\n")));
302
304
  return;
303
305
  }
304
306
 
@@ -347,7 +349,7 @@ async function codeV5(targetPath) {
347
349
  execute: async (args) => {
348
350
  const ok = planMode.exit(args.plan);
349
351
  if (!ok) return { error: 'Not in plan mode.' };
350
- console.log(tui.C.cyan('\n 📋 Plan sunuldu. Onay için /plan approve yazın, red için /plan reject.\n'));
352
+ console.log(tui.C.cyan(L('\n 📋 Plan sunuldu. Onay için /plan approve yazın, red için /plan reject.\n', '\n 📋 Plan submitted. Type /plan approve to approve, /plan reject to reject.\n')));
351
353
  return { result: `Plan submitted.\n\n${args.plan}` };
352
354
  },
353
355
  },
@@ -437,22 +439,22 @@ async function codeV5(targetPath) {
437
439
 
438
440
  // Project context
439
441
  if (projectCtx) {
440
- console.log("\n " + tui.C.muted("📂 Proje bağlamı:"));
442
+ console.log("\n " + tui.C.muted(L("📂 Proje bağlamı:", "📂 Project context:")));
441
443
  if (projectCtx.readme) console.log(" " + tui.C.muted("• README: ") + tui.C.text(projectCtx.readme));
442
444
  if (projectCtx.configFiles.length) {
443
445
  console.log(" " + tui.C.muted("• Config: ") + tui.C.text(projectCtx.configFiles.join(", ")));
444
446
  }
445
447
  if (projectCtx.dirs.length) {
446
- console.log(" " + tui.C.muted("• Klasörler: ") + tui.C.text(projectCtx.dirs.slice(0, 8).join(", ")));
448
+ console.log(" " + tui.C.muted(L("• Klasörler: ", "• Folders: ")) + tui.C.text(projectCtx.dirs.slice(0, 8).join(", ")));
447
449
  }
448
- console.log(" " + tui.C.muted("• Toplam dosya: ") + tui.C.text(String(projectCtx.totalFiles)));
450
+ console.log(" " + tui.C.muted(L("• Toplam dosya: ", "• Total files: ")) + tui.C.text(String(projectCtx.totalFiles)));
449
451
  }
450
452
 
451
- console.log("\n " + tui.C.muted("Komutlar:"));
452
- console.log(" " + tui.C.amber("/plan on|approve|reject|show") + tui.C.muted(" — Plan modu"));
453
- console.log(" " + tui.C.amber("/summary") + tui.C.muted(" — Oturum özeti"));
454
- console.log(" " + tui.C.amber("/done") + tui.C.muted(" — Özet + çıkış"));
455
- console.log(" " + tui.C.amber("Ctrl+C") + tui.C.muted(" — Çıkış"));
453
+ console.log("\n " + tui.C.muted(L("Komutlar:", "Commands:")));
454
+ console.log(" " + tui.C.amber("/plan on|approve|reject|show") + tui.C.muted(L(" — Plan modu", " — Plan mode")));
455
+ console.log(" " + tui.C.amber("/summary") + tui.C.muted(L(" — Oturum özeti", " — Session summary")));
456
+ console.log(" " + tui.C.amber("/done") + tui.C.muted(L(" — Özet + çıkış", " — Summary + exit")));
457
+ console.log(" " + tui.C.amber("Ctrl+C") + tui.C.muted(L(" — Çıkış", " — Exit")));
456
458
  console.log("");
457
459
 
458
460
  // Three-tier system prompt (Hermes-style)
@@ -461,7 +463,7 @@ async function codeV5(targetPath) {
461
463
  const projectRules = discoverProjectRules(cwd);
462
464
  const promptOpts = {
463
465
  botName: 'Code Agent',
464
- userName: cfg.userName || 'kullanıcı',
466
+ userName: cfg.userName || L('kullanıcı', 'user'),
465
467
  skillsIndexBlock,
466
468
  projectRules,
467
469
  hasHistory: false,
@@ -497,19 +499,19 @@ async function codeV5(targetPath) {
497
499
  const arg = input.slice(6).trim();
498
500
  const pm = getPlanMode();
499
501
  if (arg === "on" || arg === "enter") {
500
- if (pm.enter()) console.log(tui.C.cyan('\n 📋 Plan modu aktif.\n'));
501
- else console.log(tui.C.yellow(' Zaten plan modunda.'));
502
+ if (pm.enter()) console.log(tui.C.cyan(L('\n 📋 Plan modu aktif.\n', '\n 📋 Plan mode active.\n')));
503
+ else console.log(tui.C.yellow(L(' Zaten plan modunda.', ' Already in plan mode.')));
502
504
  } else if (arg === "approve") {
503
- if (pm.inReview()) { pm.approve(); console.log(tui.C.green(' ✓ Plan onaylandı.\n')); }
504
- else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
505
+ if (pm.inReview()) { pm.approve(); console.log(tui.C.green(L(' ✓ Plan onaylandı.\n', ' ✓ Plan approved.\n'))); }
506
+ else console.log(tui.C.yellow(L(' Onay bekleyen plan yok.', ' No plan awaiting approval.')));
505
507
  } else if (arg === "reject") {
506
- if (pm.inReview()) { pm.reject(); console.log(tui.C.amber(' ⨯ Plan reddedildi.\n')); }
507
- else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
508
+ if (pm.inReview()) { pm.reject(); console.log(tui.C.amber(L(' ⨯ Plan reddedildi.\n', ' ⨯ Plan rejected.\n'))); }
509
+ else console.log(tui.C.yellow(L(' Onay bekleyen plan yok.', ' No plan awaiting approval.')));
508
510
  } else if (arg === "show") {
509
- if (pm.planHistory.length > 0) console.log(tui.C.cyan('\n 📋 Son Plan:\n ' + pm.planHistory[pm.planHistory.length - 1].plan.replace(/\n/g, '\n ') + '\n'));
510
- else console.log(tui.C.yellow(' Henüz plan yok.'));
511
+ if (pm.planHistory.length > 0) console.log(tui.C.cyan(L('\n 📋 Son Plan:\n ', '\n 📋 Last Plan:\n ') + pm.planHistory[pm.planHistory.length - 1].plan.replace(/\n/g, '\n ') + '\n'));
512
+ else console.log(tui.C.yellow(L(' Henüz plan yok.', ' No plan yet.')));
511
513
  } else {
512
- console.log(tui.C.yellow(' Kullanım: /plan on|approve|reject|show'));
514
+ console.log(tui.C.yellow(L(' Kullanım: /plan on|approve|reject|show', ' Usage: /plan on|approve|reject|show')));
513
515
  }
514
516
  process.stdout.write("\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
515
517
  return ask();
@@ -548,12 +550,12 @@ async function codeV5(targetPath) {
548
550
  return ` ${s} ${t}: ${summary}`;
549
551
  }).join('\n');
550
552
  const skillInfo = wf.skillsLoaded && wf.skillsLoaded.length > 0
551
- ? `\n\nKullanilan skill'ler: ${wf.skillsLoaded.join(', ')}`
553
+ ? `\n\n${L("Kullanilan skill'ler", 'Skills used')}: ${wf.skillsLoaded.join(', ')}`
552
554
  : '';
553
555
  const preWfLen = messages.length;
554
556
  messages.push({
555
557
  role: 'system',
556
- content: `=== WORKFLOW SONUCLARI ===\nSu araclar calisti:\n${report}${skillInfo}\n\nKullaniciya bu sonuclari anlamli bir sekilde ozetle.\n=== SONUC BITTI ===`,
558
+ content: `=== ${L('WORKFLOW SONUÇLARI', 'WORKFLOW RESULTS')} ===\n${L('Şu araçlar çalıştı', 'These tools ran')}:\n${report}${skillInfo}\n\n${L('Kullanıcıya bu sonuçları anlamlı bir şekilde özetle.', 'Summarize these results for the user in a meaningful way.')}\n=== ${L('SONUÇ BİTTİ', 'END RESULT')} ===`,
557
559
  });
558
560
 
559
561
  process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
@@ -631,10 +633,10 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
631
633
  if (risk.requiresApproval) {
632
634
  process.stdout.write("\n");
633
635
  const approved = await confirm(
634
- `⚠ ${tc.function.name}: ${risk.reason}\n Devam edilsin mi? (Y/n) `
636
+ `⚠ ${tc.function.name}: ${risk.reason}\n ${L('Devam edilsin mi', 'Continue')}? (Y/n) `
635
637
  );
636
638
  if (!approved) {
637
- console.log("\n " + tui.C.yellow("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı."));
639
+ console.log("\n " + tui.C.yellow(L("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı.", "⚠ User declined approval, tool not run.")));
638
640
  return;
639
641
  }
640
642
  }
@@ -643,7 +645,7 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
643
645
  const pm = getPlanMode();
644
646
  const planCheck = pm.checkTool(tc.function.name, args);
645
647
  if (!planCheck.allowed) {
646
- console.log("\n " + tui.C.red("⛔ Plan modunda engellendi: " + planCheck.reason));
648
+ console.log("\n " + tui.C.red(L("⛔ Plan modunda engellendi: ", "⛔ Blocked in plan mode: ") + planCheck.reason));
647
649
  return;
648
650
  }
649
651
  pm.recordTool(tc.function.name, args);
@@ -651,18 +653,18 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
651
653
  // Permission check
652
654
  const perm = checkPermission(tc.function.name, args);
653
655
  if (perm.action === 'deny') {
654
- console.log("\n " + tui.C.red("⛔ İzin engelledi: " + perm.reason));
656
+ console.log("\n " + tui.C.red(L("⛔ İzin engelledi: ", "⛔ Permission denied: ") + perm.reason));
655
657
  return;
656
658
  }
657
659
  if (perm.action === 'ask') {
658
660
  const permKey = `${perm.rule.raw}:${JSON.stringify(args)}`;
659
661
  if (!isApproved(permKey)) {
660
662
  process.stdout.write("\n");
661
- const ok = await confirm(`İzin gerekli: ${formatPermissionPrompt(tc.function.name, args, perm.reason)}\n İzin ver? [y=once, Y=session, p=persistent, n=no] `);
663
+ const ok = await confirm(`${L('İzin gerekli', 'Permission required')}: ${formatPermissionPrompt(tc.function.name, args, perm.reason)}\n ${L('İzin ver', 'Grant')}? [y=once, Y=session, p=persistent, n=no] `);
662
664
  if (ok === 'persistent') markApproved(permKey, true);
663
665
  else if (ok === 'session' || ok === true) markApproved(permKey, false);
664
666
  else {
665
- console.log("\n " + tui.C.yellow("⛔ İzin reddedildi"));
667
+ console.log("\n " + tui.C.yellow(L("⛔ İzin reddedildi", "⛔ Permission rejected")));
666
668
  return;
667
669
  }
668
670
  }
@@ -671,13 +673,13 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
671
673
  // Pre-hook check
672
674
  const hook = checkPreHooks(tc.function.name, args);
673
675
  if (hook.action === 'deny') {
674
- console.log("\n " + tui.C.red("⛔ Hook engelledi: " + hook.rule.raw));
676
+ console.log("\n " + tui.C.red(L("⛔ Hook engelledi: ", "⛔ Hook blocked: ") + hook.rule.raw));
675
677
  return;
676
678
  }
677
679
  if (hook.action === 'ask') {
678
- const ok = await confirm(`Hook onayı: ${permissionSummary(hook.rule, tc.function.name, args)}\n İzin verilsin mi? (y/N) `);
680
+ const ok = await confirm(`${L('Hook onayı', 'Hook approval')}: ${permissionSummary(hook.rule, tc.function.name, args)}\n ${L('İzin verilsin mi', 'Grant permission')}? (y/N) `);
679
681
  if (!ok) {
680
- console.log("\n " + tui.C.yellow("⛔ Hook reddetti: " + hook.rule.raw));
682
+ console.log("\n " + tui.C.yellow(L("⛔ Hook reddetti: ", "⛔ Hook rejected: ") + hook.rule.raw));
681
683
  return;
682
684
  }
683
685
  }
@@ -729,11 +731,11 @@ function printSummary(files, cmds, msgs, startTime) {
729
731
  const elapsed = Math.floor((Date.now() - startTime) / 1000);
730
732
  const min = Math.floor(elapsed / 60);
731
733
  const sec = elapsed % 60;
732
- console.log("\n " + tui.styled("─── Session Özeti ───", { color: tui.PALETTE.primary, bold: true }));
733
- console.log(" " + tui.C.green(" ✓ " + files + " dosya değiştirildi"));
734
- console.log(" " + tui.C.green(" ✓ " + cmds + " komut çalıştırıldı"));
735
- console.log(" " + tui.C.amber(" ✓ " + msgs + " mesaj değişimi"));
736
- console.log(" " + tui.C.muted(" ⏱ " + min + "dk " + sec + "sn"));
734
+ console.log("\n " + tui.styled(L("─── Session Özeti ───", "─── Session Summary ───"), { color: tui.PALETTE.primary, bold: true }));
735
+ console.log(" " + tui.C.green(" ✓ " + files + L(" dosya değiştirildi", " files changed")));
736
+ console.log(" " + tui.C.green(" ✓ " + cmds + L(" komut çalıştırıldı", " commands run")));
737
+ console.log(" " + tui.C.amber(" ✓ " + msgs + L(" mesaj değişimi", " message exchanges")));
738
+ console.log(" " + tui.C.muted(" ⏱ " + min + L("dk ", "min ") + sec + L("sn", "s")));
737
739
  console.log("");
738
740
  }
739
741
 
@@ -1,5 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
  const fs = require('fs');
3
+ const { getLang: _gl } = require('../utils/i18n');
4
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
3
5
  const path = require('path');
4
6
  const os = require('os');
5
7
 
@@ -33,7 +35,7 @@ function commitments(args) {
33
35
  if (action === 'delete') return deleteC(params[0]);
34
36
 
35
37
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
36
- console.log(chalk.gray(' Kullanım: natureco commitments [list|add|check|resolve|pending|summary|delete]\n'));
38
+ console.log(chalk.gray(L(' Kullanım: natureco commitments [list|add|check|resolve|pending|summary|delete]\n', ' Usage: natureco commitments [list|add|check|resolve|pending|summary|delete]\n')));
37
39
  process.exit(1);
38
40
  }
39
41
 
@@ -42,7 +44,7 @@ function listC() {
42
44
  console.log(chalk.cyan('\n 📋 Commitments\n'));
43
45
  console.log(chalk.gray(' ' + '─'.repeat(48)));
44
46
  if (items.length === 0) {
45
- console.log(chalk.gray(' Henüz commitment yok.\n'));
47
+ console.log(chalk.gray(L(' Henüz commitment yok.\n', ' No commitments yet.\n')));
46
48
  return;
47
49
  }
48
50
  for (const c of items) {
@@ -55,52 +57,52 @@ function listC() {
55
57
 
56
58
  function addC(text) {
57
59
  if (!text) {
58
- console.log(chalk.red('\n ❌ Commitment text gerekli\n'));
60
+ console.log(chalk.red(L('\n ❌ Commitment text gerekli\n', '\n ❌ Commitment text required\n')));
59
61
  process.exit(1);
60
62
  }
61
63
  const items = load();
62
64
  const c = { id: genId(), text, status: 'pending', createdAt: new Date().toISOString(), resolvedAt: null };
63
65
  items.push(c);
64
66
  save(items);
65
- console.log(chalk.green(`\n ✅ Commitment eklendi: ${c.id}\n`));
67
+ console.log(chalk.green(`\n ✅ ${L('Commitment eklendi', 'Commitment added')}: ${c.id}\n`));
66
68
  console.log(` ${chalk.white(c.text)}`);
67
69
  console.log();
68
70
  }
69
71
 
70
72
  function checkC(id) {
71
73
  if (!id) {
72
- console.log(chalk.red('\n ❌ Commitment ID gerekli\n'));
74
+ console.log(chalk.red(L('\n ❌ Commitment ID gerekli\n', '\n ❌ Commitment ID required\n')));
73
75
  process.exit(1);
74
76
  }
75
77
  const items = load();
76
78
  const c = items.find(x => x.id === id);
77
- if (!c) { console.log(chalk.red(`\n ❌ Commitment bulunamadı: ${id}\n`)); process.exit(1); }
78
- if (c.status === 'resolved') { console.log(chalk.yellow(`\n ⚠️ "${c.text}" zaten çözülmüş\n`)); return; }
79
+ if (!c) { console.log(chalk.red(`\n ❌ ${L('Commitment bulunamadı', 'Commitment not found')}: ${id}\n`)); process.exit(1); }
80
+ if (c.status === 'resolved') { console.log(chalk.yellow(`\n ⚠️ "${c.text}" ${L('zaten çözülmüş', 'already resolved')}\n`)); return; }
79
81
  c.status = 'checked';
80
82
  save(items);
81
- console.log(chalk.green(`\n ☑️ "${c.text}" tamamlandı olarak işaretlendi\n`));
83
+ console.log(chalk.green(`\n ☑️ "${c.text}" ${L('tamamlandı olarak işaretlendi', 'marked as done')}\n`));
82
84
  }
83
85
 
84
86
  function resolveC(id) {
85
87
  if (!id) {
86
88
  const items = load();
87
89
  const pending = items.filter(x => x.status !== 'resolved');
88
- if (pending.length === 0) { console.log(chalk.gray('\n Çözülecek commitment yok\n')); return; }
90
+ if (pending.length === 0) { console.log(chalk.gray(L('\n Çözülecek commitment yok\n', '\n No commitments to resolve\n'))); return; }
89
91
  for (const c of pending) {
90
92
  c.status = 'resolved';
91
93
  c.resolvedAt = new Date().toISOString();
92
94
  }
93
95
  save(items);
94
- console.log(chalk.green(`\n ✅ ${pending.length} commitment çözüldü\n`));
96
+ console.log(chalk.green(`\n ✅ ${pending.length} ${L('commitment çözüldü', 'commitments resolved')}\n`));
95
97
  return;
96
98
  }
97
99
  const items = load();
98
100
  const c = items.find(x => x.id === id);
99
- if (!c) { console.log(chalk.red(`\n ❌ Commitment bulunamadı: ${id}\n`)); process.exit(1); }
101
+ if (!c) { console.log(chalk.red(`\n ❌ ${L('Commitment bulunamadı', 'Commitment not found')}: ${id}\n`)); process.exit(1); }
100
102
  c.status = 'resolved';
101
103
  c.resolvedAt = new Date().toISOString();
102
104
  save(items);
103
- console.log(chalk.green(`\n ✅ "${c.text}" çözüldü\n`));
105
+ console.log(chalk.green(`\n ✅ "${c.text}" ${L('çözüldü', 'resolved')}\n`));
104
106
  }
105
107
 
106
108
  function pendingC() {
@@ -125,8 +127,8 @@ function summaryC() {
125
127
  const pending = total - resolved - checked;
126
128
  console.log(chalk.cyan('\n 📊 Commitments Summary\n'));
127
129
  console.log(chalk.gray(' ' + '─'.repeat(48)));
128
- console.log(` ${chalk.white('Toplam:')} ${total}`);
129
- console.log(` ${chalk.green('Çözülen:')} ${resolved}`);
130
+ console.log(` ${chalk.white(L('Toplam:', 'Total:'))} ${total}`);
131
+ console.log(` ${chalk.green(L('Çözülen:', 'Resolved:'))} ${resolved}`);
130
132
  console.log(` ${chalk.yellow('Kontrol:')} ${checked}`);
131
133
  console.log(` ${chalk.cyan('Kalan:')} ${pending}`);
132
134
  console.log();
@@ -134,12 +136,12 @@ function summaryC() {
134
136
 
135
137
  function deleteC(id) {
136
138
  if (!id) {
137
- console.log(chalk.red('\n ❌ Commitment ID gerekli\n'));
139
+ console.log(chalk.red(L('\n ❌ Commitment ID gerekli\n', '\n ❌ Commitment ID required\n')));
138
140
  process.exit(1);
139
141
  }
140
142
  let items = load();
141
143
  const idx = items.findIndex(x => x.id === id);
142
- if (idx === -1) { console.log(chalk.red(`\n ❌ Commitment bulunamadı: ${id}\n`)); process.exit(1); }
144
+ if (idx === -1) { console.log(chalk.red(`\n ❌ ${L('Commitment bulunamadı', 'Commitment not found')}: ${id}\n`)); process.exit(1); }
143
145
  const removed = items.splice(idx, 1)[0];
144
146
  save(items);
145
147
  console.log(chalk.gray(`\n 🗑️ "${removed.text}" silindi\n`));
@@ -1,5 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
  const { execSync, spawn } = require('child_process');
3
+ const { getLang: _gl } = require('../utils/i18n');
4
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
3
5
  const path = require('path');
4
6
  const fs = require('fs');
5
7
  const os = require('os');
@@ -17,7 +19,7 @@ function daemon(args) {
17
19
  if (action === 'uninstall') return uninstallDaemon();
18
20
 
19
21
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
20
- console.log(chalk.gray(' Kullanım: natureco daemon [status|start|stop|restart|install|uninstall]\n'));
22
+ console.log(chalk.gray(L(' Kullanım: natureco daemon [status|start|stop|restart|install|uninstall]\n', ' Usage: natureco daemon [status|start|stop|restart|install|uninstall]\n')));
21
23
  process.exit(1);
22
24
  }
23
25
 
@@ -1,5 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
  const fs = require('fs');
3
+ const { getLang: _gl } = require('../utils/i18n');
4
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
3
5
  const path = require('path');
4
6
  const os = require('os');
5
7
  const crypto = require('crypto');
@@ -36,7 +38,7 @@ function devicePair(args) {
36
38
  if (action === 'verify') return verifyPairing(params[0], params[1]);
37
39
 
38
40
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
39
- console.log(chalk.gray(' Kullanım: natureco device-pair [list|request|approve|reject|remove|pairing-code|verify]\n'));
41
+ console.log(chalk.gray(L(' Kullanım: natureco device-pair [list|request|approve|reject|remove|pairing-code|verify]\n', ' Usage: natureco device-pair [list|request|approve|reject|remove|pairing-code|verify]\n')));
40
42
  process.exit(1);
41
43
  }
42
44
 
@@ -48,7 +50,7 @@ function listDevices() {
48
50
 
49
51
  const devices = data.pairedDevices || [];
50
52
  if (devices.length === 0) {
51
- console.log(chalk.gray(' Eşleştirilmiş cihaz yok.\n'));
53
+ console.log(chalk.gray(L(' Eşleştirilmiş cihaz yok.\n', ' No paired devices.\n')));
52
54
  } else {
53
55
  for (const d of devices) {
54
56
  console.log(` ${chalk.green('●')} ${chalk.white(d.name || d.id)} ${chalk.gray(`(${d.type || 'unknown'})`)}`);
@@ -60,13 +62,13 @@ function listDevices() {
60
62
 
61
63
  const pending = data.pendingRequests || [];
62
64
  if (pending.length > 0) {
63
- console.log(chalk.yellow(`\n ⏳ Bekleyen İstekler (${pending.length})\n`));
65
+ console.log(chalk.yellow(`\n ⏳ ${L('Bekleyen İstekler', 'Pending Requests')} (${pending.length})\n`));
64
66
  for (const p of pending) {
65
67
  console.log(` ${chalk.yellow('◐')} ${chalk.white(p.name || p.id)} ${chalk.gray(`(${p.type || 'unknown'})`)}`);
66
68
  console.log(` ${chalk.gray('Code:')} ${chalk.cyan(p.code)}`);
67
69
  console.log(` ${chalk.gray('Since:')} ${p.requestedAt ? new Date(p.requestedAt).toLocaleString() : '-'}`);
68
70
  }
69
- console.log(chalk.gray('\n Onaylamak için:'));
71
+ console.log(chalk.gray(L('\n Onaylamak için:', '\n To approve:')));
70
72
  console.log(chalk.cyan(' natureco device-pair approve <code>'));
71
73
  console.log(chalk.cyan(' natureco device-pair reject <code>'));
72
74
  }
@@ -109,7 +111,7 @@ function requestPairing(deviceName, deviceType) {
109
111
 
110
112
  function approvePairing(code) {
111
113
  if (!code) {
112
- console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
114
+ console.log(chalk.red(L('\n ❌ Pairing code gerekli\n', '\n ❌ Pairing code required\n')));
113
115
  process.exit(1);
114
116
  }
115
117
 
@@ -117,8 +119,8 @@ function approvePairing(code) {
117
119
  const idx = (data.pendingRequests || []).findIndex(p => p.code === code);
118
120
 
119
121
  if (idx === -1) {
120
- console.log(chalk.red(`\n ❌ Geçersiz pairing code: ${code}\n`));
121
- console.log(chalk.gray(' Bekleyen istekleri görmek için: natureco device-pair list\n'));
122
+ console.log(chalk.red(`\n ❌ ${L('Geçersiz pairing code', 'Invalid pairing code')}: ${code}\n`));
123
+ console.log(chalk.gray(L(' Bekleyen istekleri görmek için: natureco device-pair list\n', ' To see pending requests: natureco device-pair list\n')));
122
124
  process.exit(1);
123
125
  }
124
126
 
@@ -144,7 +146,7 @@ function approvePairing(code) {
144
146
 
145
147
  function rejectPairing(code) {
146
148
  if (!code) {
147
- console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
149
+ console.log(chalk.red(L('\n ❌ Pairing code gerekli\n', '\n ❌ Pairing code required\n')));
148
150
  process.exit(1);
149
151
  }
150
152
 
@@ -152,7 +154,7 @@ function rejectPairing(code) {
152
154
  const idx = (data.pendingRequests || []).findIndex(p => p.code === code);
153
155
 
154
156
  if (idx === -1) {
155
- console.log(chalk.red(`\n ❌ Geçersiz pairing code: ${code}\n`));
157
+ console.log(chalk.red(`\n ❌ ${L('Geçersiz pairing code', 'Invalid pairing code')}: ${code}\n`));
156
158
  process.exit(1);
157
159
  }
158
160
 
@@ -165,7 +167,7 @@ function rejectPairing(code) {
165
167
 
166
168
  function removeDevice(deviceId) {
167
169
  if (!deviceId) {
168
- console.log(chalk.red('\n ❌ Device ID gerekli\n'));
170
+ console.log(chalk.red(L('\n ❌ Device ID gerekli\n', '\n ❌ Device ID required\n')));
169
171
  console.log(chalk.cyan(' natureco device-pair remove dev_abc123\n'));
170
172
  process.exit(1);
171
173
  }
@@ -174,7 +176,7 @@ function removeDevice(deviceId) {
174
176
  const idx = (data.pairedDevices || []).findIndex(d => d.id === deviceId);
175
177
 
176
178
  if (idx === -1) {
177
- console.log(chalk.red(`\n ❌ Cihaz bulunamadı: ${deviceId}\n`));
179
+ console.log(chalk.red(`\n ❌ ${L('Cihaz bulunamadı', 'Device not found')}: ${deviceId}\n`));
178
180
  process.exit(1);
179
181
  }
180
182
 
@@ -200,7 +202,7 @@ function showPairingCode() {
200
202
 
201
203
  function verifyPairing(code, deviceName) {
202
204
  if (!code) {
203
- console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
205
+ console.log(chalk.red(L('\n ❌ Pairing code gerekli\n', '\n ❌ Pairing code required\n')));
204
206
  process.exit(1);
205
207
  }
206
208
 
@@ -1,5 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
  const tui = require('../utils/tui');
3
+ const { getLang: _gl } = require('../utils/i18n');
4
+ const L = (tr, en) => (_gl() === 'en' ? en : tr);
3
5
  const F = require('../utils/format');
4
6
  const { getConfig, saveConfig } = require('../utils/config');
5
7
  const fs = require('fs');
@@ -20,7 +22,7 @@ function devices(args) {
20
22
  if (action === 'clear') return clearDevices();
21
23
 
22
24
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
23
- console.log(chalk.gray(' Kullanım: natureco devices [list|pair|unpair|remove|token|regenerate-token|rotate|revoke|clear]\n'));
25
+ console.log(chalk.gray(L(' Kullanım: natureco devices [list|pair|unpair|remove|token|regenerate-token|rotate|revoke|clear]\n', ' Usage: natureco devices [list|pair|unpair|remove|token|regenerate-token|rotate|revoke|clear]\n')));
24
26
  process.exit(1);
25
27
  }
26
28
 
@@ -28,12 +30,12 @@ function listDevices() {
28
30
  const config = getConfig();
29
31
  const devices = config.pairedDevices || [];
30
32
 
31
- console.log('\n' + tui.styled(' 📱 Cihaz Listesi', { color: tui.PALETTE.primary, bold: true }));
33
+ console.log('\n' + tui.styled(L(' 📱 Cihaz Listesi', ' 📱 Device List'), { color: tui.PALETTE.primary, bold: true }));
32
34
  console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
33
35
 
34
36
  if (devices.length === 0) {
35
- console.log('\n ' + tui.C.muted('Eşleşmiş cihaz yok.'));
36
- console.log(' ' + tui.C.muted('Eşleştirmek için: ') + tui.C.brand('natureco devices pair <ad> <tip>'));
37
+ console.log('\n ' + tui.C.muted(L('Eşleşmiş cihaz yok.', 'No paired devices.')));
38
+ console.log(' ' + tui.C.muted(L('Eşleştirmek için: ', 'To pair: ')) + tui.C.brand('natureco devices pair <ad> <tip>'));
37
39
  console.log('');
38
40
  return;
39
41
  }
@@ -46,16 +48,16 @@ function listDevices() {
46
48
 
47
49
  console.log('\n' + tui.table(rows, [
48
50
  { key: 'id', label: 'ID', minWidth: 16, render: r => tui.C.muted(r.id) },
49
- { key: 'name', label: 'İsim', minWidth: 14, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
51
+ { key: 'name', label: L('İsim', 'Name'), minWidth: 14, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
50
52
  { key: 'type', label: 'Tip', minWidth: 12, render: r => tui.C.text(r.type) },
51
- { key: 'lastSeen', label: 'Eşleşme', minWidth: 18, render: r => tui.C.muted(r.lastSeen) },
53
+ { key: 'lastSeen', label: L('Eşleşme', 'Pairing'), minWidth: 18, render: r => tui.C.muted(r.lastSeen) },
52
54
  ], { borderStyle: 'round', zebra: true }));
53
55
  console.log('');
54
56
  }
55
57
 
56
58
  function pairDevice(name, type) {
57
59
  if (!name) {
58
- F.error('Device name gerekli');
60
+ F.error(L('Device name gerekli', 'Device name required'));
59
61
  process.exit(1);
60
62
  }
61
63
 
@@ -80,7 +82,7 @@ function pairDevice(name, type) {
80
82
 
81
83
  function unpairDevice(id) {
82
84
  if (!id) {
83
- F.error('Device ID gerekli');
85
+ F.error(L('Device ID gerekli', 'Device ID required'));
84
86
  process.exit(1);
85
87
  }
86
88
 
@@ -89,7 +91,7 @@ function unpairDevice(id) {
89
91
  const idx = devices.findIndex(d => d.id === id);
90
92
 
91
93
  if (idx === -1) {
92
- F.error('Cihaz bulunamadı: ' + id);
94
+ F.error(L('Cihaz bulunamadı: ', 'Device not found: ') + id);
93
95
  process.exit(1);
94
96
  }
95
97
 
@@ -121,7 +123,7 @@ function regenerateToken() {
121
123
 
122
124
  function rotateDevice(deviceId) {
123
125
  if (!deviceId) {
124
- F.error('Device ID gerekli');
126
+ F.error(L('Device ID gerekli', 'Device ID required'));
125
127
  process.exit(1);
126
128
  }
127
129
 
@@ -131,7 +133,7 @@ function rotateDevice(deviceId) {
131
133
 
132
134
  function revokeDevice(deviceId) {
133
135
  if (!deviceId) {
134
- F.error('Device ID gerekli');
136
+ F.error(L('Device ID gerekli', 'Device ID required'));
135
137
  process.exit(1);
136
138
  }
137
139