natureco-cli 5.59.0 → 5.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/audit.js +26 -24
- package/src/commands/code.js +95 -87
- package/src/commands/code_v5.js +58 -56
- package/src/commands/medium.js +32 -30
- package/src/commands/migrate.js +54 -52
- package/src/commands/naturehub.js +32 -30
- package/src/commands/policy.js +32 -30
- package/src/commands/security.js +24 -22
- package/src/commands/seo.js +43 -41
- package/src/commands/xp.js +42 -40
package/src/commands/code_v5.js
CHANGED
|
@@ -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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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}
|
|
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\
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
package/src/commands/medium.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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;
|