natureco-cli 5.60.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/policy.js +32 -30
- package/src/commands/security.js +24 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.61.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"
|
package/src/commands/audit.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const chalk = require('chalk');
|
|
15
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
16
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
15
17
|
const tui = require('../utils/tui');
|
|
16
18
|
const F = require('../utils/format');
|
|
17
19
|
const fs = require('fs');
|
|
@@ -53,11 +55,11 @@ function formatEntry(entry) {
|
|
|
53
55
|
|
|
54
56
|
function showEntries(entries, limit = 50) {
|
|
55
57
|
if (entries.length === 0) {
|
|
56
|
-
console.log(tui.C.muted('\n Kayıt yok.\n'));
|
|
58
|
+
console.log(tui.C.muted(L('\n Kayıt yok.\n', '\n No records.\n')));
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
const slice = entries.slice(-limit);
|
|
60
|
-
console.log(tui.styled(`\n 📋 ${entries.length} kayıt${limit < entries.length ? ` (son ${limit})` : ''}`, { color: tui.PALETTE.primary, bold: true }));
|
|
62
|
+
console.log(tui.styled(`\n 📋 ${entries.length} ${L('kayıt', 'records')}${limit < entries.length ? ` (${L('son', 'last')} ${limit})` : ''}`, { color: tui.PALETTE.primary, bold: true }));
|
|
61
63
|
|
|
62
64
|
// Yeni TUI tablo
|
|
63
65
|
const rows = slice.map(e => ({
|
|
@@ -69,9 +71,9 @@ function showEntries(entries, limit = 50) {
|
|
|
69
71
|
}));
|
|
70
72
|
|
|
71
73
|
console.log('\n' + tui.table(rows, [
|
|
72
|
-
{ key: 'ts', label: 'Saat', minWidth: 10, render: r => tui.C.muted(r.ts) },
|
|
74
|
+
{ key: 'ts', label: L('Saat', 'Time'), minWidth: 10, render: r => tui.C.muted(r.ts) },
|
|
73
75
|
{ key: 'action', label: 'Action', minWidth: 22, render: r => colorizeAction(r.action) },
|
|
74
|
-
{ key: 'data', label: 'Veri', minWidth: 30, render: r => tui.C.dim(r.data) },
|
|
76
|
+
{ key: 'data', label: L('Veri', 'Data'), minWidth: 30, render: r => tui.C.dim(r.data) },
|
|
75
77
|
], { borderStyle: 'round', zebra: true }));
|
|
76
78
|
console.log('');
|
|
77
79
|
}
|
|
@@ -88,10 +90,10 @@ function audit_cmd(args) {
|
|
|
88
90
|
|
|
89
91
|
if (action === 'stats') {
|
|
90
92
|
const stats = audit.stats24h();
|
|
91
|
-
console.log('\n' + tui.styled(' 📊 Son 24 Saat Audit İstatistiği', { color: tui.PALETTE.primary, bold: true }));
|
|
93
|
+
console.log('\n' + tui.styled(L(' 📊 Son 24 Saat Audit İstatistiği', ' 📊 Last 24h Audit Stats'), { color: tui.PALETTE.primary, bold: true }));
|
|
92
94
|
console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
|
|
93
|
-
console.log('\n ' + tui.C.muted('Dönem: ') + tui.C.text(stats.period));
|
|
94
|
-
console.log(' ' + tui.C.muted('Toplam kayıt: ') + tui.styled(String(stats.total), { color: tui.PALETTE.primary, bold: true }));
|
|
95
|
+
console.log('\n ' + tui.C.muted(L('Dönem: ', 'Period: ')) + tui.C.text(stats.period));
|
|
96
|
+
console.log(' ' + tui.C.muted(L('Toplam kayıt: ', 'Total records: ')) + tui.styled(String(stats.total), { color: tui.PALETTE.primary, bold: true }));
|
|
95
97
|
console.log('');
|
|
96
98
|
|
|
97
99
|
// TUI tablo ile
|
|
@@ -106,8 +108,8 @@ function audit_cmd(args) {
|
|
|
106
108
|
if (rows.length > 0) {
|
|
107
109
|
console.log(tui.table(rows, [
|
|
108
110
|
{ key: 'action', label: 'Action', minWidth: 22, render: r => colorizeAction(r.action) },
|
|
109
|
-
{ key: 'count', label: 'Sayı', minWidth: 6, render: r => tui.styled(r.count, { color: tui.PALETTE.secondary, bold: true }) },
|
|
110
|
-
{ key: 'bar', label: 'Dağılım', minWidth: 22, render: r => tui.styled(r.bar, { color: tui.PALETTE.primary }) },
|
|
111
|
+
{ key: 'count', label: L('Sayı', 'Count'), minWidth: 6, render: r => tui.styled(r.count, { color: tui.PALETTE.secondary, bold: true }) },
|
|
112
|
+
{ key: 'bar', label: L('Dağılım', 'Distribution'), minWidth: 22, render: r => tui.styled(r.bar, { color: tui.PALETTE.primary }) },
|
|
111
113
|
], { borderStyle: 'round', zebra: true }));
|
|
112
114
|
}
|
|
113
115
|
console.log('');
|
|
@@ -118,7 +120,7 @@ function audit_cmd(args) {
|
|
|
118
120
|
const date = params[0] || new Date().toISOString().slice(0, 10);
|
|
119
121
|
const entries = audit.readLog(date);
|
|
120
122
|
if (entries.length === 0) {
|
|
121
|
-
console.log(chalk.yellow(`\n ⚠️ ${date} için kayıt yok
|
|
123
|
+
console.log(chalk.yellow(`\n ⚠️ ${date} ${L('için kayıt yok.', '— no records.')}\n`));
|
|
122
124
|
return;
|
|
123
125
|
}
|
|
124
126
|
showEntries(entries, 9999);
|
|
@@ -127,18 +129,18 @@ function audit_cmd(args) {
|
|
|
127
129
|
|
|
128
130
|
if (action === 'cleanup') {
|
|
129
131
|
const removed = audit.cleanup();
|
|
130
|
-
console.log(chalk.green(`\n ✓ ${removed} eski log dosyası temizlendi (30 gün+)
|
|
132
|
+
console.log(chalk.green(`\n ✓ ${removed} ${L('eski log dosyası temizlendi (30 gün+).', 'old log files cleaned (30 days+).')}\n`));
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
if (action === 'tail') {
|
|
135
|
-
console.log(chalk.cyan('\n 📡 Canlı audit log (Ctrl+C ile çık)...\n'));
|
|
137
|
+
console.log(chalk.cyan(L('\n 📡 Canlı audit log (Ctrl+C ile çık)...\n', '\n 📡 Live audit log (Ctrl+C to exit)...\n')));
|
|
136
138
|
let lastSize = 0;
|
|
137
139
|
const todayFile = audit.listLogFiles()[0];
|
|
138
140
|
const interval = setInterval(() => {
|
|
139
141
|
const current = audit.listLogFiles()[0];
|
|
140
142
|
if (current !== todayFile) {
|
|
141
|
-
console.log(chalk.gray(`\n ── yeni gün: ${current} ──`));
|
|
143
|
+
console.log(chalk.gray(`\n ── ${L('yeni gün', 'new day')}: ${current} ──`));
|
|
142
144
|
}
|
|
143
145
|
const file = path.join(audit.AUDIT_DIR, audit.listLogFiles()[0]);
|
|
144
146
|
try {
|
|
@@ -167,7 +169,7 @@ function audit_cmd(args) {
|
|
|
167
169
|
if (action === 'search') {
|
|
168
170
|
const query = params.join(' ').toLowerCase();
|
|
169
171
|
if (!query) {
|
|
170
|
-
console.log(chalk.red('\n ❌ Arama terimi gerekli: natureco audit search <query>\n'));
|
|
172
|
+
console.log(chalk.red(L('\n ❌ Arama terimi gerekli: natureco audit search <query>\n', '\n ❌ Search term required: natureco audit search <query>\n')));
|
|
171
173
|
return;
|
|
172
174
|
}
|
|
173
175
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -183,7 +185,7 @@ function audit_cmd(args) {
|
|
|
183
185
|
|
|
184
186
|
if (action === 'files') {
|
|
185
187
|
const files = audit.listLogFiles();
|
|
186
|
-
console.log(chalk.bold('\n 📁 Audit log dosyaları:\n'));
|
|
188
|
+
console.log(chalk.bold(L('\n 📁 Audit log dosyaları:\n', '\n 📁 Audit log files:\n')));
|
|
187
189
|
for (const f of files) {
|
|
188
190
|
const stat = fs.statSync(path.join(audit.AUDIT_DIR, f));
|
|
189
191
|
const size = (stat.size / 1024).toFixed(1);
|
|
@@ -194,15 +196,15 @@ function audit_cmd(args) {
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
// Yardım
|
|
197
|
-
console.log(chalk.yellow('\n Kullanım:'));
|
|
198
|
-
console.log(chalk.gray(' natureco audit Bugünkü logları göster'));
|
|
199
|
-
console.log(chalk.gray(' natureco audit today Bugünkü tüm loglar'));
|
|
200
|
-
console.log(chalk.gray(' natureco audit stats 24 saat istatistik'));
|
|
201
|
-
console.log(chalk.gray(' natureco audit show <date> Belirli gün (YYYY-MM-DD)'));
|
|
202
|
-
console.log(chalk.gray(' natureco audit search <q> Log ara'));
|
|
203
|
-
console.log(chalk.gray(' natureco audit files Dosya listesi'));
|
|
204
|
-
console.log(chalk.gray(' natureco audit cleanup 30 günden eski logları sil'));
|
|
205
|
-
console.log(chalk.gray(' natureco audit tail Canlı akış'));
|
|
199
|
+
console.log(chalk.yellow(L('\n Kullanım:', '\n Usage:')));
|
|
200
|
+
console.log(chalk.gray(L(' natureco audit Bugünkü logları göster', ' natureco audit Show today\'s logs')));
|
|
201
|
+
console.log(chalk.gray(L(' natureco audit today Bugünkü tüm loglar', ' natureco audit today All of today\'s logs')));
|
|
202
|
+
console.log(chalk.gray(L(' natureco audit stats 24 saat istatistik', ' natureco audit stats 24-hour stats')));
|
|
203
|
+
console.log(chalk.gray(L(' natureco audit show <date> Belirli gün (YYYY-MM-DD)', ' natureco audit show <date> Specific day (YYYY-MM-DD)')));
|
|
204
|
+
console.log(chalk.gray(L(' natureco audit search <q> Log ara', ' natureco audit search <q> Search logs')));
|
|
205
|
+
console.log(chalk.gray(L(' natureco audit files Dosya listesi', ' natureco audit files File list')));
|
|
206
|
+
console.log(chalk.gray(L(' natureco audit cleanup 30 günden eski logları sil', ' natureco audit cleanup Delete logs older than 30 days')));
|
|
207
|
+
console.log(chalk.gray(L(' natureco audit tail Canlı akış', ' natureco audit tail Live stream')));
|
|
206
208
|
console.log('');
|
|
207
209
|
}
|
|
208
210
|
|
package/src/commands/code.js
CHANGED
|
@@ -6,6 +6,8 @@ const { execSync } = require('child_process');
|
|
|
6
6
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
7
7
|
const TB = require('../utils/token-budget');
|
|
8
8
|
const chalk = require('chalk');
|
|
9
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
10
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
9
11
|
const { getApiKey, getConfig } = require('../utils/config');
|
|
10
12
|
const { getBots, getProviderConfig, startMcpServers, sendMessageOpenAICompatible, streamProviderCompletion } = require('../utils/api');
|
|
11
13
|
const { getMemoryPrompt, loadMemory } = require('../utils/memory');
|
|
@@ -18,9 +20,9 @@ let rl = null;
|
|
|
18
20
|
|
|
19
21
|
async function confirmAction(message) {
|
|
20
22
|
return new Promise(resolve => {
|
|
21
|
-
rl.question(chalk.yellow(`⚠ ${message}\n[? Devam edilsin mi? (Y/n) `), answer => {
|
|
23
|
+
rl.question(chalk.yellow(`⚠ ${message}\n[? ${L('Devam edilsin mi', 'Continue')}? (Y/n) `), answer => {
|
|
22
24
|
const confirmed = !answer || answer.toLowerCase() === 'y';
|
|
23
|
-
console.log(chalk.gray(` ✓ Devam edilsin mi? ${confirmed ? 'Yes' : 'No'}`));
|
|
25
|
+
console.log(chalk.gray(` ✓ ${L('Devam edilsin mi', 'Continue')}? ${confirmed ? 'Yes' : 'No'}`));
|
|
24
26
|
resolve(confirmed);
|
|
25
27
|
});
|
|
26
28
|
});
|
|
@@ -169,24 +171,24 @@ function loadProjectMemory(workDir) {
|
|
|
169
171
|
|
|
170
172
|
async function generateSummary(messages, providerConfig) {
|
|
171
173
|
const recent = messages.filter(m => m.role !== 'system').slice(-12);
|
|
172
|
-
if (!recent.length) return 'Bu session boş geçti.';
|
|
173
|
-
const prompt =
|
|
174
|
+
if (!recent.length) return L('Bu session boş geçti.', 'This session was empty.');
|
|
175
|
+
const prompt = `${L("Bu kod session'ını 3-5 madde halinde Türkçe özetle. Ne yapıldı, hangi dosyalar değiştirildi, hangi sorunlar çözüldü", 'Summarize this code session in 3-5 bullet points in English. What was done, which files changed, which issues were solved')}:\n${JSON.stringify(recent).slice(0, 3000)}`;
|
|
174
176
|
try {
|
|
175
177
|
const result = await sendMessageOpenAICompatible(providerConfig, [{ role: 'user', content: prompt }], []);
|
|
176
|
-
return result.content || 'Özet oluşturulamadı.';
|
|
178
|
+
return result.content || L('Özet oluşturulamadı.', 'Could not generate summary.');
|
|
177
179
|
} catch {
|
|
178
|
-
return 'Özet oluşturulamadı.';
|
|
180
|
+
return L('Özet oluşturulamadı.', 'Could not generate summary.');
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
async function saveProjectMemory(messages, providerConfig, workDir) {
|
|
183
|
-
const sp = startSpinner('Proje hafızası güncelleniyor...');
|
|
185
|
+
const sp = startSpinner(L('Proje hafızası güncelleniyor...', 'Updating project memory...'));
|
|
184
186
|
const summary = await generateSummary(messages, providerConfig);
|
|
185
|
-
stopSpinner(sp, 'Proje hafızası güncellendi', true);
|
|
187
|
+
stopSpinner(sp, L('Proje hafızası güncellendi', 'Project memory updated'), true);
|
|
186
188
|
const memPath = getProjectMemoryPath(workDir);
|
|
187
189
|
const dir = path.dirname(memPath);
|
|
188
190
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
189
|
-
const existing = fs.existsSync(memPath) ? fs.readFileSync(memPath, 'utf8') : '# Proje Hafızası\n';
|
|
191
|
+
const existing = fs.existsSync(memPath) ? fs.readFileSync(memPath, 'utf8') : L('# Proje Hafızası\n', '# Project Memory\n');
|
|
190
192
|
const entry = `\n## ${new Date().toLocaleDateString('tr-TR')} — ${new Date().toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' })}\n${summary}\n`;
|
|
191
193
|
fs.writeFileSync(memPath, existing + entry);
|
|
192
194
|
}
|
|
@@ -195,8 +197,8 @@ async function saveProjectMemory(messages, providerConfig, workDir) {
|
|
|
195
197
|
async function generateCommitMessage(diff, providerConfig) {
|
|
196
198
|
try {
|
|
197
199
|
const result = await sendMessageOpenAICompatible(providerConfig, [
|
|
198
|
-
{ role: 'system', content: 'Sen bir git commit mesajı üreticisin. Conventional Commits formatında (feat/fix/refactor/chore vb.) kısa ve açıklayıcı bir commit mesajı yaz. Sadece mesajı yaz, başka hiçbir şey yazma.' },
|
|
199
|
-
{ role: 'user', content:
|
|
200
|
+
{ role: 'system', content: L('Sen bir git commit mesajı üreticisin. Conventional Commits formatında (feat/fix/refactor/chore vb.) kısa ve açıklayıcı bir commit mesajı yaz. Sadece mesajı yaz, başka hiçbir şey yazma.', 'You are a git commit message generator. Write a short, descriptive commit message in Conventional Commits format (feat/fix/refactor/chore etc.). Write only the message, nothing else.') },
|
|
201
|
+
{ role: 'user', content: `${L('Bu diff için commit mesajı üret', 'Generate a commit message for this diff')}:\n\n${diff}` },
|
|
200
202
|
], []);
|
|
201
203
|
return (result.content || 'chore: update files').trim().replace(/^["']|["']$/g, '');
|
|
202
204
|
} catch {
|
|
@@ -243,19 +245,19 @@ async function runToolCall(toolCall, stats, dryRun = false) {
|
|
|
243
245
|
oldLines.forEach(line => {
|
|
244
246
|
if (line && !newLines.includes(line)) console.log(chalk.red(' - ' + line));
|
|
245
247
|
});
|
|
246
|
-
console.log(chalk.yellow('\n ⚠️ DRY RUN — dosya değiştirilmedi\n'));
|
|
248
|
+
console.log(chalk.yellow(L('\n ⚠️ DRY RUN — dosya değiştirilmedi\n', '\n ⚠️ DRY RUN — no file changed\n')));
|
|
247
249
|
stats.filesChanged++;
|
|
248
250
|
stats.changedFiles.push(toolCall.input.path || '?');
|
|
249
251
|
stats.toolCallCount++;
|
|
250
|
-
return { success: true, output: '[DRY RUN] Değişiklik gösterildi, uygulanmadı' };
|
|
252
|
+
return { success: true, output: L('[DRY RUN] Değişiklik gösterildi, uygulanmadı', '[DRY RUN] Change shown, not applied') };
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
if (needsConfirm) {
|
|
254
256
|
console.log(chalk.yellow(`\n ⚠️ ${toolCall.name}: ${inputPreview}`));
|
|
255
|
-
const ok = await confirmAction('Devam edilsin mi?');
|
|
257
|
+
const ok = await confirmAction(L('Devam edilsin mi?', 'Continue?'));
|
|
256
258
|
if (!ok) {
|
|
257
|
-
console.log(chalk.gray(' İptal edildi.\n'));
|
|
258
|
-
return { success: false, output: 'Kullanıcı iptal etti.' };
|
|
259
|
+
console.log(chalk.gray(L(' İptal edildi.\n', ' Cancelled.\n')));
|
|
260
|
+
return { success: false, output: L('Kullanıcı iptal etti.', 'User cancelled.') };
|
|
259
261
|
}
|
|
260
262
|
}
|
|
261
263
|
|
|
@@ -267,9 +269,9 @@ async function runToolCall(toolCall, stats, dryRun = false) {
|
|
|
267
269
|
if (toolCall.name === 'write_file') {
|
|
268
270
|
stats.filesChanged++;
|
|
269
271
|
stats.changedFiles.push(toolCall.input.path || '?');
|
|
270
|
-
console.log(chalk.green(` ✓ ${toolCall.input.path} güncellendi`));
|
|
272
|
+
console.log(chalk.green(` ✓ ${toolCall.input.path} ${L('güncellendi', 'updated')}`));
|
|
271
273
|
if (stats.changedFiles.length === 1) {
|
|
272
|
-
console.log(chalk.gray(` 💡 git add . && /commit ile kaydet`));
|
|
274
|
+
console.log(chalk.gray(` 💡 git add . && /commit ${L('ile kaydet', 'to save')}`));
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
if (toolCall.name === 'bash') stats.commandsRun++;
|
|
@@ -284,24 +286,24 @@ async function runTests(projectIndex, conversationMessages, tools, providerConfi
|
|
|
284
286
|
const testScript = projectIndex.packageJson?.scripts?.test;
|
|
285
287
|
if (!testScript || testScript.includes('no test')) return;
|
|
286
288
|
|
|
287
|
-
const confirmed = await confirmAction('🧪 Testleri çalıştıralım mı?');
|
|
289
|
+
const confirmed = await confirmAction(L('🧪 Testleri çalıştıralım mı?', '🧪 Run the tests?'));
|
|
288
290
|
if (!confirmed) return;
|
|
289
291
|
|
|
290
|
-
console.log(chalk.gray('\n npm test çalışıyor...\n'));
|
|
292
|
+
console.log(chalk.gray(L('\n npm test çalışıyor...\n', '\n npm test running...\n')));
|
|
291
293
|
try {
|
|
292
294
|
const output = execSync('npm test', {
|
|
293
295
|
cwd: workDir, timeout: 30000, stdio: 'pipe',
|
|
294
296
|
}).toString();
|
|
295
|
-
console.log(chalk.green(' ✅ Testler geçti!\n'));
|
|
297
|
+
console.log(chalk.green(L(' ✅ Testler geçti!\n', ' ✅ Tests passed!\n')));
|
|
296
298
|
} catch (err) {
|
|
297
299
|
const errOutput = (err.stdout?.toString() || err.message || '').slice(0, 500);
|
|
298
|
-
console.log(chalk.red(' ❌ Test hatası:\n'));
|
|
300
|
+
console.log(chalk.red(L(' ❌ Test hatası:\n', ' ❌ Test error:\n')));
|
|
299
301
|
console.log(chalk.gray(' ' + errOutput.split('\n').join('\n ')));
|
|
300
302
|
console.log();
|
|
301
303
|
|
|
302
|
-
const fix = await confirmAction('Agent test hatasını düzeltsin mi?');
|
|
304
|
+
const fix = await confirmAction(L('Agent test hatasını düzeltsin mi?', 'Let the agent fix the test error?'));
|
|
303
305
|
if (fix) {
|
|
304
|
-
return
|
|
306
|
+
return `${L('Test hatası oluştu', 'A test error occurred')}:\n${errOutput}\n${L('Bu hatayı düzelt.', 'Fix this error.')}`;
|
|
305
307
|
}
|
|
306
308
|
}
|
|
307
309
|
return null;
|
|
@@ -335,7 +337,7 @@ async function code(targetFile, options = {}) {
|
|
|
335
337
|
if (!bot) {
|
|
336
338
|
process.stdin.resume();
|
|
337
339
|
const { selectedBot } = await inquirer.prompt([{
|
|
338
|
-
type: 'list', name: 'selectedBot', message: 'Bot seçin:',
|
|
340
|
+
type: 'list', name: 'selectedBot', message: L('Bot seçin:', 'Select bot:'),
|
|
339
341
|
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
340
342
|
}]);
|
|
341
343
|
bot = botList.bots.find(b => b.id === selectedBot);
|
|
@@ -347,29 +349,35 @@ async function code(targetFile, options = {}) {
|
|
|
347
349
|
const providerConfig = getProviderConfig();
|
|
348
350
|
|
|
349
351
|
if (!providerConfig) {
|
|
350
|
-
console.log(chalk.red('\n❌ Provider yapılandırılmamış. natureco config set providerUrl ...\n'));
|
|
352
|
+
console.log(chalk.red(L('\n❌ Provider yapılandırılmamış. natureco config set providerUrl ...\n', '\n❌ Provider not configured. natureco config set providerUrl ...\n')));
|
|
351
353
|
process.exit(1);
|
|
352
354
|
}
|
|
353
355
|
|
|
354
356
|
const shortModel = providerConfig.model.split('/').pop().split('-').slice(0, 3).join('-');
|
|
355
357
|
|
|
356
358
|
// ── Proje indexing ───────────────────────────────────────────────────────────
|
|
357
|
-
const indexSpinner = startSpinner('Proje indexleniyor...');
|
|
359
|
+
const indexSpinner = startSpinner(L('Proje indexleniyor...', 'Indexing project...'));
|
|
358
360
|
const projectIndex = await indexProject(workDir);
|
|
359
|
-
stopSpinner(indexSpinner, `${projectIndex.type.toUpperCase()} projesi — ${projectIndex.files.length} dosya`, true);
|
|
361
|
+
stopSpinner(indexSpinner, `${projectIndex.type.toUpperCase()} ${L('projesi', 'project')} — ${projectIndex.files.length} ${L('dosya', 'files')}`, true);
|
|
360
362
|
|
|
361
363
|
// ── Sistem prompt ────────────────────────────────────────────────────────────
|
|
362
364
|
const agentsPrompt = getAgentsPrompt();
|
|
363
365
|
const memoryPrompt = getMemoryPrompt(bot.id);
|
|
364
366
|
const indexPrompt = buildIndexPrompt(projectIndex);
|
|
365
367
|
|
|
366
|
-
let systemPrompt = `
|
|
368
|
+
let systemPrompt = (_gl() === 'en' ? `You are the NatureCo Code Agent — a powerful AI coding assistant.
|
|
369
|
+
Actually work in the user's project: read files, change them, run commands.
|
|
370
|
+
ALWAYS explain every step in English. Say what you'll do before making changes.
|
|
371
|
+
Catch and fix errors. Give a summary when done.
|
|
372
|
+
User: ${userName}
|
|
373
|
+
|
|
374
|
+
${indexPrompt}` : `Sen NatureCo Code Agent'sın — güçlü bir AI coding asistanı.
|
|
367
375
|
Kullanıcının projesinde gerçekten çalış: dosyaları oku, değiştir, komutları çalıştır.
|
|
368
376
|
Her adımı Türkçe açıkla. Değişiklik yapmadan önce ne yapacağını söyle.
|
|
369
377
|
Hataları yakala ve düzelt. İş bitince özet sun.
|
|
370
378
|
Kullanıcı: ${userName}
|
|
371
379
|
|
|
372
|
-
${indexPrompt}
|
|
380
|
+
${indexPrompt}`);
|
|
373
381
|
|
|
374
382
|
if (agentsPrompt) systemPrompt += `\n\n## Project Instructions\n${agentsPrompt}`;
|
|
375
383
|
if (memoryPrompt) systemPrompt += '\n\n' + memoryPrompt;
|
|
@@ -384,9 +392,9 @@ ${indexPrompt}`;
|
|
|
384
392
|
if (targetFile) {
|
|
385
393
|
try {
|
|
386
394
|
const content = fs.readFileSync(path.resolve(targetFile), 'utf-8');
|
|
387
|
-
systemPrompt += `\n\n## Odak
|
|
395
|
+
systemPrompt += `\n\n## ${L('Odak Dosyası', 'Focus File')}: ${targetFile}\n\`\`\`\n${TB.trimFileContent(content)}\n\`\`\``;
|
|
388
396
|
} catch {
|
|
389
|
-
console.log(chalk.yellow(` ⚠️ ${targetFile}
|
|
397
|
+
console.log(chalk.yellow(` ⚠️ ${targetFile} ${L('okunamadı', 'could not be read')}\n`));
|
|
390
398
|
}
|
|
391
399
|
}
|
|
392
400
|
|
|
@@ -422,16 +430,16 @@ ${indexPrompt}`;
|
|
|
422
430
|
].join('\n');
|
|
423
431
|
console.log(centerText(chalk.green(codeLogo)));
|
|
424
432
|
console.log();
|
|
425
|
-
console.log(centerText(chalk.cyan(`(\\_/) ${displayBotName} hazır`) + chalk.gray(` · v${version}`)));
|
|
433
|
+
console.log(centerText(chalk.cyan(`(\\_/) ${displayBotName} ${L('hazır', 'ready')}`) + chalk.gray(` · v${version}`)));
|
|
426
434
|
console.log(sep());
|
|
427
|
-
console.log(centerText(chalk.gray(`📁 ${projectIndex.type.toUpperCase()} projesi · ${projectIndex.files.length} dosya`)));
|
|
435
|
+
console.log(centerText(chalk.gray(`📁 ${projectIndex.type.toUpperCase()} ${L('projesi', 'project')} · ${projectIndex.files.length} ${L('dosya', 'files')}`)));
|
|
428
436
|
if (projectIndex.gitBranch) {
|
|
429
437
|
const changes = projectIndex.gitStatus?.length || 0;
|
|
430
|
-
console.log(centerText(chalk.gray(`🌿 ${projectIndex.gitBranch} · ${changes} değişiklik`)));
|
|
438
|
+
console.log(centerText(chalk.gray(`🌿 ${projectIndex.gitBranch} · ${changes} ${L('değişiklik', 'changes')}`)));
|
|
431
439
|
}
|
|
432
440
|
if (targetFile) console.log(centerText(chalk.gray(`📄 ${targetFile}`)));
|
|
433
|
-
if (projectMemory) console.log(centerText(chalk.gray(`📋 Proje hafızası yüklendi`)));
|
|
434
|
-
console.log(centerText(chalk.gray(`${shortModel} · /help · Ctrl+C
|
|
441
|
+
if (projectMemory) console.log(centerText(chalk.gray(`📋 ${L('Proje hafızası yüklendi', 'Project memory loaded')}`)));
|
|
442
|
+
console.log(centerText(chalk.gray(`${shortModel} · /help · Ctrl+C ${L('çıkış', 'exit')}`)));
|
|
435
443
|
console.log(sep());
|
|
436
444
|
console.log();
|
|
437
445
|
|
|
@@ -439,16 +447,16 @@ ${indexPrompt}`;
|
|
|
439
447
|
function showSummary() {
|
|
440
448
|
const w = process.stdout.columns || 120;
|
|
441
449
|
console.log(chalk.gray('\n' + '─'.repeat(w)));
|
|
442
|
-
console.log(chalk.gray(' Agent Session Özeti'));
|
|
443
|
-
if (options.dryRun) console.log(chalk.yellow(' ⚠️ DRY RUN — hiçbir dosya değiştirilmedi'));
|
|
450
|
+
console.log(chalk.gray(L(' Agent Session Özeti', ' Agent Session Summary')));
|
|
451
|
+
if (options.dryRun) console.log(chalk.yellow(L(' ⚠️ DRY RUN — hiçbir dosya değiştirilmedi', ' ⚠️ DRY RUN — no files changed')));
|
|
444
452
|
console.log(chalk.gray('─'.repeat(w)));
|
|
445
|
-
console.log(` ${chalk.green('✓')} ${stats.filesChanged} dosya değiştirildi`);
|
|
446
|
-
console.log(` ${chalk.green('✓')} ${stats.commandsRun} komut
|
|
447
|
-
console.log(` ${chalk.green('✓')} ${stats.toolCallCount} tool çağrısı
|
|
448
|
-
console.log(` ${chalk.cyan('◉')} ${stats.messageCount} mesaj`);
|
|
453
|
+
console.log(` ${chalk.green('✓')} ${stats.filesChanged} ${L('dosya değiştirildi', 'files changed')}`);
|
|
454
|
+
console.log(` ${chalk.green('✓')} ${stats.commandsRun} ${L('komut çalıştırıldı', 'commands run')}`);
|
|
455
|
+
console.log(` ${chalk.green('✓')} ${stats.toolCallCount} ${L('tool çağrısı yapıldı', 'tool calls made')}`);
|
|
456
|
+
console.log(` ${chalk.cyan('◉')} ${stats.messageCount} ${L('mesaj', 'messages')}`);
|
|
449
457
|
if (stats.changedFiles.length > 0) {
|
|
450
458
|
console.log();
|
|
451
|
-
console.log(chalk.cyan(` 📝 Değiştirilen dosyalar (${stats.changedFiles.length}):`));
|
|
459
|
+
console.log(chalk.cyan(` 📝 ${L('Değiştirilen dosyalar', 'Changed files')} (${stats.changedFiles.length}):`));
|
|
452
460
|
stats.changedFiles.forEach(f => console.log(chalk.white(` ${f}`)));
|
|
453
461
|
}
|
|
454
462
|
console.log(chalk.gray('─'.repeat(w)));
|
|
@@ -457,24 +465,24 @@ ${indexPrompt}`;
|
|
|
457
465
|
|
|
458
466
|
// ── Komut çalıştır + hata döngüsü ───────────────────────────────────────────
|
|
459
467
|
async function runAndFix(cmd) {
|
|
460
|
-
console.log(chalk.gray(`\n ▶ ${cmd} çalıştırılıyor
|
|
468
|
+
console.log(chalk.gray(`\n ▶ ${cmd} ${L('çalıştırılıyor...', 'running...')}\n`));
|
|
461
469
|
try {
|
|
462
470
|
const output = execSync(cmd, {
|
|
463
471
|
cwd: workDir, timeout: 30000, stdio: 'pipe',
|
|
464
472
|
}).toString();
|
|
465
|
-
console.log(chalk.green(' ✓ Başarılı:'));
|
|
473
|
+
console.log(chalk.green(L(' ✓ Başarılı:', ' ✓ Success:')));
|
|
466
474
|
console.log(chalk.gray(' ' + output.slice(0, 500).split('\n').join('\n ')));
|
|
467
475
|
console.log();
|
|
468
476
|
} catch (err) {
|
|
469
477
|
const errorOutput = (err.stderr?.toString() || err.stdout?.toString() || err.message || '').slice(0, 500);
|
|
470
|
-
console.log(chalk.red(' ✗ Hata:'));
|
|
478
|
+
console.log(chalk.red(L(' ✗ Hata:', ' ✗ Error:')));
|
|
471
479
|
console.log(chalk.gray(' ' + errorOutput.split('\n').join('\n ')));
|
|
472
480
|
console.log();
|
|
473
481
|
|
|
474
|
-
const fix = await confirmAction('Hatayı otomatik düzeltmemi ister misin?');
|
|
482
|
+
const fix = await confirmAction(L('Hatayı otomatik düzeltmemi ister misin?', 'Want me to auto-fix the error?'));
|
|
475
483
|
if (fix) {
|
|
476
|
-
const fixMessage =
|
|
477
|
-
console.log(chalk.cyan('\n Düzeltiliyor...\n'));
|
|
484
|
+
const fixMessage = `${L('Şu komut çalıştırıldı', 'This command was run')}: ${cmd}\n${L('Hata oluştu', 'An error occurred')}:\n${errorOutput}\n${L('Bu hatayı analiz et ve düzelt.', 'Analyze and fix this error.')}`;
|
|
485
|
+
console.log(chalk.cyan(L('\n Düzeltiliyor...\n', '\n Fixing...\n')));
|
|
478
486
|
await handleMessage(fixMessage);
|
|
479
487
|
}
|
|
480
488
|
}
|
|
@@ -489,20 +497,20 @@ ${indexPrompt}`;
|
|
|
489
497
|
const [cmd] = userMessage.slice(1).split(' ');
|
|
490
498
|
switch (cmd.toLowerCase()) {
|
|
491
499
|
case 'help':
|
|
492
|
-
console.log(chalk.yellow('Code Agent Komutları:'));
|
|
500
|
+
console.log(chalk.yellow(L('Code Agent Komutları:', 'Code Agent Commands:')));
|
|
493
501
|
[
|
|
494
|
-
['/clear', 'Ekranı temizle'],
|
|
495
|
-
['/summary', 'Session özetini göster ve kaydet'],
|
|
496
|
-
['/memory', 'Proje hafızasını göster'],
|
|
497
|
-
['/done', 'Bitir ve özet göster'],
|
|
498
|
-
['/index', 'Projeyi yeniden indexle'],
|
|
499
|
-
['/run <cmd>','Komutu çalıştır, hata varsa düzelt'],
|
|
500
|
-
['/test', 'Testleri çalıştır, hata varsa düzelt'],
|
|
501
|
-
['/git', 'Git durumu ve son commitler'],
|
|
502
|
-
['/commit', 'Staged değişiklikleri AI ile commit et'],
|
|
503
|
-
['/help', 'Bu yardım'],
|
|
502
|
+
['/clear', L('Ekranı temizle', 'Clear the screen')],
|
|
503
|
+
['/summary', L('Session özetini göster ve kaydet', 'Show and save session summary')],
|
|
504
|
+
['/memory', L('Proje hafızasını göster', 'Show project memory')],
|
|
505
|
+
['/done', L('Bitir ve özet göster', 'Finish and show summary')],
|
|
506
|
+
['/index', L('Projeyi yeniden indexle', 'Re-index the project')],
|
|
507
|
+
['/run <cmd>',L('Komutu çalıştır, hata varsa düzelt', 'Run command, fix errors if any')],
|
|
508
|
+
['/test', L('Testleri çalıştır, hata varsa düzelt', 'Run tests, fix errors if any')],
|
|
509
|
+
['/git', L('Git durumu ve son commitler', 'Git status and recent commits')],
|
|
510
|
+
['/commit', L('Staged değişiklikleri AI ile commit et', 'Commit staged changes with AI')],
|
|
511
|
+
['/help', L('Bu yardım', 'This help')],
|
|
504
512
|
].forEach(([c, d]) => console.log(' ' + chalk.cyan(c.padEnd(12)) + chalk.gray(d)));
|
|
505
|
-
console.log(chalk.gray(' Ctrl+C'.padEnd(14) + 'Çıkış'));
|
|
513
|
+
console.log(chalk.gray(' Ctrl+C'.padEnd(14) + L('Çıkış', 'Exit')));
|
|
506
514
|
console.log();
|
|
507
515
|
return;
|
|
508
516
|
case 'clear':
|
|
@@ -511,7 +519,7 @@ ${indexPrompt}`;
|
|
|
511
519
|
case 'summary':
|
|
512
520
|
case 'done': {
|
|
513
521
|
const sum = await generateSummary(conversationMessages, providerConfig);
|
|
514
|
-
console.log(chalk.yellow('\n 📝 Session Özeti:'));
|
|
522
|
+
console.log(chalk.yellow(L('\n 📝 Session Özeti:', '\n 📝 Session Summary:')));
|
|
515
523
|
console.log(chalk.white(' ' + sum.split('\n').join('\n ')));
|
|
516
524
|
console.log();
|
|
517
525
|
showSummary();
|
|
@@ -521,17 +529,17 @@ ${indexPrompt}`;
|
|
|
521
529
|
case 'memory': {
|
|
522
530
|
const mem = loadProjectMemory();
|
|
523
531
|
if (mem) {
|
|
524
|
-
console.log(chalk.yellow('\n 📋 Proje Hafızası:'));
|
|
532
|
+
console.log(chalk.yellow(L('\n 📋 Proje Hafızası:', '\n 📋 Project Memory:')));
|
|
525
533
|
console.log(chalk.gray(' ' + mem.slice(0, 1500).split('\n').join('\n ')));
|
|
526
534
|
} else {
|
|
527
|
-
console.log(chalk.gray('\n Henüz proje hafızası yok. /done ile kaydet.\n'));
|
|
535
|
+
console.log(chalk.gray(L('\n Henüz proje hafızası yok. /done ile kaydet.\n', '\n No project memory yet. Save with /done.\n')));
|
|
528
536
|
}
|
|
529
537
|
return;
|
|
530
538
|
}
|
|
531
539
|
case 'index': {
|
|
532
|
-
const sp = startSpinner('Proje yeniden indexleniyor...');
|
|
540
|
+
const sp = startSpinner(L('Proje yeniden indexleniyor...', 'Re-indexing project...'));
|
|
533
541
|
const newIndex = await indexProject(workDir);
|
|
534
|
-
stopSpinner(sp, `${newIndex.files.length} dosya indexlendi`, true);
|
|
542
|
+
stopSpinner(sp, `${newIndex.files.length} ${L('dosya indexlendi', 'files indexed')}`, true);
|
|
535
543
|
// Sistem prompt'u güncelle
|
|
536
544
|
conversationMessages[0].content = conversationMessages[0].content.replace(
|
|
537
545
|
/Proje Bilgisi:[\s\S]*?(?=\n\n|$)/,
|
|
@@ -549,7 +557,7 @@ ${indexPrompt}`;
|
|
|
549
557
|
? 'npm test'
|
|
550
558
|
: projectIndex.type === 'python' ? 'python -m pytest' : null;
|
|
551
559
|
if (!testCmd) {
|
|
552
|
-
console.log(chalk.red(' Test komutu bulunamadı.\n'));
|
|
560
|
+
console.log(chalk.red(L(' Test komutu bulunamadı.\n', ' Test command not found.\n')));
|
|
553
561
|
return;
|
|
554
562
|
}
|
|
555
563
|
await runAndFix(testCmd);
|
|
@@ -559,13 +567,13 @@ ${indexPrompt}`;
|
|
|
559
567
|
try {
|
|
560
568
|
const status = execSync('git status --short', { cwd: workDir, stdio: 'pipe' }).toString().trim();
|
|
561
569
|
const log = execSync('git log --oneline -5', { cwd: workDir, stdio: 'pipe' }).toString().trim();
|
|
562
|
-
console.log(chalk.yellow('\n Git Durumu:'));
|
|
563
|
-
console.log(status ? chalk.gray(' ' + status.split('\n').join('\n ')) : chalk.gray(' temiz'));
|
|
564
|
-
console.log(chalk.yellow('\n Son Commitler:'));
|
|
570
|
+
console.log(chalk.yellow(L('\n Git Durumu:', '\n Git Status:')));
|
|
571
|
+
console.log(status ? chalk.gray(' ' + status.split('\n').join('\n ')) : chalk.gray(L(' temiz', ' clean')));
|
|
572
|
+
console.log(chalk.yellow(L('\n Son Commitler:', '\n Recent Commits:')));
|
|
565
573
|
console.log(chalk.gray(' ' + log.split('\n').join('\n ')));
|
|
566
574
|
console.log();
|
|
567
575
|
} catch (e) {
|
|
568
|
-
console.log(chalk.red(' Git bulunamadı veya bu dizin bir git repo değil.\n'));
|
|
576
|
+
console.log(chalk.red(L(' Git bulunamadı veya bu dizin bir git repo değil.\n', ' Git not found or this is not a git repo.\n')));
|
|
569
577
|
}
|
|
570
578
|
return;
|
|
571
579
|
}
|
|
@@ -573,28 +581,28 @@ ${indexPrompt}`;
|
|
|
573
581
|
try {
|
|
574
582
|
const diff = execSync('git diff --staged', { cwd: workDir, stdio: 'pipe' }).toString();
|
|
575
583
|
if (!diff.trim()) {
|
|
576
|
-
console.log(chalk.red('\n Staged değişiklik yok.'));
|
|
577
|
-
console.log(chalk.gray(' Önce: git add .\n'));
|
|
584
|
+
console.log(chalk.red(L('\n Staged değişiklik yok.', '\n No staged changes.')));
|
|
585
|
+
console.log(chalk.gray(L(' Önce: git add .\n', ' First: git add .\n')));
|
|
578
586
|
return;
|
|
579
587
|
}
|
|
580
|
-
const sp = startSpinner('Commit mesajı üretiliyor...');
|
|
588
|
+
const sp = startSpinner(L('Commit mesajı üretiliyor...', 'Generating commit message...'));
|
|
581
589
|
const commitMsg = await generateCommitMessage(diff.slice(0, 2000), providerConfig);
|
|
582
|
-
stopSpinner(sp, 'Commit mesajı hazır', true);
|
|
583
|
-
console.log(chalk.cyan(`\n Önerilen: ${chalk.white(commitMsg)}\n`));
|
|
584
|
-
const ok = await confirmAction('Commit edilsin mi?');
|
|
590
|
+
stopSpinner(sp, L('Commit mesajı hazır', 'Commit message ready'), true);
|
|
591
|
+
console.log(chalk.cyan(`\n ${L('Önerilen', 'Suggested')}: ${chalk.white(commitMsg)}\n`));
|
|
592
|
+
const ok = await confirmAction(L('Commit edilsin mi?', 'Commit?'));
|
|
585
593
|
if (ok) {
|
|
586
594
|
execSync(`git commit -m "${commitMsg.replace(/"/g, '\\"')}"`, { cwd: workDir, stdio: 'pipe' });
|
|
587
|
-
console.log(chalk.green(' ✓ Commit yapıldı!\n'));
|
|
595
|
+
console.log(chalk.green(L(' ✓ Commit yapıldı!\n', ' ✓ Committed!\n')));
|
|
588
596
|
} else {
|
|
589
|
-
console.log(chalk.gray(' İptal edildi.\n'));
|
|
597
|
+
console.log(chalk.gray(L(' İptal edildi.\n', ' Cancelled.\n')));
|
|
590
598
|
}
|
|
591
599
|
} catch (e) {
|
|
592
|
-
console.log(chalk.red(` Git
|
|
600
|
+
console.log(chalk.red(` ${L('Git hatası', 'Git error')}: ${e.message}\n`));
|
|
593
601
|
}
|
|
594
602
|
return;
|
|
595
603
|
}
|
|
596
604
|
default:
|
|
597
|
-
console.log(chalk.red(
|
|
605
|
+
console.log(chalk.red(`${L('Bilinmeyen komut', 'Unknown command')}: /${cmd}\n`));
|
|
598
606
|
return;
|
|
599
607
|
}
|
|
600
608
|
}
|
|
@@ -638,19 +646,19 @@ ${indexPrompt}`;
|
|
|
638
646
|
|
|
639
647
|
if (!streamResult.toolCalls?.length) {
|
|
640
648
|
if (!streamResult.text) {
|
|
641
|
-
console.log(chalk.yellow('\n ⚠️ Model cevap vermedi, tekrar deneyin.\n'));
|
|
649
|
+
console.log(chalk.yellow(L('\n ⚠️ Model cevap vermedi, tekrar deneyin.\n', '\n ⚠️ Model did not respond, try again.\n')));
|
|
642
650
|
}
|
|
643
651
|
break;
|
|
644
652
|
}
|
|
645
653
|
|
|
646
|
-
console.log(chalk.yellow(`\n🔧 ${streamResult?.toolCalls?.length ?? 0} tool çalıştırılıyor
|
|
654
|
+
console.log(chalk.yellow(`\n🔧 ${streamResult?.toolCalls?.length ?? 0} ${L('tool çalıştırılıyor...', 'running tools...')}\n`));
|
|
647
655
|
|
|
648
656
|
for (let ti = 0; ti < streamResult.toolCalls.length; ti++) {
|
|
649
657
|
const toolCall = streamResult.toolCalls[ti];
|
|
650
658
|
const result = await runToolCall(toolCall, stats, options.dryRun);
|
|
651
659
|
const resultStr = result.success !== false
|
|
652
660
|
? (result.output || JSON.stringify(result))
|
|
653
|
-
:
|
|
661
|
+
: `${L('Hata', 'Error')}: ${result.error}`;
|
|
654
662
|
|
|
655
663
|
const matchedId = assistantMsg.tool_calls?.[ti]?.id || toolCall.id;
|
|
656
664
|
conversationMessages.push({
|
|
@@ -678,7 +686,7 @@ ${indexPrompt}`;
|
|
|
678
686
|
}
|
|
679
687
|
}
|
|
680
688
|
} catch (err) {
|
|
681
|
-
console.log(chalk.red(`\n ❌ Kayıt
|
|
689
|
+
console.log(chalk.red(`\n ❌ ${L('Kayıt hatası', 'Save error')}: ${err.message}\n`));
|
|
682
690
|
}
|
|
683
691
|
}
|
|
684
692
|
|
|
@@ -699,7 +707,7 @@ ${indexPrompt}`;
|
|
|
699
707
|
rl.pause();
|
|
700
708
|
if (conversationMessages.filter(m => m.role === 'user').length > 0) {
|
|
701
709
|
try {
|
|
702
|
-
const save = await confirmAction("Bu session'ı proje hafızasına kaydet?");
|
|
710
|
+
const save = await confirmAction(L("Bu session'ı proje hafızasına kaydet?", 'Save this session to project memory?'));
|
|
703
711
|
if (save) await saveProjectMemory(conversationMessages, providerConfig, workDir);
|
|
704
712
|
} catch {}
|
|
705
713
|
}
|
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/policy.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
3
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
2
4
|
const fs = require('fs');
|
|
3
5
|
const path = require('path');
|
|
4
6
|
const os = require('os');
|
|
@@ -12,35 +14,35 @@ function policy(args) {
|
|
|
12
14
|
if (action === 'list') return listPolicies();
|
|
13
15
|
if (action === 'remove') return removePolicy(params[0]);
|
|
14
16
|
|
|
15
|
-
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
16
|
-
console.log(chalk.gray(' Kullanım: natureco policy [check|set|list|remove]\n'));
|
|
17
|
+
console.log(chalk.red(`\n ❌ ${L('Bilinmeyen komut', 'Unknown command')}: ${action}\n`));
|
|
18
|
+
console.log(chalk.gray(L(' Kullanım: natureco policy [check|set|list|remove]\n', ' Usage: natureco policy [check|set|list|remove]\n')));
|
|
17
19
|
process.exit(1);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
const POLICY_CHECKS = [
|
|
21
23
|
{
|
|
22
24
|
id: 'node-version',
|
|
23
|
-
name: 'Node.js Versiyonu',
|
|
25
|
+
name: L('Node.js Versiyonu', 'Node.js Version'),
|
|
24
26
|
check: () => {
|
|
25
27
|
const v = process.version.slice(1).split('.')[0];
|
|
26
28
|
return parseInt(v) >= 18
|
|
27
29
|
? { status: 'pass', message: `Node.js ${process.version}` }
|
|
28
|
-
: { status: 'fail', message: `Node.js ${process.version} (18+ gerekli)`, fix: 'Node.js güncelleyin' };
|
|
30
|
+
: { status: 'fail', message: `Node.js ${process.version} (18+ ${L('gerekli', 'required')})`, fix: L('Node.js güncelleyin', 'Update Node.js') };
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
33
|
{
|
|
32
34
|
id: 'config-exists',
|
|
33
|
-
name: 'Config Dosyası',
|
|
35
|
+
name: L('Config Dosyası', 'Config File'),
|
|
34
36
|
check: () => {
|
|
35
37
|
const configFile = path.join(os.homedir(), '.natureco', 'config.json');
|
|
36
38
|
if (!fs.existsSync(configFile)) {
|
|
37
|
-
return { status: 'fail', message: 'config.json bulunamadı', fix: 'natureco setup çalıştırın' };
|
|
39
|
+
return { status: 'fail', message: L('config.json bulunamadı', 'config.json not found'), fix: L('natureco setup çalıştırın', 'run natureco setup') };
|
|
38
40
|
}
|
|
39
41
|
try {
|
|
40
42
|
JSON.parse(fs.readFileSync(configFile, 'utf-8'));
|
|
41
|
-
return { status: 'pass', message: 'Config geçerli JSON' };
|
|
43
|
+
return { status: 'pass', message: L('Config geçerli JSON', 'Config valid JSON') };
|
|
42
44
|
} catch {
|
|
43
|
-
return { status: 'fail', message: 'Config bozuk JSON', fix: '~/.natureco/config.json düzeltin' };
|
|
45
|
+
return { status: 'fail', message: L('Config bozuk JSON', 'Config broken JSON'), fix: L('~/.natureco/config.json düzeltin', 'fix ~/.natureco/config.json') };
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
},
|
|
@@ -50,9 +52,9 @@ const POLICY_CHECKS = [
|
|
|
50
52
|
check: () => {
|
|
51
53
|
const config = getConfig();
|
|
52
54
|
if (config.providerApiKey || config.apiKey || process.env.GROQ_API_KEY) {
|
|
53
|
-
return { status: 'pass', message: 'API key mevcut' };
|
|
55
|
+
return { status: 'pass', message: L('API key mevcut', 'API key present') };
|
|
54
56
|
}
|
|
55
|
-
return { status: 'warn', message: 'API key eksik', fix: 'natureco login veya GROQ_API_KEY env' };
|
|
57
|
+
return { status: 'warn', message: L('API key eksik', 'API key missing'), fix: L('natureco login veya GROQ_API_KEY env', 'natureco login or GROQ_API_KEY env') };
|
|
56
58
|
}
|
|
57
59
|
},
|
|
58
60
|
{
|
|
@@ -63,46 +65,46 @@ const POLICY_CHECKS = [
|
|
|
63
65
|
if (config.providerUrl) {
|
|
64
66
|
return { status: 'pass', message: config.providerUrl };
|
|
65
67
|
}
|
|
66
|
-
return { status: 'warn', message: 'Provider ayarlanmamış', fix: 'natureco setup' };
|
|
68
|
+
return { status: 'warn', message: L('Provider ayarlanmamış', 'Provider not set'), fix: 'natureco setup' };
|
|
67
69
|
}
|
|
68
70
|
},
|
|
69
71
|
{
|
|
70
72
|
id: 'git-config',
|
|
71
|
-
name: 'Git Yapılandırması',
|
|
73
|
+
name: L('Git Yapılandırması', 'Git Configuration'),
|
|
72
74
|
check: () => {
|
|
73
75
|
try {
|
|
74
76
|
const { execSync } = require('child_process');
|
|
75
77
|
const name = execSync('git config user.name', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
76
78
|
const email = execSync('git config user.email', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
77
79
|
if (name && email) return { status: 'pass', message: `${name} <${email}>` };
|
|
78
|
-
return { status: 'warn', message: 'Git user.name/email eksik', fix: 'git config --global user.name "Adınız"' };
|
|
80
|
+
return { status: 'warn', message: L('Git user.name/email eksik', 'Git user.name/email missing'), fix: L('git config --global user.name "Adınız"', 'git config --global user.name "Your Name"') };
|
|
79
81
|
} catch {
|
|
80
|
-
return { status: 'warn', message: 'Git repo değil', fix: 'git init' };
|
|
82
|
+
return { status: 'warn', message: L('Git repo değil', 'Not a git repo'), fix: 'git init' };
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
},
|
|
84
86
|
{
|
|
85
87
|
id: 'disk-space',
|
|
86
|
-
name: 'Disk Alanı',
|
|
88
|
+
name: L('Disk Alanı', 'Disk Space'),
|
|
87
89
|
check: () => {
|
|
88
90
|
try {
|
|
89
91
|
const drive = path.parse(os.homedir()).root.replace(':', '');
|
|
90
92
|
const { execSync } = require('child_process');
|
|
91
93
|
const output = execSync(`powershell -Command "Get-PSDrive -Name ${drive} | Select-Object -ExpandProperty Free"`, { encoding: 'utf-8' }).trim();
|
|
92
94
|
const free = parseInt(output);
|
|
93
|
-
if (isNaN(free)) return { status: 'pass', message: 'Kontrol edilemedi' };
|
|
95
|
+
if (isNaN(free)) return { status: 'pass', message: L('Kontrol edilemedi', 'Could not check') };
|
|
94
96
|
const freeGB = free / 1e9;
|
|
95
|
-
if (freeGB < 0.5) return { status: 'fail', message:
|
|
96
|
-
return { status: 'pass', message: `${freeGB.toFixed(1)}GB boş alan` };
|
|
97
|
+
if (freeGB < 0.5) return { status: 'fail', message: `${L('Sadece', 'Only')} ${freeGB.toFixed(1)}GB ${L('boş', 'free')}`, fix: L('Disk temizliği yapın', 'Free up disk space') };
|
|
98
|
+
return { status: 'pass', message: `${freeGB.toFixed(1)}GB ${L('boş alan', 'free')}` };
|
|
97
99
|
} catch {
|
|
98
|
-
return { status: 'pass', message: 'Kontrol edilemedi' };
|
|
100
|
+
return { status: 'pass', message: L('Kontrol edilemedi', 'Could not check') };
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
];
|
|
103
105
|
|
|
104
106
|
function checkPolicy() {
|
|
105
|
-
console.log(chalk.cyan.bold('\n Workspace Uyumluluk Politikası\n'));
|
|
107
|
+
console.log(chalk.cyan.bold(L('\n Workspace Uyumluluk Politikası\n', '\n Workspace Compliance Policy\n')));
|
|
106
108
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
107
109
|
|
|
108
110
|
let passed = 0;
|
|
@@ -116,29 +118,29 @@ function checkPolicy() {
|
|
|
116
118
|
passed++;
|
|
117
119
|
} else if (result.status === 'fail') {
|
|
118
120
|
console.log(` ${chalk.red('✗')} ${check.name}: ${chalk.white(result.message)}`);
|
|
119
|
-
console.log(chalk.gray(` Düzeltme: ${result.fix}`));
|
|
121
|
+
console.log(chalk.gray(` ${L('Düzeltme', 'Fix')}: ${result.fix}`));
|
|
120
122
|
failed++;
|
|
121
123
|
} else {
|
|
122
124
|
console.log(` ${chalk.yellow('⚠')} ${check.name}: ${chalk.white(result.message)}`);
|
|
123
|
-
if (result.fix) console.log(chalk.gray(` Öneri: ${result.fix}`));
|
|
125
|
+
if (result.fix) console.log(chalk.gray(` ${L('Öneri', 'Tip')}: ${result.fix}`));
|
|
124
126
|
warnings++;
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
129
|
-
console.log(chalk.gray(` Geçti: ${passed} |
|
|
131
|
+
console.log(chalk.gray(` ${L('Geçti', 'Passed')}: ${passed} | ${L('Uyarı', 'Warnings')}: ${warnings} | ${L('Hata', 'Errors')}: ${failed}\n`));
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
function setPolicy(key, value) {
|
|
133
135
|
if (!key) {
|
|
134
|
-
console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
|
|
136
|
+
console.log(chalk.red(L('\n ❌ Politika adı gerekli\n', '\n ❌ Policy name required\n')));
|
|
135
137
|
return;
|
|
136
138
|
}
|
|
137
139
|
const config = getConfig();
|
|
138
140
|
if (!config.policies) config.policies = {};
|
|
139
141
|
config.policies[key] = value;
|
|
140
142
|
saveConfig(config);
|
|
141
|
-
console.log(chalk.green(`\n ✓ Politika
|
|
143
|
+
console.log(chalk.green(`\n ✓ ${L('Politika ayarlandı', 'Policy set')}: ${key} = ${value}\n`));
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
function listPolicies() {
|
|
@@ -146,11 +148,11 @@ function listPolicies() {
|
|
|
146
148
|
const policies = config.policies || {};
|
|
147
149
|
|
|
148
150
|
if (Object.keys(policies).length === 0) {
|
|
149
|
-
console.log(chalk.gray('\n Tanımlı politika yok.\n'));
|
|
151
|
+
console.log(chalk.gray(L('\n Tanımlı politika yok.\n', '\n No policies defined.\n')));
|
|
150
152
|
return;
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
console.log(chalk.cyan.bold('\n Tanımlı Politikalar\n'));
|
|
155
|
+
console.log(chalk.cyan.bold(L('\n Tanımlı Politikalar\n', '\n Defined Policies\n')));
|
|
154
156
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
155
157
|
for (const [key, value] of Object.entries(policies)) {
|
|
156
158
|
console.log(` ${chalk.white(key)}: ${chalk.cyan(value)}`);
|
|
@@ -160,16 +162,16 @@ function listPolicies() {
|
|
|
160
162
|
|
|
161
163
|
function removePolicy(key) {
|
|
162
164
|
if (!key) {
|
|
163
|
-
console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
|
|
165
|
+
console.log(chalk.red(L('\n ❌ Politika adı gerekli\n', '\n ❌ Policy name required\n')));
|
|
164
166
|
return;
|
|
165
167
|
}
|
|
166
168
|
const config = getConfig();
|
|
167
169
|
if (config.policies?.[key]) {
|
|
168
170
|
delete config.policies[key];
|
|
169
171
|
saveConfig(config);
|
|
170
|
-
console.log(chalk.green(`\n ✓ Politika silindi: ${key}\n`));
|
|
172
|
+
console.log(chalk.green(`\n ✓ ${L('Politika silindi', 'Policy deleted')}: ${key}\n`));
|
|
171
173
|
} else {
|
|
172
|
-
console.log(chalk.yellow(`\n ⚠ Politika
|
|
174
|
+
console.log(chalk.yellow(`\n ⚠ ${L('Politika bulunamadı', 'Policy not found')}: ${key}\n`));
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
|
package/src/commands/security.js
CHANGED
|
@@ -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 fs = require('fs');
|
|
3
5
|
const path = require('path');
|
|
4
6
|
const os = require('os');
|
|
@@ -17,8 +19,8 @@ async function security(args) {
|
|
|
17
19
|
|
|
18
20
|
if (action === 'secrets') return scanSecrets(args);
|
|
19
21
|
|
|
20
|
-
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
21
|
-
console.log(chalk.gray(' Kullanım: natureco security [audit|allowlist|policy|secrets]\n'));
|
|
22
|
+
console.log(chalk.red(`\n ❌ ${L('Bilinmeyen komut', 'Unknown command')}: ${action}\n`));
|
|
23
|
+
console.log(chalk.gray(L(' Kullanım: natureco security [audit|allowlist|policy|secrets]\n', ' Usage: natureco security [audit|allowlist|policy|secrets]\n')));
|
|
22
24
|
process.exit(1);
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -58,7 +60,7 @@ async function allowlistAction(args) {
|
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
console.log(chalk.gray('\n Kullanım:'));
|
|
63
|
+
console.log(chalk.gray(L('\n Kullanım:', '\n Usage:')));
|
|
62
64
|
console.log(chalk.gray(' natureco security allowlist list'));
|
|
63
65
|
console.log(chalk.gray(' natureco security allowlist add "<command>"'));
|
|
64
66
|
console.log(chalk.gray(' natureco security allowlist remove <id>\n'));
|
|
@@ -79,7 +81,7 @@ async function policyAction(args) {
|
|
|
79
81
|
return;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
console.log(chalk.gray('\n Kullanım:'));
|
|
84
|
+
console.log(chalk.gray(L('\n Kullanım:', '\n Usage:')));
|
|
83
85
|
console.log(chalk.gray(' natureco security policy set deny|allowlist|full'));
|
|
84
86
|
console.log(chalk.gray('\n Policy levels:'));
|
|
85
87
|
console.log(chalk.gray(' deny - Block all command execution'));
|
|
@@ -140,11 +142,11 @@ async function audit(args) {
|
|
|
140
142
|
if (process.platform !== 'win32' && mode !== '600' && mode !== '644') {
|
|
141
143
|
issues.push({
|
|
142
144
|
id: 'config-permissions',
|
|
143
|
-
msg:
|
|
145
|
+
msg: `${L('Config dosyası izinleri geniş', 'Config file permissions too broad')}: ${mode} ${L('(önerilen: 600)', '(recommended: 600)')}`,
|
|
144
146
|
fix: () => fs.chmodSync(CONFIG_FILE, 0o600),
|
|
145
147
|
});
|
|
146
148
|
} else {
|
|
147
|
-
ok.push('Config dosyası izinleri');
|
|
149
|
+
ok.push(L('Config dosyası izinleri', 'Config file permissions'));
|
|
148
150
|
}
|
|
149
151
|
} catch {}
|
|
150
152
|
}
|
|
@@ -153,7 +155,7 @@ async function audit(args) {
|
|
|
153
155
|
const config = getConfig();
|
|
154
156
|
if (config.providerApiKey) {
|
|
155
157
|
if (config.providerApiKey.length < 10) {
|
|
156
|
-
issues.push({ id: 'weak-api-key', msg: 'API key çok kısa görünüyor' });
|
|
158
|
+
issues.push({ id: 'weak-api-key', msg: L('API key çok kısa görünüyor', 'API key looks too short') });
|
|
157
159
|
} else {
|
|
158
160
|
ok.push('API key formatı');
|
|
159
161
|
}
|
|
@@ -161,9 +163,9 @@ async function audit(args) {
|
|
|
161
163
|
|
|
162
164
|
// 3. Debug mode
|
|
163
165
|
if (config.debug === true) {
|
|
164
|
-
warnings.push({ id: 'debug-mode', msg: 'Debug modu açık — API key\'ler loglara yazılabilir' });
|
|
166
|
+
warnings.push({ id: 'debug-mode', msg: L('Debug modu açık — API key\'ler loglara yazılabilir', 'Debug mode on — API keys may be written to logs') });
|
|
165
167
|
} else {
|
|
166
|
-
ok.push('Debug modu kapalı');
|
|
168
|
+
ok.push(L('Debug modu kapalı', 'Debug mode off'));
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
// 4. WhatsApp session dosyaları
|
|
@@ -171,9 +173,9 @@ async function audit(args) {
|
|
|
171
173
|
if (fs.existsSync(waDir)) {
|
|
172
174
|
const sessions = fs.readdirSync(waDir);
|
|
173
175
|
if (sessions.length > 3) {
|
|
174
|
-
warnings.push({ id: 'old-wa-sessions', msg: `${sessions.length} WhatsApp session var — eskiler temizlenebilir` });
|
|
176
|
+
warnings.push({ id: 'old-wa-sessions', msg: `${sessions.length} WhatsApp ${L('session var — eskiler temizlenebilir', 'sessions — old ones can be cleaned')}` });
|
|
175
177
|
} else {
|
|
176
|
-
ok.push('WhatsApp session sayısı');
|
|
178
|
+
ok.push(L('WhatsApp session sayısı', 'WhatsApp session count'));
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -183,9 +185,9 @@ async function audit(args) {
|
|
|
183
185
|
const stat = fs.statSync(logFile);
|
|
184
186
|
const sizeMB = stat.size / (1024 * 1024);
|
|
185
187
|
if (sizeMB > 50) {
|
|
186
|
-
warnings.push({ id: 'large-log', msg:
|
|
188
|
+
warnings.push({ id: 'large-log', msg: `${L('Gateway log dosyası büyük', 'Gateway log file large')}: ${sizeMB.toFixed(1)}MB` });
|
|
187
189
|
} else {
|
|
188
|
-
ok.push('Gateway log boyutu');
|
|
190
|
+
ok.push(L('Gateway log boyutu', 'Gateway log size'));
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
193
|
|
|
@@ -194,9 +196,9 @@ async function audit(args) {
|
|
|
194
196
|
if (fs.existsSync(convDir)) {
|
|
195
197
|
const convFiles = fs.readdirSync(convDir).filter(f => f.endsWith('.json'));
|
|
196
198
|
if (convFiles.length > 20) {
|
|
197
|
-
warnings.push({ id: 'old-conversations', msg: `${convFiles.length} konuşma dosyası var — eskiler temizlenebilir` });
|
|
199
|
+
warnings.push({ id: 'old-conversations', msg: `${convFiles.length} ${L('konuşma dosyası var — eskiler temizlenebilir', 'conversation files — old ones can be cleaned')}` });
|
|
198
200
|
} else {
|
|
199
|
-
ok.push('Konuşma dosyası sayısı');
|
|
201
|
+
ok.push(L('Konuşma dosyası sayısı', 'Conversation file count'));
|
|
200
202
|
}
|
|
201
203
|
}
|
|
202
204
|
|
|
@@ -245,7 +247,7 @@ async function audit(args) {
|
|
|
245
247
|
|
|
246
248
|
console.log('');
|
|
247
249
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
248
|
-
console.log(chalk.cyan.bold('\n Güvenlik Denetimi\n'));
|
|
250
|
+
console.log(chalk.cyan.bold(L('\n Güvenlik Denetimi\n', '\n Security Audit\n')));
|
|
249
251
|
|
|
250
252
|
ok.forEach(msg => console.log(chalk.green(' ✓ ') + chalk.gray(msg)));
|
|
251
253
|
|
|
@@ -263,11 +265,11 @@ async function audit(args) {
|
|
|
263
265
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
264
266
|
|
|
265
267
|
if (issues.length === 0 && warnings.length === 0) {
|
|
266
|
-
console.log(chalk.green(' ✓ Güvenlik sorunu bulunamadı\n'));
|
|
268
|
+
console.log(chalk.green(L(' ✓ Güvenlik sorunu bulunamadı\n', ' ✓ No security issues found\n')));
|
|
267
269
|
return;
|
|
268
270
|
}
|
|
269
271
|
|
|
270
|
-
console.log(chalk.gray(` ${ok.length} geçti · ${warnings.length} uyarı · ${issues.length} sorun`));
|
|
272
|
+
console.log(chalk.gray(` ${ok.length} ${L('geçti', 'passed')} · ${warnings.length} ${L('uyarı', 'warnings')} · ${issues.length} ${L('sorun', 'issues')}`));
|
|
271
273
|
|
|
272
274
|
if (fix && issues.length > 0) {
|
|
273
275
|
console.log('');
|
|
@@ -275,14 +277,14 @@ async function audit(args) {
|
|
|
275
277
|
if (i.fix) {
|
|
276
278
|
try {
|
|
277
279
|
i.fix();
|
|
278
|
-
console.log(chalk.green(` ✓ Düzeltildi: ${i.id}`));
|
|
280
|
+
console.log(chalk.green(` ✓ ${L('Düzeltildi', 'Fixed')}: ${i.id}`));
|
|
279
281
|
} catch (e) {
|
|
280
|
-
console.log(chalk.red(` ❌ Düzeltilemedi: ${i.id} — ${e.message}`));
|
|
282
|
+
console.log(chalk.red(` ❌ ${L('Düzeltilemedi', 'Could not fix')}: ${i.id} — ${e.message}`));
|
|
281
283
|
}
|
|
282
284
|
}
|
|
283
285
|
});
|
|
284
286
|
} else if (issues.length > 0) {
|
|
285
|
-
console.log(chalk.gray('\n Otomatik düzeltmek için: ') + chalk.cyan('natureco security audit --fix'));
|
|
287
|
+
console.log(chalk.gray(L('\n Otomatik düzeltmek için: ', '\n To auto-fix: ')) + chalk.cyan('natureco security audit --fix'));
|
|
286
288
|
}
|
|
287
289
|
console.log('');
|
|
288
290
|
}
|