natureco-cli 2.23.28 → 2.23.30
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/README.md +94 -11
- package/bin/natureco.js +470 -10
- package/package.json +10 -6
- package/src/commands/admin-rpc.js +219 -0
- package/src/commands/agent.js +89 -0
- package/src/commands/approvals.js +53 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/capability.js +64 -0
- package/src/commands/channels.js +94 -4
- package/src/commands/chat.js +11 -25
- package/src/commands/clickclack.js +130 -0
- package/src/commands/commitments.js +32 -0
- package/src/commands/completion.js +76 -0
- package/src/commands/config.js +111 -68
- package/src/commands/configure.js +93 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/daemon.js +60 -0
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +110 -0
- package/src/commands/directory.js +47 -0
- package/src/commands/dns.js +58 -0
- package/src/commands/docs.js +43 -0
- package/src/commands/doctor.js +121 -16
- package/src/commands/exec-policy.js +71 -0
- package/src/commands/gateway-server.js +1175 -30
- package/src/commands/gateway.js +11 -20
- package/src/commands/health.js +18 -0
- package/src/commands/help.js +6 -0
- package/src/commands/imessage.js +169 -0
- package/src/commands/infer.js +73 -0
- package/src/commands/irc.js +119 -0
- package/src/commands/mattermost.js +164 -0
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/message.js +30 -4
- package/src/commands/migrate.js +213 -2
- package/src/commands/models.js +584 -216
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +106 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +70 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/plugins.js +415 -172
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +155 -0
- package/src/commands/qr.js +28 -0
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +118 -0
- package/src/commands/security.js +149 -1
- package/src/commands/setup.js +114 -10
- package/src/commands/signal.js +495 -0
- package/src/commands/skills.js +20 -29
- package/src/commands/sms.js +168 -0
- package/src/commands/system.js +53 -0
- package/src/commands/tasks.js +328 -79
- package/src/commands/terminal.js +21 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +72 -0
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/webhooks.js +79 -0
- package/src/commands/whatsapp.js +7 -21
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- package/src/tools/bash.js +63 -29
- package/src/tools/browser.js +112 -0
- package/src/tools/canvas.js +104 -0
- package/src/tools/document_extract.js +84 -0
- package/src/tools/duckduckgo.js +54 -0
- package/src/tools/exa_search.js +66 -0
- package/src/tools/firecrawl.js +104 -0
- package/src/tools/image_generation.js +99 -0
- package/src/tools/llm_task.js +118 -0
- package/src/tools/media_understanding.js +128 -0
- package/src/tools/music_generation.js +113 -0
- package/src/tools/parallel_search.js +77 -0
- package/src/tools/phone_control.js +80 -0
- package/src/tools/phone_control_enhanced.js +184 -0
- package/src/tools/searxng.js +61 -0
- package/src/tools/speech_to_text.js +135 -0
- package/src/tools/text_to_speech.js +105 -0
- package/src/tools/thread_ownership.js +88 -0
- package/src/tools/video_generation.js +72 -0
- package/src/tools/web_readability.js +104 -0
- package/src/utils/api.js +3 -20
- package/src/utils/approvals.js +297 -0
- package/src/utils/background.js +223 -66
- package/src/utils/baileys.js +21 -0
- package/src/utils/config.js +141 -10
- package/src/utils/errors.js +148 -0
- package/src/utils/inquirer-wrapper.js +1 -2
- package/src/utils/memory.js +200 -0
- package/src/utils/path-utils.js +13 -13
- package/src/utils/plugin-registry.js +238 -0
- package/src/utils/secrets.js +177 -0
- package/src/utils/skills.js +10 -23
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function devices(args) {
|
|
7
|
+
const [action, ...params] = args || [];
|
|
8
|
+
|
|
9
|
+
if (!action || action === 'list') return listDevices();
|
|
10
|
+
if (action === 'pair') return pairDevice(params[0], params[1]);
|
|
11
|
+
if (action === 'unpair') return unpairDevice(params[0]);
|
|
12
|
+
if (action === 'token' || action === 'show-token') return showToken();
|
|
13
|
+
if (action === 'regenerate-token') return regenerateToken();
|
|
14
|
+
|
|
15
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
16
|
+
console.log(chalk.gray(' Kullanım: natureco devices [list|pair|unpair|token|regenerate-token]\n'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function listDevices() {
|
|
21
|
+
const config = getConfig();
|
|
22
|
+
const devices = config.pairedDevices || [];
|
|
23
|
+
|
|
24
|
+
console.log(chalk.cyan('\n 📱 Devices\n'));
|
|
25
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
26
|
+
|
|
27
|
+
if (devices.length === 0) {
|
|
28
|
+
console.log(chalk.gray(' No paired devices.\n'));
|
|
29
|
+
console.log(chalk.gray(' Pair a device:'));
|
|
30
|
+
console.log(chalk.cyan(' natureco devices pair <name> <type>\n'));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const d of devices) {
|
|
35
|
+
console.log(` ${chalk.green('●')} ${chalk.white(d.name)} ${chalk.gray(`(${d.type || 'unknown'})`)}`);
|
|
36
|
+
console.log(` ${chalk.gray('ID:')} ${chalk.cyan(d.id)}`);
|
|
37
|
+
console.log(` ${chalk.gray('Since:')} ${d.pairedAt ? new Date(d.pairedAt).toLocaleString() : '-'}`);
|
|
38
|
+
}
|
|
39
|
+
console.log();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function pairDevice(name, type) {
|
|
43
|
+
if (!name) {
|
|
44
|
+
console.log(chalk.red('\n ❌ Device name gerekli\n'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
if (!config.pairedDevices) config.pairedDevices = [];
|
|
50
|
+
|
|
51
|
+
const device = {
|
|
52
|
+
id: `dev_${crypto.randomBytes(8).toString('hex')}`,
|
|
53
|
+
name,
|
|
54
|
+
type: type || 'unknown',
|
|
55
|
+
token: crypto.randomBytes(16).toString('hex'),
|
|
56
|
+
pairedAt: new Date().toISOString()
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
config.pairedDevices.push(device);
|
|
60
|
+
saveConfig(config);
|
|
61
|
+
|
|
62
|
+
console.log(chalk.green(`\n ✅ Paired: ${name}\n`));
|
|
63
|
+
console.log(chalk.gray(` Device ID: ${device.id}`));
|
|
64
|
+
console.log(chalk.gray(` Token: ${device.token}\n`));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function unpairDevice(id) {
|
|
68
|
+
if (!id) {
|
|
69
|
+
console.log(chalk.red('\n ❌ Device ID gerekli\n'));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const config = getConfig();
|
|
74
|
+
const devices = config.pairedDevices || [];
|
|
75
|
+
const idx = devices.findIndex(d => d.id === id);
|
|
76
|
+
|
|
77
|
+
if (idx === -1) {
|
|
78
|
+
console.log(chalk.red(`\n ❌ Cihaz bulunamadı: ${id}\n`));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const removed = devices.splice(idx, 1)[0];
|
|
83
|
+
config.pairedDevices = devices;
|
|
84
|
+
saveConfig(config);
|
|
85
|
+
|
|
86
|
+
console.log(chalk.gray(`\n 🗑️ Unpaired: ${removed.name}\n`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function showToken() {
|
|
90
|
+
const config = getConfig();
|
|
91
|
+
const token = config.pairingToken || 'not-set';
|
|
92
|
+
|
|
93
|
+
console.log(chalk.cyan('\n 🔑 Device Token\n'));
|
|
94
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
95
|
+
console.log(` Token: ${chalk.yellow(token)}`);
|
|
96
|
+
console.log(chalk.gray('\n This token identifies this device for pairing.\n'));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function regenerateToken() {
|
|
100
|
+
const config = getConfig();
|
|
101
|
+
config.pairingToken = `nc_${crypto.randomBytes(16).toString('hex')}`;
|
|
102
|
+
saveConfig(config);
|
|
103
|
+
|
|
104
|
+
console.log(chalk.green('\n ✅ Token regenerated\n'));
|
|
105
|
+
console.log(chalk.gray(` New token: ${chalk.yellow(config.pairingToken)}\n`));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const crypto = require('crypto');
|
|
109
|
+
|
|
110
|
+
module.exports = devices;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig } = require('../utils/config');
|
|
3
|
+
|
|
4
|
+
function directory(args) {
|
|
5
|
+
const [action, ...params] = args || [];
|
|
6
|
+
|
|
7
|
+
if (!action || action === 'self') return showSelf();
|
|
8
|
+
if (action === 'channels' || action === 'peers') return listChannels();
|
|
9
|
+
|
|
10
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
11
|
+
console.log(chalk.gray(' Kullanım: natureco directory [self|channels]\n'));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function showSelf() {
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
console.log(chalk.cyan('\n 👤 Self\n'));
|
|
18
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
19
|
+
console.log(` ${chalk.white('Name:')} ${chalk.cyan(config.agentName || process.env.USER || 'user')}`);
|
|
20
|
+
console.log(` ${chalk.white('Gateway:')} ${chalk.gray(config.gatewayUrl || 'not configured')}`);
|
|
21
|
+
console.log(` ${chalk.white('Provider:')} ${chalk.gray(config.provider || 'not set')}`);
|
|
22
|
+
console.log(` ${chalk.white('Model:')} ${chalk.gray(config.model || 'not set')}`);
|
|
23
|
+
console.log(` ${chalk.white('User ID:')} ${chalk.gray(config.userId || 'local')}`);
|
|
24
|
+
console.log();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function listChannels() {
|
|
28
|
+
const config = getConfig();
|
|
29
|
+
console.log(chalk.cyan('\n 📡 Channels\n'));
|
|
30
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
31
|
+
|
|
32
|
+
const channels = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage', 'sms'];
|
|
33
|
+
let found = false;
|
|
34
|
+
|
|
35
|
+
for (const ch of channels) {
|
|
36
|
+
if (config[ch]) {
|
|
37
|
+
const info = typeof config[ch] === 'object' ? Object.keys(config[ch]).join(', ') : 'connected';
|
|
38
|
+
console.log(` ${chalk.green('●')} ${chalk.white(ch)}: ${chalk.gray(info)}`);
|
|
39
|
+
found = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!found) console.log(chalk.gray(' No channels configured.\n'));
|
|
44
|
+
console.log();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = directory;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const dns = require('dns');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
function dnsCmd(args) {
|
|
6
|
+
const [action, ...params] = args || [];
|
|
7
|
+
|
|
8
|
+
if (!action || action === 'discover') return discoverNetwork();
|
|
9
|
+
if (action === 'resolve') return resolveHost(params[0]);
|
|
10
|
+
|
|
11
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
12
|
+
console.log(chalk.gray(' Kullanım: natureco dns [discover|resolve]\n'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function discoverNetwork() {
|
|
17
|
+
console.log(chalk.cyan('\n 🌐 Network Discovery (DNS)\n'));
|
|
18
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
19
|
+
|
|
20
|
+
const interfaces = os.networkInterfaces();
|
|
21
|
+
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
22
|
+
if (!addrs) continue;
|
|
23
|
+
for (const addr of addrs) {
|
|
24
|
+
if (addr.family === 'IPv4' && !addr.internal) {
|
|
25
|
+
console.log(` ${chalk.white(name)}`);
|
|
26
|
+
console.log(` ${chalk.gray('IP:')} ${addr.address}`);
|
|
27
|
+
console.log(` ${chalk.gray('MAC:')} ${addr.mac}`);
|
|
28
|
+
console.log(` ${chalk.gray('Mask:')} ${addr.netmask}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(chalk.gray('\n Service discovery for wide-area (Tailscale + CoreDNS).'));
|
|
34
|
+
console.log(chalk.gray(' For full mDNS: ') + chalk.cyan('natureco bonjour scan\n'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function resolveHost(hostname) {
|
|
38
|
+
if (!hostname) {
|
|
39
|
+
console.log(chalk.red('\n ❌ Hostname gerekli\n'));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(chalk.cyan(`\n 🔍 Resolving: ${hostname}\n`));
|
|
44
|
+
|
|
45
|
+
dns.resolve4(hostname, (err, addresses) => {
|
|
46
|
+
if (err) {
|
|
47
|
+
console.log(chalk.red(` ❌ ${err.message}\n`));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
51
|
+
for (const addr of addresses) {
|
|
52
|
+
console.log(` ${chalk.white(hostname)} → ${chalk.cyan(addr)}`);
|
|
53
|
+
}
|
|
54
|
+
console.log();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = dnsCmd;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
async function docs(args) {
|
|
4
|
+
const query = args.join(' ').trim();
|
|
5
|
+
|
|
6
|
+
if (!query) {
|
|
7
|
+
console.log(chalk.cyan('\n 📚 NatureCo Docs Search\n'));
|
|
8
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
9
|
+
console.log(chalk.gray(' Search live documentation from the web.\n'));
|
|
10
|
+
console.log(chalk.gray(' Usage:'));
|
|
11
|
+
console.log(chalk.cyan(' natureco docs <search query>'));
|
|
12
|
+
console.log(chalk.gray('\n Examples:'));
|
|
13
|
+
console.log(chalk.gray(' natureco docs how to setup gateway'));
|
|
14
|
+
console.log(chalk.gray(' natureco docs channels telegram'));
|
|
15
|
+
console.log();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
console.log(chalk.cyan(`\n 🔍 Searching docs for: "${query}"\n`));
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`https://api.duckduckgo.com/?q=${encodeURIComponent('natureco ' + query)}&format=json&no_html=1`, {
|
|
23
|
+
headers: { 'User-Agent': 'NatureCo-CLI/2.0' }
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (!response.ok) throw new Error(`Search error: ${response.status}`);
|
|
27
|
+
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
if (data.AbstractText) {
|
|
30
|
+
console.log(chalk.white(data.AbstractText));
|
|
31
|
+
if (data.AbstractURL) console.log(chalk.gray(`\n Source: ${data.AbstractURL}`));
|
|
32
|
+
} else {
|
|
33
|
+
console.log(chalk.gray(' No documentation found for this query.'));
|
|
34
|
+
console.log(chalk.gray('\n Try searching the web:'));
|
|
35
|
+
console.log(chalk.cyan(` natureco web_search query="${query}"`));
|
|
36
|
+
}
|
|
37
|
+
console.log();
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.log(chalk.red(` ❌ ${err.message}\n`));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = docs;
|
package/src/commands/doctor.js
CHANGED
|
@@ -2,9 +2,12 @@ const chalk = require('chalk');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const net = require('net');
|
|
5
|
-
const { getConfig, saveConfig, CONFIG_FILE, CONFIG_DIR } = require('../utils/config');
|
|
5
|
+
const { getConfig, saveConfig, CONFIG_FILE, CONFIG_DIR, listBackups } = require('../utils/config');
|
|
6
6
|
const { getBots } = require('../utils/api');
|
|
7
7
|
const { getSkills } = require('../utils/skills');
|
|
8
|
+
const { NatureCoError, ApiError, ConfigError, handleError } = require('../utils/errors');
|
|
9
|
+
const { listSecretRefs, resolveSecretRef } = require('../utils/secrets');
|
|
10
|
+
const { loadApprovals, resolveEffectivePolicy } = require('../utils/approvals');
|
|
8
11
|
|
|
9
12
|
async function doctor(options) {
|
|
10
13
|
const shouldFix = options && (options.includes('--fix') || options.includes('-f'));
|
|
@@ -258,27 +261,40 @@ async function doctor(options) {
|
|
|
258
261
|
results.push({ status: 'warning', message: 'Tavily API key yok', fix: 'natureco config set tavilyApiKey tvly_xxx' });
|
|
259
262
|
}
|
|
260
263
|
|
|
261
|
-
// 15. Provider erişim kontrolü
|
|
264
|
+
// 15. Provider erişim kontrolü (gerçek API doğrulama)
|
|
262
265
|
total++;
|
|
263
266
|
criticalTotal++;
|
|
264
267
|
if (config && config.providerUrl) {
|
|
265
268
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
const response = await fetch(config.providerUrl, {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
headers: {
|
|
272
|
+
'Content-Type': 'application/json',
|
|
273
|
+
...(config.providerApiKey ? { 'Authorization': `Bearer ${config.providerApiKey}` } : {}),
|
|
274
|
+
},
|
|
275
|
+
body: JSON.stringify({
|
|
276
|
+
model: config.providerModel || 'llama-3.3-70b-versatile',
|
|
277
|
+
messages: [{ role: 'user', content: 'test' }],
|
|
278
|
+
max_tokens: 1,
|
|
279
|
+
}),
|
|
280
|
+
signal: AbortSignal.timeout(15000),
|
|
272
281
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
282
|
+
|
|
283
|
+
if (response.ok) {
|
|
284
|
+
console.log(chalk.green('✅ Provider:'), chalk.white('API doğrulandı'));
|
|
285
|
+
passed++;
|
|
286
|
+
criticalPassed++;
|
|
287
|
+
results.push({ status: 'ok', message: 'Provider API doğrulandı' });
|
|
288
|
+
} else if (response.status === 401 || response.status === 403) {
|
|
289
|
+
console.log(chalk.red('❌ Provider:'), chalk.white('API key geçersiz'));
|
|
290
|
+
results.push({ status: 'error', message: 'API key reddedildi', fix: 'natureco config set providerApiKey <key>' });
|
|
291
|
+
} else {
|
|
292
|
+
console.log(chalk.yellow('⚠️ Provider:'), chalk.white(`HTTP ${response.status} — beklenmeyen yanıt`));
|
|
293
|
+
results.push({ status: 'warning', message: `Provider HTTP ${response.status} döndü` });
|
|
294
|
+
}
|
|
279
295
|
} catch (err) {
|
|
280
|
-
console.log(chalk.red('Bağlantı hatası: ' + err.message));
|
|
281
|
-
results.push({ status: 'error', message: 'Provider
|
|
296
|
+
console.log(chalk.red('❌ Provider:'), chalk.white('Bağlantı hatası: ' + err.message));
|
|
297
|
+
results.push({ status: 'error', message: 'Provider bağlantı hatası' });
|
|
282
298
|
}
|
|
283
299
|
} else {
|
|
284
300
|
console.log(chalk.gray('⚪ Provider Erişim:'), chalk.white('Provider URL ayarlanmamış'));
|
|
@@ -321,6 +337,95 @@ async function doctor(options) {
|
|
|
321
337
|
results.push({ status: 'info', message: 'Versiyon kontrol edilemedi' });
|
|
322
338
|
}
|
|
323
339
|
|
|
340
|
+
// 17. Exec approvals kontrolü
|
|
341
|
+
total++;
|
|
342
|
+
const approvals = loadApprovals();
|
|
343
|
+
const policy = resolveEffectivePolicy(approvals);
|
|
344
|
+
const allowlistCount = (approvals.allowlist || []).length;
|
|
345
|
+
if (policy !== 'deny' || allowlistCount > 0) {
|
|
346
|
+
passed++;
|
|
347
|
+
results.push({ status: 'ok', message: `Güvenlik: ${policy} (${allowlistCount} allowlist)` });
|
|
348
|
+
console.log(chalk.green('✅ Exec Güvenlik:'), chalk.white(`${policy} — ${allowlistCount} allowlist kuralı`));
|
|
349
|
+
} else {
|
|
350
|
+
results.push({ status: 'warning', message: 'Exec güvenlik deny modunda', fix: 'natureco security policy set allowlist' });
|
|
351
|
+
console.log(chalk.yellow('⚠️ Exec Güvenlik:'), chalk.white('deny modunda, komut çalıştırma engelli'));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// 18. Exec approvals allowlist durumu (opsiyonel detay)
|
|
355
|
+
if (allowlistCount > 0) {
|
|
356
|
+
const expired = (approvals.allowlist || []).filter(e => e.expires && new Date(e.expires) < new Date()).length;
|
|
357
|
+
if (expired > 0) {
|
|
358
|
+
console.log(chalk.yellow(` ⚠ ${expired} allowlist kuralı süresi dolmuş`));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 19. Config yedekleri kontrolü
|
|
363
|
+
total++;
|
|
364
|
+
try {
|
|
365
|
+
const backupDir = path.join(CONFIG_DIR, 'backups');
|
|
366
|
+
if (fs.existsSync(backupDir)) {
|
|
367
|
+
const backups = fs.readdirSync(backupDir).filter(f => f.startsWith('config-') && f.endsWith('.json'));
|
|
368
|
+
if (backups.length > 0) {
|
|
369
|
+
passed++;
|
|
370
|
+
results.push({ status: 'ok', message: `${backups.length} config yedeği mevcut` });
|
|
371
|
+
console.log(chalk.green('✅ Config Yedek:'), chalk.white(`${backups.length} yedek`));
|
|
372
|
+
|
|
373
|
+
if (backups.length >= 10) {
|
|
374
|
+
console.log(chalk.yellow(' ⚠ Maksimum yedek sayısına ulaşıldı (10)'));
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
results.push({ status: 'info', message: 'Config yedeği yok' });
|
|
378
|
+
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Yedek bulunamadı'));
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
results.push({ status: 'info', message: 'Config yedeği yok' });
|
|
382
|
+
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Yedek klasörü yok'));
|
|
383
|
+
}
|
|
384
|
+
} catch {
|
|
385
|
+
results.push({ status: 'info', message: 'Config yedekleri kontrol edilemedi' });
|
|
386
|
+
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Kontrol edilemedi'));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// 20. Secret referansları kontrolü
|
|
390
|
+
total++;
|
|
391
|
+
try {
|
|
392
|
+
const secretRefs = listSecretRefs(config || {});
|
|
393
|
+
if (secretRefs.length > 0) {
|
|
394
|
+
const unresolved = secretRefs.filter(ref => {
|
|
395
|
+
try {
|
|
396
|
+
return resolveSecretRef(ref) === null;
|
|
397
|
+
} catch {
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
if (unresolved.length === 0) {
|
|
403
|
+
passed++;
|
|
404
|
+
results.push({ status: 'ok', message: `${secretRefs.length} secret referansı çözüldü` });
|
|
405
|
+
console.log(chalk.green('✅ Secrets:'), chalk.white(`${secretRefs.length} referans çözüldü`));
|
|
406
|
+
} else {
|
|
407
|
+
results.push({ status: 'warning', message: `${unresolved.length}/${secretRefs.length} secret çözülemedi`, fix: '.env dosyası oluşturun' });
|
|
408
|
+
console.log(chalk.yellow('⚠️ Secrets:'), chalk.white(`${unresolved.length}/${secretRefs.length} referans çözülemedi`));
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
results.push({ status: 'info', message: 'Secret referansı yok' });
|
|
412
|
+
console.log(chalk.gray('⚪ Secrets:'), chalk.white('Referans yok'));
|
|
413
|
+
}
|
|
414
|
+
} catch {
|
|
415
|
+
results.push({ status: 'info', message: 'Secrets kontrol edilemedi' });
|
|
416
|
+
console.log(chalk.gray('⚪ Secrets:'), chalk.white('Kontrol edilemedi'));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 21. .env dosyası varlığı (secret ref varsa)
|
|
420
|
+
if (config) {
|
|
421
|
+
const envFile = path.join(CONFIG_DIR, '.env');
|
|
422
|
+
if (fs.existsSync(envFile)) {
|
|
423
|
+
console.log(chalk.gray(' 📄 .env dosyası:'), chalk.white('Mevcut'));
|
|
424
|
+
} else {
|
|
425
|
+
console.log(chalk.gray(' 📄 .env dosyası:'), chalk.white('Yok'));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
324
429
|
// Özet
|
|
325
430
|
console.log('');
|
|
326
431
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
|
+
|
|
4
|
+
function execPolicy(args) {
|
|
5
|
+
const [action, ...params] = args || [];
|
|
6
|
+
|
|
7
|
+
if (!action || action === 'show') return showPolicy();
|
|
8
|
+
if (action === 'set') return setPolicy(params[0]);
|
|
9
|
+
if (action === 'sync') return syncPolicy();
|
|
10
|
+
|
|
11
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
12
|
+
console.log(chalk.gray(' Kullanım: natureco exec-policy [show|set|sync]\n'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function showPolicy() {
|
|
17
|
+
const config = getConfig();
|
|
18
|
+
const policy = config.execPolicy || 'default';
|
|
19
|
+
|
|
20
|
+
console.log(chalk.cyan('\n 📋 Exec Policy\n'));
|
|
21
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
22
|
+
console.log(` ${chalk.white('Policy:')} ${chalk.cyan(policy)}`);
|
|
23
|
+
console.log(` ${chalk.white('Allow commands:')} ${chalk.gray(config.execAllowCommands !== false ? 'Yes' : 'No')}`);
|
|
24
|
+
console.log(` ${chalk.white('Timeout:')} ${chalk.gray(config.execTimeout || 30000)}ms`);
|
|
25
|
+
console.log(` ${chalk.white('Sandbox:')} ${chalk.gray(config.execSandbox || 'none')}`);
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(chalk.gray(' Set policy:'));
|
|
28
|
+
console.log(chalk.cyan(' natureco exec-policy set <policy>'));
|
|
29
|
+
console.log(chalk.cyan(' natureco exec-policy sync\n'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function setPolicy(policy) {
|
|
33
|
+
if (!policy) {
|
|
34
|
+
console.log(chalk.red('\n ❌ Policy gerekli\n'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const config = getConfig();
|
|
39
|
+
config.execPolicy = policy;
|
|
40
|
+
saveConfig(config);
|
|
41
|
+
console.log(chalk.green(`\n ✅ Exec policy: ${policy}\n`));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function syncPolicy() {
|
|
45
|
+
const config = getConfig();
|
|
46
|
+
console.log(chalk.cyan('\n 🔄 Syncing exec policy...\n'));
|
|
47
|
+
|
|
48
|
+
const defaults = {
|
|
49
|
+
execPolicy: 'default',
|
|
50
|
+
execAllowCommands: true,
|
|
51
|
+
execTimeout: 30000,
|
|
52
|
+
execSandbox: 'none'
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
let changed = 0;
|
|
56
|
+
for (const [key, val] of Object.entries(defaults)) {
|
|
57
|
+
if (config[key] === undefined) {
|
|
58
|
+
config[key] = val;
|
|
59
|
+
changed++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (changed > 0) {
|
|
64
|
+
saveConfig(config);
|
|
65
|
+
console.log(chalk.green(` ✅ Synced ${changed} policy settings\n`));
|
|
66
|
+
} else {
|
|
67
|
+
console.log(chalk.gray(' ✅ Already in sync\n'));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = execPolicy;
|