natureco-cli 2.17.1 → 2.17.2
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/bin/natureco.js +35 -0
- package/package.json +1 -1
- package/src/commands/agents.js +141 -0
- package/src/commands/dashboard.js +2 -2
- package/src/commands/help.js +4 -0
- package/src/commands/pairing.js +107 -0
- package/src/commands/plugins.js +172 -0
- package/src/commands/uninstall.js +92 -0
- package/src/utils/config.js +25 -9
package/bin/natureco.js
CHANGED
|
@@ -308,6 +308,41 @@ program
|
|
|
308
308
|
securityCmd(process.argv.slice(3));
|
|
309
309
|
});
|
|
310
310
|
|
|
311
|
+
program
|
|
312
|
+
.command('agents [action] [params...]')
|
|
313
|
+
.description('Manage agents/bots (list|set|info|add)')
|
|
314
|
+
.action((action, params) => {
|
|
315
|
+
const agentsCmd = require('../src/commands/agents');
|
|
316
|
+
agentsCmd([action, ...(params || [])]);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
program
|
|
320
|
+
.command('plugins [action] [params...]')
|
|
321
|
+
.description('Manage plugins (list|install|enable|disable|info|doctor)')
|
|
322
|
+
.action((action, params) => {
|
|
323
|
+
const pluginsCmd = require('../src/commands/plugins');
|
|
324
|
+
pluginsCmd([action, ...(params || [])]);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
program
|
|
328
|
+
.command('pairing [action] [params...]')
|
|
329
|
+
.description('Manage device pairings (list|approve|reject)')
|
|
330
|
+
.action((action, params) => {
|
|
331
|
+
const pairingCmd = require('../src/commands/pairing');
|
|
332
|
+
pairingCmd([action, ...(params || [])]);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
program
|
|
336
|
+
.command('uninstall')
|
|
337
|
+
.description('Uninstall NatureCo CLI data')
|
|
338
|
+
.option('--all', 'Remove all data including config')
|
|
339
|
+
.option('--yes, -y', 'Skip confirmation')
|
|
340
|
+
.option('--dry-run', 'Preview actions without executing')
|
|
341
|
+
.action(() => {
|
|
342
|
+
const uninstallCmd = require('../src/commands/uninstall');
|
|
343
|
+
uninstallCmd(process.argv.slice(3));
|
|
344
|
+
});
|
|
345
|
+
|
|
311
346
|
program
|
|
312
347
|
.command('help')
|
|
313
348
|
.description('Show help information')
|
package/package.json
CHANGED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
4
|
+
const { getBots } = require('../utils/api');
|
|
5
|
+
|
|
6
|
+
async function agents(args) {
|
|
7
|
+
const [action, ...params] = (args || []);
|
|
8
|
+
|
|
9
|
+
if (!action || action === 'list') return listAgents();
|
|
10
|
+
if (action === 'set') return setActiveAgent(params[0]);
|
|
11
|
+
if (action === 'info') return agentInfo(params[0]);
|
|
12
|
+
if (action === 'add') return addAgent();
|
|
13
|
+
|
|
14
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
15
|
+
console.log(chalk.gray(' Kullanım: natureco agents [list|set|info|add]\n'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function listAgents() {
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
const apiKey = config.providerApiKey || config.apiKey || '';
|
|
22
|
+
|
|
23
|
+
console.log(chalk.gray('\n Agentlar yükleniyor...\n'));
|
|
24
|
+
|
|
25
|
+
let botList = { bots: [] };
|
|
26
|
+
try {
|
|
27
|
+
botList = await getBots(apiKey);
|
|
28
|
+
} catch {}
|
|
29
|
+
|
|
30
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
31
|
+
console.log(chalk.cyan.bold('\n Agentlar (Botlar)\n'));
|
|
32
|
+
|
|
33
|
+
if (!botList.bots?.length) {
|
|
34
|
+
console.log(chalk.gray(' Agent bulunamadı.'));
|
|
35
|
+
console.log(chalk.gray(' Oluşturmak için: ') + chalk.cyan('developers.natureco.me\n'));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
botList.bots.forEach((bot, i) => {
|
|
40
|
+
const active = config.botName === bot.name ? chalk.green(' ← aktif') : '';
|
|
41
|
+
console.log(chalk.white(` ${i + 1}. ${bot.name}`) + active);
|
|
42
|
+
console.log(chalk.gray(` ID : ${bot.id}`));
|
|
43
|
+
console.log(chalk.gray(` Provider: ${bot.ai_provider || 'groq'}`));
|
|
44
|
+
if (bot.model) console.log(chalk.gray(` Model : ${bot.model}`));
|
|
45
|
+
console.log('');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
49
|
+
console.log(chalk.gray(' Değiştirmek için: ') + chalk.cyan('natureco agents set <bot-adı>\n'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function setActiveAgent(botName) {
|
|
53
|
+
const config = getConfig();
|
|
54
|
+
const apiKey = config.providerApiKey || config.apiKey || '';
|
|
55
|
+
|
|
56
|
+
let botList = { bots: [] };
|
|
57
|
+
try {
|
|
58
|
+
botList = await getBots(apiKey);
|
|
59
|
+
} catch {}
|
|
60
|
+
|
|
61
|
+
if (!botName) {
|
|
62
|
+
if (!botList.bots?.length) {
|
|
63
|
+
console.log(chalk.gray('\n Agent bulunamadı.\n'));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const { selected } = await inquirer.prompt([{
|
|
67
|
+
type: 'list',
|
|
68
|
+
name: 'selected',
|
|
69
|
+
message: ' Aktif agent seç:',
|
|
70
|
+
choices: botList.bots.map(b => ({ name: b.name, value: b.name })),
|
|
71
|
+
}]);
|
|
72
|
+
botName = selected;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const bot = botList.bots?.find(b => b.name === botName || b.id === botName);
|
|
76
|
+
if (!bot && botList.bots?.length) {
|
|
77
|
+
console.log(chalk.red(`\n ❌ Agent bulunamadı: ${botName}\n`));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
config.botName = botName;
|
|
82
|
+
if (bot?.id) config.defaultBotId = bot.id;
|
|
83
|
+
saveConfig(config);
|
|
84
|
+
|
|
85
|
+
console.log(chalk.green(`\n ✓ Aktif agent: ${botName}\n`));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function agentInfo(botName) {
|
|
89
|
+
const config = getConfig();
|
|
90
|
+
const apiKey = config.providerApiKey || config.apiKey || '';
|
|
91
|
+
const name = botName || config.botName;
|
|
92
|
+
|
|
93
|
+
if (!name) {
|
|
94
|
+
console.log(chalk.gray('\n Agent adı belirtin: natureco agents info <bot-adı>\n'));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let botList = { bots: [] };
|
|
99
|
+
try {
|
|
100
|
+
botList = await getBots(apiKey);
|
|
101
|
+
} catch {}
|
|
102
|
+
|
|
103
|
+
const bot = botList.bots?.find(b => b.name === name || b.id === name);
|
|
104
|
+
|
|
105
|
+
console.log('');
|
|
106
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
107
|
+
console.log(chalk.cyan.bold(`\n Agent: ${name}\n`));
|
|
108
|
+
|
|
109
|
+
if (bot) {
|
|
110
|
+
console.log(chalk.gray(' ID : ') + chalk.white(bot.id));
|
|
111
|
+
console.log(chalk.gray(' Provider: ') + chalk.white(bot.ai_provider || 'groq'));
|
|
112
|
+
if (bot.model) console.log(chalk.gray(' Model : ') + chalk.white(bot.model));
|
|
113
|
+
if (bot.system_prompt) {
|
|
114
|
+
console.log(chalk.gray(' Prompt : ') + chalk.white(bot.system_prompt.slice(0, 80) + (bot.system_prompt.length > 80 ? '...' : '')));
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
console.log(chalk.gray(' (Detay alınamadı)'));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Hafıza bilgisi
|
|
121
|
+
try {
|
|
122
|
+
const { loadMemory } = require('../utils/memory');
|
|
123
|
+
const mem = loadMemory(bot?.id || 'universal-provider');
|
|
124
|
+
if (mem.name || mem.facts?.length) {
|
|
125
|
+
console.log('');
|
|
126
|
+
if (mem.name) console.log(chalk.gray(' Kullanıcı: ') + chalk.white(mem.name));
|
|
127
|
+
console.log(chalk.gray(' Hafıza : ') + chalk.white(`${(mem.facts || []).length} bilgi`));
|
|
128
|
+
}
|
|
129
|
+
} catch {}
|
|
130
|
+
|
|
131
|
+
console.log('');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function addAgent() {
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(chalk.gray(' Yeni agent oluşturmak için Developers Portal\'ı kullanın:'));
|
|
137
|
+
console.log(chalk.cyan(' developers.natureco.me\n'));
|
|
138
|
+
console.log(chalk.gray(' Oluşturduktan sonra: ') + chalk.cyan('natureco agents list\n'));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = agents;
|
|
@@ -211,7 +211,7 @@ body::before{
|
|
|
211
211
|
<div class="header-bot-name" id="header-bot-name">Nature Bot</div>
|
|
212
212
|
<div class="header-bot-model" id="header-bot-model">NatureCo</div>
|
|
213
213
|
</div>
|
|
214
|
-
<div class="version-badge" id="version-badge">v2.17.
|
|
214
|
+
<div class="version-badge" id="version-badge">v2.17.2</div>
|
|
215
215
|
</div>
|
|
216
216
|
<div class="messages" id="messages"></div>
|
|
217
217
|
<div class="input-area">
|
|
@@ -341,7 +341,7 @@ function dashboard(action) {
|
|
|
341
341
|
apiKey: cfg.apiKey,
|
|
342
342
|
defaultBot: cfg.defaultBot,
|
|
343
343
|
defaultBotId: cfg.defaultBotId,
|
|
344
|
-
version: 'v2.17.
|
|
344
|
+
version: 'v2.17.2',
|
|
345
345
|
bots: cfg.bots || [],
|
|
346
346
|
telegramToken: cfg.telegramToken || null,
|
|
347
347
|
whatsappConnected: cfg.whatsappConnected || false,
|
package/src/commands/help.js
CHANGED
|
@@ -75,10 +75,14 @@ function help() {
|
|
|
75
75
|
printCmd('natureco channels [action]', 'Kanal yönetimi (list|status|remove|logs)');
|
|
76
76
|
printCmd('natureco models [action]', 'Model yönetimi (list|set|scan|aliases)');
|
|
77
77
|
printCmd('natureco memory [action]', 'Hafıza yönetimi (status|list|search|show|clear)');
|
|
78
|
+
printCmd('natureco agents [action]', 'Agent yönetimi (list|set|info)');
|
|
79
|
+
printCmd('natureco plugins [action]', 'Plugin yönetimi (list|install|enable|disable)');
|
|
80
|
+
printCmd('natureco pairing [action]', 'Cihaz eşleştirme (list|approve|reject)');
|
|
78
81
|
printCmd('natureco logs', 'Gateway loglarını göster (--follow ile canlı)');
|
|
79
82
|
printCmd('natureco status', 'Genel sistem durumu');
|
|
80
83
|
printCmd('natureco security audit', 'Güvenlik denetimi (--fix ile otomatik düzelt)');
|
|
81
84
|
printCmd('natureco reset', 'Config sıfırla (--scope config|memory|sessions|full)');
|
|
85
|
+
printCmd('natureco uninstall', 'CLI verilerini kaldır (--all ile tam temizlik)');
|
|
82
86
|
printCmd('natureco sessions list', 'Geçmiş oturumları listele');
|
|
83
87
|
printCmd('natureco tasks list', 'Arka plan görevlerini listele');
|
|
84
88
|
printCmd('natureco config list', 'Tüm ayarları göster');
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
|
+
|
|
4
|
+
async function pairing(args) {
|
|
5
|
+
const [action, ...params] = (args || []);
|
|
6
|
+
|
|
7
|
+
if (!action || action === 'list') return listPairing();
|
|
8
|
+
if (action === 'approve') return approvePairing(params[0], params[1]);
|
|
9
|
+
if (action === 'reject') return rejectPairing(params[0]);
|
|
10
|
+
|
|
11
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
12
|
+
console.log(chalk.gray(' Kullanım: natureco pairing [list|approve|reject]\n'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function listPairing() {
|
|
17
|
+
const config = getConfig();
|
|
18
|
+
const pending = config.pendingPairings || [];
|
|
19
|
+
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
22
|
+
console.log(chalk.cyan.bold('\n Bekleyen Eşleştirmeler\n'));
|
|
23
|
+
|
|
24
|
+
if (pending.length === 0) {
|
|
25
|
+
console.log(chalk.gray(' Bekleyen eşleştirme yok.\n'));
|
|
26
|
+
console.log(chalk.gray(' Telegram bağlamak için: ') + chalk.cyan('natureco telegram connect'));
|
|
27
|
+
console.log(chalk.gray(' WhatsApp bağlamak için: ') + chalk.cyan('natureco whatsapp connect\n'));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pending.forEach((p, i) => {
|
|
32
|
+
console.log(chalk.white(` ${i + 1}. ${p.channel} — ${p.id}`));
|
|
33
|
+
console.log(chalk.gray(` Kod: ${p.code} · ${new Date(p.createdAt).toLocaleString('tr-TR')}`));
|
|
34
|
+
console.log('');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
console.log(chalk.gray(' Onaylamak için: ') + chalk.cyan('natureco pairing approve <kanal> <kod>'));
|
|
38
|
+
console.log(chalk.gray(' Reddetmek için: ') + chalk.cyan('natureco pairing reject <kod>\n'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function approvePairing(channel, code) {
|
|
42
|
+
if (!channel || !code) {
|
|
43
|
+
console.log(chalk.red('\n ❌ Kanal ve kod gerekli\n'));
|
|
44
|
+
console.log(chalk.gray(' Kullanım: natureco pairing approve <telegram|whatsapp> <KOD>\n'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
const pending = config.pendingPairings || [];
|
|
50
|
+
const idx = pending.findIndex(p => p.code === code && p.channel === channel);
|
|
51
|
+
|
|
52
|
+
if (idx === -1) {
|
|
53
|
+
console.log(chalk.yellow(`\n ⚠ Eşleştirme bulunamadı: ${channel} ${code}\n`));
|
|
54
|
+
console.log(chalk.gray(' Bekleyen listesi: ') + chalk.cyan('natureco pairing list\n'));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const pairing = pending[idx];
|
|
59
|
+
pending.splice(idx, 1);
|
|
60
|
+
|
|
61
|
+
// Onaylanan kanalı izin listesine ekle
|
|
62
|
+
if (channel === 'telegram') {
|
|
63
|
+
const allowed = config.telegramAllowedChats || [];
|
|
64
|
+
if (!allowed.includes(pairing.id)) {
|
|
65
|
+
allowed.push(pairing.id);
|
|
66
|
+
config.telegramAllowedChats = allowed;
|
|
67
|
+
}
|
|
68
|
+
} else if (channel === 'whatsapp') {
|
|
69
|
+
const allowed = config.whatsappAllowedNumbers || [];
|
|
70
|
+
const num = pairing.id.replace(/\D/g, '');
|
|
71
|
+
if (!allowed.includes(num)) {
|
|
72
|
+
allowed.push(num);
|
|
73
|
+
config.whatsappAllowedNumbers = allowed;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
config.pendingPairings = pending;
|
|
78
|
+
saveConfig(config);
|
|
79
|
+
|
|
80
|
+
console.log(chalk.green(`\n ✓ Eşleştirme onaylandı: ${channel} — ${pairing.id}\n`));
|
|
81
|
+
console.log(chalk.gray(' Gateway\'i yeniden başlatın: ') + chalk.cyan('natureco gateway stop && natureco gateway start\n'));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function rejectPairing(code) {
|
|
85
|
+
if (!code) {
|
|
86
|
+
console.log(chalk.red('\n ❌ Kod gerekli\n'));
|
|
87
|
+
console.log(chalk.gray(' Kullanım: natureco pairing reject <KOD>\n'));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const config = getConfig();
|
|
92
|
+
const pending = config.pendingPairings || [];
|
|
93
|
+
const idx = pending.findIndex(p => p.code === code);
|
|
94
|
+
|
|
95
|
+
if (idx === -1) {
|
|
96
|
+
console.log(chalk.yellow(`\n ⚠ Eşleştirme bulunamadı: ${code}\n`));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
pending.splice(idx, 1);
|
|
101
|
+
config.pendingPairings = pending;
|
|
102
|
+
saveConfig(config);
|
|
103
|
+
|
|
104
|
+
console.log(chalk.gray(`\n ○ Eşleştirme reddedildi: ${code}\n`));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = pairing;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
const PLUGINS_DIR = path.join(os.homedir(), '.natureco', 'plugins');
|
|
7
|
+
|
|
8
|
+
function ensurePluginsDir() {
|
|
9
|
+
if (!fs.existsSync(PLUGINS_DIR)) fs.mkdirSync(PLUGINS_DIR, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function loadPlugins() {
|
|
13
|
+
ensurePluginsDir();
|
|
14
|
+
if (!fs.existsSync(PLUGINS_DIR)) return [];
|
|
15
|
+
return fs.readdirSync(PLUGINS_DIR, { withFileTypes: true })
|
|
16
|
+
.filter(d => d.isDirectory())
|
|
17
|
+
.map(d => {
|
|
18
|
+
const metaFile = path.join(PLUGINS_DIR, d.name, 'plugin.json');
|
|
19
|
+
let meta = { name: d.name, description: '', version: '1.0.0', enabled: true };
|
|
20
|
+
if (fs.existsSync(metaFile)) {
|
|
21
|
+
try { meta = { ...meta, ...JSON.parse(fs.readFileSync(metaFile, 'utf-8')) }; } catch {}
|
|
22
|
+
}
|
|
23
|
+
// enabled durumu
|
|
24
|
+
const disabledFile = path.join(PLUGINS_DIR, d.name, '.disabled');
|
|
25
|
+
meta.enabled = !fs.existsSync(disabledFile);
|
|
26
|
+
return { ...meta, slug: d.name, path: path.join(PLUGINS_DIR, d.name) };
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function plugins(args) {
|
|
31
|
+
const [action, ...params] = (args || []);
|
|
32
|
+
|
|
33
|
+
if (!action || action === 'list') return listPlugins();
|
|
34
|
+
if (action === 'install') return installPlugin(params[0]);
|
|
35
|
+
if (action === 'enable') return togglePlugin(params[0], true);
|
|
36
|
+
if (action === 'disable') return togglePlugin(params[0], false);
|
|
37
|
+
if (action === 'info') return pluginInfo(params[0]);
|
|
38
|
+
if (action === 'doctor') return pluginDoctor();
|
|
39
|
+
|
|
40
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
41
|
+
console.log(chalk.gray(' Kullanım: natureco plugins [list|install|enable|disable|info|doctor]\n'));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listPlugins() {
|
|
46
|
+
const list = loadPlugins();
|
|
47
|
+
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
50
|
+
console.log(chalk.cyan.bold('\n Plugins\n'));
|
|
51
|
+
|
|
52
|
+
if (list.length === 0) {
|
|
53
|
+
console.log(chalk.gray(' Yüklü plugin yok.\n'));
|
|
54
|
+
console.log(chalk.gray(' Yüklemek için: ') + chalk.cyan('natureco plugins install <npm-paketi>\n'));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
list.forEach(p => {
|
|
59
|
+
const status = p.enabled ? chalk.green('✓ aktif') : chalk.gray('○ pasif');
|
|
60
|
+
console.log(chalk.white(` ${p.name}`) + chalk.gray(` v${p.version} `) + status);
|
|
61
|
+
if (p.description) console.log(chalk.gray(` ${p.description}`));
|
|
62
|
+
console.log('');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
66
|
+
console.log(chalk.gray(` Toplam: ${list.length} plugin`));
|
|
67
|
+
console.log(chalk.gray(' Devre dışı: ') + chalk.cyan('natureco plugins disable <slug>\n'));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function installPlugin(pkg) {
|
|
71
|
+
if (!pkg) {
|
|
72
|
+
console.log(chalk.red('\n ❌ Paket adı gerekli\n'));
|
|
73
|
+
console.log(chalk.gray(' Kullanım: natureco plugins install <npm-paketi|./yerel-yol>\n'));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ensurePluginsDir();
|
|
78
|
+
console.log(chalk.gray(`\n "${pkg}" yükleniyor...\n`));
|
|
79
|
+
|
|
80
|
+
// Yerel path
|
|
81
|
+
if (pkg.startsWith('./') || pkg.startsWith('/')) {
|
|
82
|
+
const src = path.resolve(pkg);
|
|
83
|
+
if (!fs.existsSync(src)) {
|
|
84
|
+
console.log(chalk.red(`\n ❌ Yol bulunamadı: ${src}\n`));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const slug = path.basename(src);
|
|
88
|
+
const dest = path.join(PLUGINS_DIR, slug);
|
|
89
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
90
|
+
console.log(chalk.green(`\n ✓ Plugin yüklendi: ${slug}\n`));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// npm paketi — basit indirme
|
|
95
|
+
try {
|
|
96
|
+
const { execSync } = require('child_process');
|
|
97
|
+
const tmpDir = path.join(os.tmpdir(), `nc-plugin-${Date.now()}`);
|
|
98
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
99
|
+
execSync(`npm install ${pkg} --prefix ${tmpDir} --no-save`, { stdio: 'pipe' });
|
|
100
|
+
const pkgDir = path.join(tmpDir, 'node_modules', pkg.split('/').pop());
|
|
101
|
+
if (fs.existsSync(pkgDir)) {
|
|
102
|
+
const slug = pkg.replace(/[@\/]/g, '-').replace(/^-/, '');
|
|
103
|
+
const dest = path.join(PLUGINS_DIR, slug);
|
|
104
|
+
fs.cpSync(pkgDir, dest, { recursive: true });
|
|
105
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
106
|
+
console.log(chalk.green(`\n ✓ Plugin yüklendi: ${slug}\n`));
|
|
107
|
+
} else {
|
|
108
|
+
console.log(chalk.yellow('\n ⚠ Paket yüklendi ama plugin dizini bulunamadı.\n'));
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.log(chalk.red(`\n ❌ Yükleme başarısız: ${e.message}\n`));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function togglePlugin(slug, enable) {
|
|
117
|
+
if (!slug) {
|
|
118
|
+
console.log(chalk.red(`\n ❌ Plugin adı gerekli\n`));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
const pluginDir = path.join(PLUGINS_DIR, slug);
|
|
122
|
+
if (!fs.existsSync(pluginDir)) {
|
|
123
|
+
console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
const disabledFile = path.join(pluginDir, '.disabled');
|
|
127
|
+
if (enable) {
|
|
128
|
+
if (fs.existsSync(disabledFile)) fs.unlinkSync(disabledFile);
|
|
129
|
+
console.log(chalk.green(`\n ✓ Plugin aktif: ${slug}\n`));
|
|
130
|
+
} else {
|
|
131
|
+
fs.writeFileSync(disabledFile, '');
|
|
132
|
+
console.log(chalk.gray(`\n ○ Plugin pasif: ${slug}\n`));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function pluginInfo(slug) {
|
|
137
|
+
if (!slug) {
|
|
138
|
+
console.log(chalk.red('\n ❌ Plugin adı gerekli\n'));
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
const list = loadPlugins();
|
|
142
|
+
const p = list.find(x => x.slug === slug);
|
|
143
|
+
if (!p) {
|
|
144
|
+
console.log(chalk.red(`\n ❌ Plugin bulunamadı: ${slug}\n`));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
console.log('');
|
|
148
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
149
|
+
console.log(chalk.cyan.bold(`\n Plugin: ${p.name}\n`));
|
|
150
|
+
console.log(chalk.gray(' Versiyon: ') + chalk.white(p.version));
|
|
151
|
+
console.log(chalk.gray(' Durum : ') + (p.enabled ? chalk.green('aktif') : chalk.gray('pasif')));
|
|
152
|
+
if (p.description) console.log(chalk.gray(' Açıklama: ') + chalk.white(p.description));
|
|
153
|
+
console.log(chalk.gray(' Yol : ') + chalk.gray(p.path));
|
|
154
|
+
console.log('');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function pluginDoctor() {
|
|
158
|
+
const list = loadPlugins();
|
|
159
|
+
console.log(chalk.cyan.bold('\n Plugin Tanılama\n'));
|
|
160
|
+
if (list.length === 0) {
|
|
161
|
+
console.log(chalk.gray(' Yüklü plugin yok.\n'));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
list.forEach(p => {
|
|
165
|
+
const hasIndex = fs.existsSync(path.join(p.path, 'index.js'));
|
|
166
|
+
const icon = hasIndex ? chalk.green('✓') : chalk.yellow('⚠');
|
|
167
|
+
console.log(` ${icon} ${p.name} ${hasIndex ? '' : chalk.yellow('(index.js bulunamadı)')}`);
|
|
168
|
+
});
|
|
169
|
+
console.log('');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = plugins;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const { CONFIG_DIR } = require('../utils/config');
|
|
7
|
+
|
|
8
|
+
async function uninstall(args) {
|
|
9
|
+
const all = args?.includes('--all');
|
|
10
|
+
const yes = args?.includes('--yes') || args?.includes('-y');
|
|
11
|
+
const dryRun = args?.includes('--dry-run');
|
|
12
|
+
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
15
|
+
console.log(chalk.red.bold('\n NatureCo CLI — Kaldırma\n'));
|
|
16
|
+
|
|
17
|
+
const actions = [];
|
|
18
|
+
|
|
19
|
+
// Gateway service PID
|
|
20
|
+
const pidFile = path.join(CONFIG_DIR, 'gateway.pid');
|
|
21
|
+
if (fs.existsSync(pidFile)) actions.push('Gateway durdurulacak');
|
|
22
|
+
|
|
23
|
+
// Config ve data
|
|
24
|
+
if (all) {
|
|
25
|
+
actions.push(`~/.natureco/ klasörü silinecek (config, hafıza, session'lar)`);
|
|
26
|
+
} else {
|
|
27
|
+
actions.push('Gateway ve dashboard durdurulacak');
|
|
28
|
+
actions.push('~/.natureco/gateway.pid ve dashboard.pid silinecek');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
actions.push('npm uninstall -g natureco-cli komutu gösterilecek');
|
|
32
|
+
|
|
33
|
+
if (dryRun) {
|
|
34
|
+
console.log(chalk.yellow(' Dry-run modu — hiçbir şey silinmeyecek\n'));
|
|
35
|
+
actions.forEach(a => console.log(chalk.gray(` • ${a}`)));
|
|
36
|
+
console.log('');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(chalk.yellow(' Yapılacaklar:\n'));
|
|
41
|
+
actions.forEach(a => console.log(chalk.gray(` • ${a}`)));
|
|
42
|
+
console.log('');
|
|
43
|
+
|
|
44
|
+
if (!yes) {
|
|
45
|
+
const { confirm } = await inquirer.prompt([{
|
|
46
|
+
type: 'confirm',
|
|
47
|
+
name: 'confirm',
|
|
48
|
+
message: ' Devam etmek istediğinizden emin misiniz?',
|
|
49
|
+
default: false,
|
|
50
|
+
}]);
|
|
51
|
+
if (!confirm) {
|
|
52
|
+
console.log(chalk.gray('\n İptal edildi.\n'));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Gateway durdur
|
|
58
|
+
if (fs.existsSync(pidFile)) {
|
|
59
|
+
try {
|
|
60
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim());
|
|
61
|
+
if (pid) process.kill(pid, 'SIGTERM');
|
|
62
|
+
fs.unlinkSync(pidFile);
|
|
63
|
+
console.log(chalk.green(' ✓ Gateway durduruldu'));
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Dashboard durdur
|
|
68
|
+
const dashPid = path.join(CONFIG_DIR, 'dashboard.pid');
|
|
69
|
+
if (fs.existsSync(dashPid)) {
|
|
70
|
+
try {
|
|
71
|
+
const pid = parseInt(fs.readFileSync(dashPid, 'utf-8').trim());
|
|
72
|
+
if (pid) process.kill(pid, 'SIGTERM');
|
|
73
|
+
fs.unlinkSync(dashPid);
|
|
74
|
+
console.log(chalk.green(' ✓ Dashboard durduruldu'));
|
|
75
|
+
} catch {}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// --all ise tüm veriyi sil
|
|
79
|
+
if (all && fs.existsSync(CONFIG_DIR)) {
|
|
80
|
+
fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
|
|
81
|
+
console.log(chalk.green(' ✓ ~/.natureco/ silindi'));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log(chalk.green(' ✓ Temizlik tamamlandı!'));
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(chalk.gray(' CLI\'yi tamamen kaldırmak için:'));
|
|
88
|
+
console.log(chalk.cyan(' npm uninstall -g natureco-cli'));
|
|
89
|
+
console.log('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = uninstall;
|
package/src/utils/config.js
CHANGED
|
@@ -5,23 +5,39 @@ const os = require('os');
|
|
|
5
5
|
const CONFIG_DIR = path.join(os.homedir(), '.natureco');
|
|
6
6
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
7
7
|
|
|
8
|
+
// --profile flag desteği: ~/.natureco-<profile>/
|
|
9
|
+
function getProfileDir() {
|
|
10
|
+
const profileArg = process.argv.find(a => a.startsWith('--profile='));
|
|
11
|
+
const profileIdx = process.argv.indexOf('--profile');
|
|
12
|
+
const profile = profileArg
|
|
13
|
+
? profileArg.split('=')[1]
|
|
14
|
+
: (profileIdx !== -1 ? process.argv[profileIdx + 1] : null);
|
|
15
|
+
if (profile && profile !== 'default') {
|
|
16
|
+
return path.join(os.homedir(), `.natureco-${profile}`);
|
|
17
|
+
}
|
|
18
|
+
return CONFIG_DIR;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ACTIVE_CONFIG_DIR = getProfileDir();
|
|
22
|
+
const ACTIVE_CONFIG_FILE = path.join(ACTIVE_CONFIG_DIR, 'config.json');
|
|
23
|
+
|
|
8
24
|
function ensureConfigDir() {
|
|
9
|
-
if (!fs.existsSync(
|
|
10
|
-
fs.mkdirSync(
|
|
25
|
+
if (!fs.existsSync(ACTIVE_CONFIG_DIR)) {
|
|
26
|
+
fs.mkdirSync(ACTIVE_CONFIG_DIR, { recursive: true });
|
|
11
27
|
}
|
|
12
28
|
}
|
|
13
29
|
|
|
14
30
|
function saveConfig(data) {
|
|
15
31
|
ensureConfigDir();
|
|
16
|
-
fs.writeFileSync(
|
|
32
|
+
fs.writeFileSync(ACTIVE_CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
function loadConfig() {
|
|
20
|
-
if (!fs.existsSync(
|
|
36
|
+
if (!fs.existsSync(ACTIVE_CONFIG_FILE)) {
|
|
21
37
|
return null;
|
|
22
38
|
}
|
|
23
39
|
try {
|
|
24
|
-
const content = fs.readFileSync(
|
|
40
|
+
const content = fs.readFileSync(ACTIVE_CONFIG_FILE, 'utf8');
|
|
25
41
|
return JSON.parse(content);
|
|
26
42
|
} catch (err) {
|
|
27
43
|
return null;
|
|
@@ -29,8 +45,8 @@ function loadConfig() {
|
|
|
29
45
|
}
|
|
30
46
|
|
|
31
47
|
function deleteConfig() {
|
|
32
|
-
if (fs.existsSync(
|
|
33
|
-
fs.unlinkSync(
|
|
48
|
+
if (fs.existsSync(ACTIVE_CONFIG_FILE)) {
|
|
49
|
+
fs.unlinkSync(ACTIVE_CONFIG_FILE);
|
|
34
50
|
}
|
|
35
51
|
}
|
|
36
52
|
|
|
@@ -76,6 +92,6 @@ module.exports = {
|
|
|
76
92
|
getConfig,
|
|
77
93
|
getAllConfig,
|
|
78
94
|
setConfigValue,
|
|
79
|
-
CONFIG_FILE,
|
|
80
|
-
CONFIG_DIR,
|
|
95
|
+
CONFIG_FILE: ACTIVE_CONFIG_FILE,
|
|
96
|
+
CONFIG_DIR: ACTIVE_CONFIG_DIR,
|
|
81
97
|
};
|