natureco-cli 5.58.0 → 5.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/channels.js +11 -9
- package/src/commands/doctor.js +24 -22
- package/src/commands/init.js +30 -28
- package/src/commands/medium.js +32 -30
- package/src/commands/migrate.js +54 -52
- package/src/commands/naturehub.js +32 -30
- package/src/commands/seo.js +43 -41
- package/src/commands/setup.js +42 -40
- package/src/commands/status.js +10 -8
- package/src/commands/xp.js +42 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.60.0",
|
|
4
4
|
"description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
package/src/commands/channels.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 tui = require('../utils/tui');
|
|
3
5
|
const F = require('../utils/format');
|
|
4
6
|
const { getConfig, saveConfig } = require('../utils/config');
|
|
@@ -297,9 +299,9 @@ function listChannels() {
|
|
|
297
299
|
F.header('Channels');
|
|
298
300
|
|
|
299
301
|
if (channels.length === 0) {
|
|
300
|
-
console.log('\n' + tui.styled(' 📡 Bağlı Kanal Yok', { color: tui.PALETTE.warning, bold: true }));
|
|
302
|
+
console.log('\n' + tui.styled(L(' 📡 Bağlı Kanal Yok', ' 📡 No Connected Channels'), { color: tui.PALETTE.warning, bold: true }));
|
|
301
303
|
console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
|
|
302
|
-
console.log('\n ' + tui.C.muted('Bağlamak için:'));
|
|
304
|
+
console.log('\n ' + tui.C.muted(L('Bağlamak için:', 'To connect:')));
|
|
303
305
|
const connectCmds = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage', 'sms', 'webhooks'];
|
|
304
306
|
for (const c of connectCmds) {
|
|
305
307
|
console.log(' ' + tui.C.brand('natureco ' + c + ' connect'));
|
|
@@ -308,23 +310,23 @@ function listChannels() {
|
|
|
308
310
|
return;
|
|
309
311
|
}
|
|
310
312
|
|
|
311
|
-
console.log('\n' + tui.styled(' 📡 Bağlı Kanallar (' + channels.length + ')', { color: tui.PALETTE.primary, bold: true }));
|
|
313
|
+
console.log('\n' + tui.styled(L(' 📡 Bağlı Kanallar (', ' 📡 Connected Channels (') + channels.length + ')', { color: tui.PALETTE.primary, bold: true }));
|
|
312
314
|
console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
|
|
313
315
|
console.log('\n' + tui.table(channels, [
|
|
314
316
|
{
|
|
315
|
-
key: 'name', label: 'Kanal', minWidth: 14,
|
|
317
|
+
key: 'name', label: L('Kanal', 'Channel'), minWidth: 14,
|
|
316
318
|
render: r => tui.styled(r.type + ' ' + r.name, { color: tui.PALETTE.primary, bold: true })
|
|
317
319
|
},
|
|
318
320
|
{
|
|
319
|
-
key: 'status', label: 'Durum', minWidth: 14,
|
|
321
|
+
key: 'status', label: L('Durum', 'Status'), minWidth: 14,
|
|
320
322
|
render: r => r.status === 'connected'
|
|
321
|
-
? tui.styled(' ✓ Bağlı ', { bg: tui.PALETTE.success, color: '#000', bold: true })
|
|
322
|
-
: tui.styled(' ✗ Kopuk ', { bg: tui.PALETTE.muted, color: '#000', bold: true })
|
|
323
|
+
? tui.styled(L(' ✓ Bağlı ', ' ✓ Linked '), { bg: tui.PALETTE.success, color: '#000', bold: true })
|
|
324
|
+
: tui.styled(L(' ✗ Kopuk ', ' ✗ Down '), { bg: tui.PALETTE.muted, color: '#000', bold: true })
|
|
323
325
|
},
|
|
324
|
-
{ key: 'detail', label: 'Detay', minWidth: 30, render: r => tui.C.muted(r.detail) },
|
|
326
|
+
{ key: 'detail', label: L('Detay', 'Detail'), minWidth: 30, render: r => tui.C.muted(r.detail) },
|
|
325
327
|
], { borderStyle: 'round', zebra: true }));
|
|
326
328
|
|
|
327
|
-
console.log('\n ' + tui.C.muted('Kaldırmak için: ') + tui.C.brand('natureco channels remove <kanal>'));
|
|
329
|
+
console.log('\n ' + tui.C.muted(L('Kaldırmak için: ', 'To remove: ')) + tui.C.brand(L('natureco channels remove <kanal>', 'natureco channels remove <channel>')));
|
|
328
330
|
console.log('');
|
|
329
331
|
}
|
|
330
332
|
|
package/src/commands/doctor.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 F = require('../utils/format');
|
|
3
5
|
const tui = require('../utils/tui');
|
|
4
6
|
const fs = require('fs');
|
|
@@ -98,19 +100,19 @@ function cmdCheck(name) {
|
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
function cmdRun(opts = {}) {
|
|
101
|
-
F.header(opts.fix ? 'System Doctor · Otomatik Düzeltme (--fix)' : 'System Doctor · Tüm Sistem Kontrolleri', { icon: opts.fix ? '🔧' : '🩺' });
|
|
103
|
+
F.header(opts.fix ? L('System Doctor · Otomatik Düzeltme (--fix)', 'System Doctor · Auto-Fix (--fix)') : L('System Doctor · Tüm Sistem Kontrolleri', 'System Doctor · All System Checks'), { icon: opts.fix ? '🔧' : '🩺' });
|
|
102
104
|
|
|
103
105
|
// v5.43.2: --fix modunda önce düzeltilebilir sorunları onar, sonra kontrolleri çalıştır.
|
|
104
106
|
if (opts.fix) {
|
|
105
107
|
const { applied, failed } = applyFixes();
|
|
106
108
|
if (applied.length) {
|
|
107
|
-
console.log('\n' + tui.C.green(' 🔧 Düzeltildi:'));
|
|
109
|
+
console.log('\n' + tui.C.green(L(' 🔧 Düzeltildi:', ' 🔧 Fixed:')));
|
|
108
110
|
applied.forEach(a => console.log(' ' + tui.C.text('• ' + a)));
|
|
109
111
|
} else {
|
|
110
|
-
console.log('\n' + tui.C.muted(' 🔧 Düzeltilecek bir şey yok — sistem zaten düzgün.'));
|
|
112
|
+
console.log('\n' + tui.C.muted(L(' 🔧 Düzeltilecek bir şey yok — sistem zaten düzgün.', ' 🔧 Nothing to fix — system is already fine.')));
|
|
111
113
|
}
|
|
112
114
|
if (failed.length) {
|
|
113
|
-
console.log('\n' + tui.C.amber(' ⚠️ Otomatik düzeltilemedi:'));
|
|
115
|
+
console.log('\n' + tui.C.amber(L(' ⚠️ Otomatik düzeltilemedi:', ' ⚠️ Could not auto-fix:')));
|
|
114
116
|
failed.forEach(f => console.log(' ' + tui.C.muted('• ' + f)));
|
|
115
117
|
}
|
|
116
118
|
console.log('');
|
|
@@ -133,14 +135,14 @@ function cmdRun(opts = {}) {
|
|
|
133
135
|
|
|
134
136
|
// Yeni TUI tablo
|
|
135
137
|
console.log('\n' + tui.table(rows, [
|
|
136
|
-
{ key: 'check', label: 'Kontrol', minWidth: 28 },
|
|
138
|
+
{ key: 'check', label: L('Kontrol', 'Check'), minWidth: 28 },
|
|
137
139
|
{
|
|
138
|
-
key: 'status', label: 'Durum', minWidth: 9,
|
|
140
|
+
key: 'status', label: L('Durum', 'Status'), minWidth: 9,
|
|
139
141
|
render: r => r.status
|
|
140
142
|
? tui.styled(' ✓ PASS ', { bg: tui.PALETTE.success, color: '#000000', bold: true })
|
|
141
143
|
: tui.styled(' ✗ FAIL ', { bg: tui.PALETTE.danger, color: '#000000', bold: true }),
|
|
142
144
|
},
|
|
143
|
-
{ key: 'message', label: 'Mesaj', minWidth: 20 },
|
|
145
|
+
{ key: 'message', label: L('Mesaj', 'Message'), minWidth: 20 },
|
|
144
146
|
], { borderStyle: 'round', zebra: true }));
|
|
145
147
|
|
|
146
148
|
const total = passed + failed;
|
|
@@ -148,17 +150,17 @@ function cmdRun(opts = {}) {
|
|
|
148
150
|
|
|
149
151
|
// Özet kartı
|
|
150
152
|
console.log('\n' + tui.box(60, 5, {
|
|
151
|
-
title: 'Özet',
|
|
153
|
+
title: L('Özet', 'Summary'),
|
|
152
154
|
borderColor: failed > 0 ? tui.PALETTE.warning : tui.PALETTE.success,
|
|
153
155
|
}).split('\n').map((line, i) => {
|
|
154
|
-
if (i === 2) return line.replace(' '.repeat(58), ` ${tui.C.text(`${passed}/${total} kontrol geçti`)} · ${tui.C.muted(duration + 'ms')}`);
|
|
156
|
+
if (i === 2) return line.replace(' '.repeat(58), ` ${tui.C.text(`${passed}/${total} ${L('kontrol geçti', 'checks passed')}`)} · ${tui.C.muted(duration + 'ms')}`);
|
|
155
157
|
return line;
|
|
156
158
|
}).join('\n'));
|
|
157
159
|
|
|
158
160
|
if (failed > 0) {
|
|
159
|
-
console.log('\n' + tui.C.amber(' ⚠️ Bazı kontroller başarısız. Detay için: ') + tui.C.brand('natureco doctor check <name>'));
|
|
161
|
+
console.log('\n' + tui.C.amber(L(' ⚠️ Bazı kontroller başarısız. Detay için: ', ' ⚠️ Some checks failed. For details: ')) + tui.C.brand('natureco doctor check <name>'));
|
|
160
162
|
} else {
|
|
161
|
-
console.log('\n' + tui.C.green(' ✨ Tüm kontroller geçti! Sistem sağlıklı.'));
|
|
163
|
+
console.log('\n' + tui.C.green(L(' ✨ Tüm kontroller geçti! Sistem sağlıklı.', ' ✨ All checks passed! System healthy.')));
|
|
162
164
|
}
|
|
163
165
|
console.log('');
|
|
164
166
|
}
|
|
@@ -209,7 +211,7 @@ function runCheck(name) {
|
|
|
209
211
|
}
|
|
210
212
|
return {
|
|
211
213
|
pass: freeGB > 0.5,
|
|
212
|
-
message: freeGB > 0.5 ? `${freeGB.toFixed(1)} GB free` :
|
|
214
|
+
message: freeGB > 0.5 ? `${freeGB.toFixed(1)} GB free` : `${L('Sadece', 'Only')} ${(freeGB * 1024).toFixed(0)} ${L('MB kaldı — gerekli: 500 MB', 'MB left — need: 500 MB')}`,
|
|
213
215
|
};
|
|
214
216
|
} catch (e) {
|
|
215
217
|
return { pass: true, message: 'Unable to check disk space' };
|
|
@@ -233,9 +235,9 @@ function runCheck(name) {
|
|
|
233
235
|
if (!fs.existsSync(CONFIG_FILE)) return { pass: false, message: 'Config missing — run `natureco setup`' };
|
|
234
236
|
const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
235
237
|
const key = cfg.providerApiKey || cfg.apiKey;
|
|
236
|
-
if (!key) return { pass: false, message: 'API key tanımlı değil' };
|
|
237
|
-
if (key.length < 10) return { pass: false, message: 'API key çok kısa — yanlış kopyalanmış olabilir' };
|
|
238
|
-
return { pass: true, message:
|
|
238
|
+
if (!key) return { pass: false, message: L('API key tanımlı değil', 'API key not set') };
|
|
239
|
+
if (key.length < 10) return { pass: false, message: L('API key çok kısa — yanlış kopyalanmış olabilir', 'API key too short — may be copied wrong') };
|
|
240
|
+
return { pass: true, message: `${L('Key uzunluğu', 'Key length')}: ${key.length} ${L('karakter', 'chars')}` };
|
|
239
241
|
} catch (e) {
|
|
240
242
|
return { pass: false, message: e.message };
|
|
241
243
|
}
|
|
@@ -246,10 +248,10 @@ function runCheck(name) {
|
|
|
246
248
|
if (!fs.existsSync(CONFIG_FILE)) return { pass: false, message: 'Config missing' };
|
|
247
249
|
const cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
248
250
|
const url = cfg.providerUrl;
|
|
249
|
-
if (!url) return { pass: false, message: 'Provider URL tanımlı değil' };
|
|
251
|
+
if (!url) return { pass: false, message: L('Provider URL tanımlı değil', 'Provider URL not set') };
|
|
250
252
|
// URL format geçerli mi?
|
|
251
253
|
const parsed = new URL(url);
|
|
252
|
-
return { pass: true, message:
|
|
254
|
+
return { pass: true, message: `${L('URL geçerli', 'URL valid')}: ${parsed.host}` };
|
|
253
255
|
} catch (e) {
|
|
254
256
|
return { pass: false, message: e.message };
|
|
255
257
|
}
|
|
@@ -261,13 +263,13 @@ function runCheck(name) {
|
|
|
261
263
|
const REQUIRED = ['sources', 'concepts', 'cache', 'skills', 'memory', 'sessions', 'backups', 'hooks', 'audit'];
|
|
262
264
|
const missing = REQUIRED.filter(d => !fs.existsSync(path.join(BASE_DIR, d)));
|
|
263
265
|
if (missing.length === 0) {
|
|
264
|
-
return { pass: true, message: `${REQUIRED.length} dizin hazır` };
|
|
266
|
+
return { pass: true, message: `${REQUIRED.length} ${L('dizin hazır', 'directories ready')}` };
|
|
265
267
|
}
|
|
266
268
|
// Otomatik oluştur
|
|
267
269
|
for (const d of missing) {
|
|
268
270
|
try { fs.mkdirSync(path.join(BASE_DIR, d), { recursive: true }); } catch {}
|
|
269
271
|
}
|
|
270
|
-
return { pass: true, message:
|
|
272
|
+
return { pass: true, message: `${L('Eksik dizinler oluşturuldu', 'Created missing directories')}: ${missing.join(', ')}` };
|
|
271
273
|
} catch (e) {
|
|
272
274
|
return { pass: false, message: e.message };
|
|
273
275
|
}
|
|
@@ -278,7 +280,7 @@ function runCheck(name) {
|
|
|
278
280
|
// Audit log yazma testi
|
|
279
281
|
audit.logSync(audit.ACTIONS.INFO, { source: 'doctor', check: 'auditLog' });
|
|
280
282
|
const files = audit.listLogFiles();
|
|
281
|
-
return { pass: true, message: `${files.length} log dosyası, en son: ${files[0] || 'yok'}` };
|
|
283
|
+
return { pass: true, message: `${files.length} ${L('log dosyası, en son', 'log files, latest')}: ${files[0] || L('yok', 'none')}` };
|
|
282
284
|
} catch (e) {
|
|
283
285
|
return { pass: false, message: e.message };
|
|
284
286
|
}
|
|
@@ -307,12 +309,12 @@ function runCheck(name) {
|
|
|
307
309
|
return false;
|
|
308
310
|
});
|
|
309
311
|
if (realSecrets.length === 0) {
|
|
310
|
-
return { pass: true, message: 'Çalışma dizininde gerçek secret bulunamadı ✓' };
|
|
312
|
+
return { pass: true, message: L('Çalışma dizininde gerçek secret bulunamadı ✓', 'No real secrets found in working directory ✓') };
|
|
311
313
|
}
|
|
312
314
|
const sample = realSecrets.slice(0, 3).map(f => `${f.type}@${path.basename(f.file || '?')}`).join(', ');
|
|
313
315
|
return {
|
|
314
316
|
pass: false,
|
|
315
|
-
message: `${realSecrets.length} gerçek secret: ${sample}${realSecrets.length > 3 ? '...' : ''}`,
|
|
317
|
+
message: `${realSecrets.length} ${L('gerçek secret', 'real secrets')}: ${sample}${realSecrets.length > 3 ? '...' : ''}`,
|
|
316
318
|
};
|
|
317
319
|
} catch (e) {
|
|
318
320
|
return { pass: false, message: e.message };
|
package/src/commands/init.js
CHANGED
|
@@ -1,49 +1,51 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
4
|
-
const chalk = require('chalk');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { getLang: _gl } = require('../utils/i18n');
|
|
6
|
+
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
5
7
|
const { getApiKey } = require('../utils/config');
|
|
6
8
|
const { getBots } = require('../utils/api');
|
|
7
9
|
|
|
8
10
|
async function init() {
|
|
9
|
-
console.log(chalk.green.bold('\n╭─ NatureCo Proje Başlatma ─╮\n'));
|
|
11
|
+
console.log(chalk.green.bold(L('\n╭─ NatureCo Proje Başlatma ─╮\n', '\n╭─ NatureCo Project Init ─╮\n')));
|
|
10
12
|
|
|
11
13
|
const apiKey = getApiKey();
|
|
12
14
|
if (!apiKey) {
|
|
13
|
-
console.log(chalk.red('❌ Giriş yapılmadı. Önce "natureco login" çalıştırın.\n'));
|
|
15
|
+
console.log(chalk.red(L('❌ Giriş yapılmadı. Önce "natureco login" çalıştırın.\n', '❌ Not logged in. Run "natureco login" first.\n')));
|
|
14
16
|
process.exit(1);
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
// Mevcut klasörde .natureco var mı kontrol et
|
|
18
20
|
const projectDir = path.join(process.cwd(), '.natureco');
|
|
19
21
|
if (fs.existsSync(projectDir)) {
|
|
20
|
-
console.log(chalk.yellow('⚠️ Bu klasörde zaten .natureco/ mevcut.\n'));
|
|
22
|
+
console.log(chalk.yellow(L('⚠️ Bu klasörde zaten .natureco/ mevcut.\n', '⚠️ This folder already has .natureco/.\n')));
|
|
21
23
|
const { overwrite } = await inquirer.prompt([
|
|
22
24
|
{
|
|
23
25
|
type: 'confirm',
|
|
24
26
|
name: 'overwrite',
|
|
25
|
-
message: 'Üzerine yazmak ister misiniz?',
|
|
27
|
+
message: L('Üzerine yazmak ister misiniz?', 'Overwrite?'),
|
|
26
28
|
default: false,
|
|
27
29
|
},
|
|
28
30
|
]);
|
|
29
31
|
if (!overwrite) {
|
|
30
|
-
console.log(chalk.gray('İptal edildi.\n'));
|
|
32
|
+
console.log(chalk.gray(L('İptal edildi.\n', 'Cancelled.\n')));
|
|
31
33
|
process.exit(0);
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
// Botları çek
|
|
36
|
-
console.log(chalk.yellow('⏳ Botlar yükleniyor...\n'));
|
|
38
|
+
console.log(chalk.yellow(L('⏳ Botlar yükleniyor...\n', '⏳ Loading bots...\n')));
|
|
37
39
|
let botList;
|
|
38
40
|
try {
|
|
39
41
|
botList = await getBots(apiKey);
|
|
40
42
|
} catch (err) {
|
|
41
|
-
console.log(chalk.red(`❌ Hata: ${err.message}\n`));
|
|
43
|
+
console.log(chalk.red(`❌ ${L('Hata', 'Error')}: ${err.message}\n`));
|
|
42
44
|
process.exit(1);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
if (!botList || !botList.bots || botList.bots.length === 0) {
|
|
46
|
-
console.log(chalk.gray('Bot bulunamadı. Önce https://developers.natureco.me adresinden bot oluşturun.\n'));
|
|
48
|
+
console.log(chalk.gray(L('Bot bulunamadı. Önce https://developers.natureco.me adresinden bot oluşturun.\n', 'No bots found. Create a bot at https://developers.natureco.me first.\n')));
|
|
47
49
|
process.exit(1);
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -52,7 +54,7 @@ async function init() {
|
|
|
52
54
|
{
|
|
53
55
|
type: 'list',
|
|
54
56
|
name: 'defaultBot',
|
|
55
|
-
message: 'Varsayılan bot:',
|
|
57
|
+
message: L('Varsayılan bot:', 'Default bot:'),
|
|
56
58
|
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
57
59
|
},
|
|
58
60
|
]);
|
|
@@ -64,11 +66,11 @@ async function init() {
|
|
|
64
66
|
{
|
|
65
67
|
type: 'checkbox',
|
|
66
68
|
name: 'skills',
|
|
67
|
-
message: 'Hangi skill\'ler eklensin?',
|
|
69
|
+
message: L('Hangi skill\'ler eklensin?', 'Which skills to add?'),
|
|
68
70
|
choices: [
|
|
69
|
-
{ name: 'code-review (Kod inceleme)', value: 'code-review', checked: true },
|
|
70
|
-
{ name: 'summarize (Özetleme)', value: 'summarize', checked: true },
|
|
71
|
-
{ name: 'translate (Çeviri)', value: 'translate', checked: false },
|
|
71
|
+
{ name: L('code-review (Kod inceleme)', 'code-review (Code review)'), value: 'code-review', checked: true },
|
|
72
|
+
{ name: L('summarize (Özetleme)', 'summarize (Summarize)'), value: 'summarize', checked: true },
|
|
73
|
+
{ name: L('translate (Çeviri)', 'translate (Translate)'), value: 'translate', checked: false },
|
|
72
74
|
],
|
|
73
75
|
},
|
|
74
76
|
]);
|
|
@@ -95,24 +97,24 @@ async function init() {
|
|
|
95
97
|
);
|
|
96
98
|
|
|
97
99
|
// AGENTS.md
|
|
98
|
-
const agentsMd = `# ${selectedBot.name} Talimatları
|
|
100
|
+
const agentsMd = `# ${selectedBot.name} ${L('Talimatları', 'Instructions')}
|
|
99
101
|
|
|
100
|
-
Bu dosya projeye özel bot talimatlarını içerir.
|
|
101
|
-
Chat başladığında bu içerik sistem promptuna eklenir.
|
|
102
|
+
${L('Bu dosya projeye özel bot talimatlarını içerir.', 'This file contains project-specific bot instructions.')}
|
|
103
|
+
${L('Chat başladığında bu içerik sistem promptuna eklenir.', 'This content is added to the system prompt when chat starts.')}
|
|
102
104
|
|
|
103
|
-
## Proje Hakkında
|
|
105
|
+
## ${L('Proje Hakkında', 'About the Project')}
|
|
104
106
|
|
|
105
|
-
[Projenizi tanımlayın]
|
|
107
|
+
${L('[Projenizi tanımlayın]', '[Describe your project]')}
|
|
106
108
|
|
|
107
|
-
## Bot Görevleri
|
|
109
|
+
## ${L('Bot Görevleri', 'Bot Tasks')}
|
|
108
110
|
|
|
109
|
-
- [Görev 1]
|
|
110
|
-
- [Görev 2]
|
|
111
|
+
- ${L('[Görev 1]', '[Task 1]')}
|
|
112
|
+
- ${L('[Görev 2]', '[Task 2]')}
|
|
111
113
|
|
|
112
|
-
## Kurallar
|
|
114
|
+
## ${L('Kurallar', 'Rules')}
|
|
113
115
|
|
|
114
|
-
- [Kural 1]
|
|
115
|
-
- [Kural 2]
|
|
116
|
+
- ${L('[Kural 1]', '[Rule 1]')}
|
|
117
|
+
- ${L('[Kural 2]', '[Rule 2]')}
|
|
116
118
|
`;
|
|
117
119
|
fs.writeFileSync(path.join(projectDir, 'AGENTS.md'), agentsMd, 'utf8');
|
|
118
120
|
|
|
@@ -122,13 +124,13 @@ Chat başladığında bu içerik sistem promptuna eklenir.
|
|
|
122
124
|
fs.mkdirSync(skillsDir, { recursive: true });
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
console.log(chalk.green('\n✅ Proje başlatıldı!\n'));
|
|
126
|
-
console.log(chalk.cyan('Oluşturulan dosyalar:'));
|
|
127
|
+
console.log(chalk.green(L('\n✅ Proje başlatıldı!\n', '\n✅ Project initialized!\n')));
|
|
128
|
+
console.log(chalk.cyan(L('Oluşturulan dosyalar:', 'Created files:')));
|
|
127
129
|
console.log(chalk.gray(` .natureco/config.json`));
|
|
128
130
|
console.log(chalk.gray(` .natureco/AGENTS.md`));
|
|
129
131
|
console.log(chalk.gray(` .natureco/skills/`));
|
|
130
132
|
console.log('');
|
|
131
|
-
console.log(chalk.yellow('Sonraki adım:'), chalk.white(`natureco chat "${selectedBot.name}"`));
|
|
133
|
+
console.log(chalk.yellow(L('Sonraki adım:', 'Next step:')), chalk.white(`natureco chat "${selectedBot.name}"`));
|
|
132
134
|
console.log('');
|
|
133
135
|
}
|
|
134
136
|
|
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;
|