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,219 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const http = require('http');
|
|
3
|
+
const { getConfig } = require('../utils/config');
|
|
4
|
+
|
|
5
|
+
const ALLOWED_METHODS = [
|
|
6
|
+
'health', 'status',
|
|
7
|
+
'config.get', 'config.set',
|
|
8
|
+
'channels.status', 'channels.start', 'channels.stop',
|
|
9
|
+
'agents.list',
|
|
10
|
+
'logs.tail',
|
|
11
|
+
'cron.list', 'cron.status',
|
|
12
|
+
'tasks.list',
|
|
13
|
+
'plugins.list'
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
let serverInstance = null;
|
|
17
|
+
|
|
18
|
+
function adminRpc(args) {
|
|
19
|
+
const [action, ...params] = args || [];
|
|
20
|
+
|
|
21
|
+
if (!action || action === 'status') return statusAdmin();
|
|
22
|
+
if (action === 'start') return startAdmin(params[0]);
|
|
23
|
+
if (action === 'stop') return stopAdmin();
|
|
24
|
+
if (action === 'call') return callMethod(params[0], params.slice(1).join(' '));
|
|
25
|
+
if (action === 'methods') return listMethods();
|
|
26
|
+
|
|
27
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
28
|
+
console.log(chalk.gray(' Kullanım: natureco admin-rpc [status|start|stop|call|methods]\n'));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function statusAdmin() {
|
|
33
|
+
const running = serverInstance !== null;
|
|
34
|
+
console.log(chalk.cyan('\n 🖥️ Admin HTTP RPC\n'));
|
|
35
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
36
|
+
console.log(` ${chalk.white('Server:')} ${running ? chalk.green(`http://localhost:${serverInstance?.port || 3847}`) : chalk.red('Durduruldu')}`);
|
|
37
|
+
console.log(` ${chalk.white('Methods:')} ${ALLOWED_METHODS.length}`);
|
|
38
|
+
console.log(chalk.gray('\n Commands:'));
|
|
39
|
+
console.log(chalk.cyan(' start [port]') + chalk.gray(' Start RPC server (default: 3847)'));
|
|
40
|
+
console.log(chalk.cyan(' stop') + chalk.gray(' Stop RPC server'));
|
|
41
|
+
console.log(chalk.cyan(' call <method>') + chalk.gray(' Call RPC method'));
|
|
42
|
+
console.log(chalk.cyan(' methods') + chalk.gray(' List methods'));
|
|
43
|
+
console.log();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function listMethods() {
|
|
47
|
+
console.log(chalk.cyan('\n 📋 Admin RPC Methods\n'));
|
|
48
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
49
|
+
for (const m of ALLOWED_METHODS) {
|
|
50
|
+
console.log(` ${chalk.white(m)}`);
|
|
51
|
+
}
|
|
52
|
+
console.log();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function callMethod(method, jsonParams) {
|
|
56
|
+
if (!method) {
|
|
57
|
+
console.log(chalk.red('\n ❌ Method adı gerekli\n'));
|
|
58
|
+
console.log(chalk.cyan(' natureco admin-rpc call health\n'));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!ALLOWED_METHODS.includes(method)) {
|
|
63
|
+
console.log(chalk.red(`\n ❌ Desteklenmeyen method: ${method}\n`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let params = {};
|
|
68
|
+
if (jsonParams) {
|
|
69
|
+
try { params = JSON.parse(jsonParams); }
|
|
70
|
+
catch { console.log(chalk.red('\n ❌ Geçersiz JSON\n')); process.exit(1); }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(chalk.cyan(`\n 📡 Calling: ${method}\n`));
|
|
74
|
+
|
|
75
|
+
if (method === 'health') {
|
|
76
|
+
console.log(chalk.green(' ✅ System healthy'));
|
|
77
|
+
console.log(chalk.gray(` Node: ${process.version}`));
|
|
78
|
+
console.log(chalk.gray(` Platform: ${process.platform}`));
|
|
79
|
+
console.log(chalk.gray(` Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB\n`));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (method === 'status') {
|
|
84
|
+
const config = getConfig();
|
|
85
|
+
console.log(chalk.green(' ✅ Status\n'));
|
|
86
|
+
console.log(chalk.gray(` Gateway: ${config.gatewayUrl || 'not configured'}`));
|
|
87
|
+
console.log(chalk.gray(` Provider: ${config.provider || 'not set'}`));
|
|
88
|
+
console.log(chalk.gray(` Model: ${config.model || 'not set'}\n`));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (method === 'plugins.list') {
|
|
93
|
+
const { loadTools } = require('../utils/tool-runner');
|
|
94
|
+
const tools = loadTools();
|
|
95
|
+
console.log(chalk.green(` 📦 ${Object.keys(tools).length} tools loaded\n`));
|
|
96
|
+
for (const [name, t] of Object.entries(tools)) {
|
|
97
|
+
console.log(` ${chalk.white('●')} ${name} ${chalk.gray('- ' + (t.description || '').substring(0, 60))}`);
|
|
98
|
+
}
|
|
99
|
+
console.log();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (method === 'config.get') {
|
|
104
|
+
const config = getConfig();
|
|
105
|
+
const key = params.key;
|
|
106
|
+
if (key) {
|
|
107
|
+
const value = key.split('.').reduce((o, k) => o?.[k], config);
|
|
108
|
+
console.log(chalk.white(` ${key}: `) + chalk.cyan(JSON.stringify(value)));
|
|
109
|
+
} else {
|
|
110
|
+
console.log(chalk.cyan(JSON.stringify(config, null, 2)));
|
|
111
|
+
}
|
|
112
|
+
console.log();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (method === 'logs.tail') {
|
|
117
|
+
const lines = params.lines || 20;
|
|
118
|
+
const { execSync } = require('child_process');
|
|
119
|
+
try {
|
|
120
|
+
const logPath = require('path').join(require('os').homedir(), '.natureco', 'logs', 'gateway.log');
|
|
121
|
+
const output = execSync(`tail -${lines} "${logPath}"`, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
|
|
122
|
+
console.log(output);
|
|
123
|
+
} catch {
|
|
124
|
+
console.log(chalk.yellow(' ⚠️ Log bulunamadı\n'));
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log(chalk.yellow(` ⚠️ Method "${method}" henüz implemente edilmedi\n`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function startAdmin(portStr) {
|
|
133
|
+
if (serverInstance) {
|
|
134
|
+
console.log(chalk.yellow('\n ⚠️ Server zaten çalışıyor\n'));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const port = parseInt(portStr, 10) || 3847;
|
|
139
|
+
|
|
140
|
+
const server = http.createServer((req, res) => {
|
|
141
|
+
if (req.method !== 'POST') {
|
|
142
|
+
res.writeHead(405, { 'Allow': 'POST', 'Content-Type': 'application/json' });
|
|
143
|
+
res.end(JSON.stringify({ ok: false, error: 'Method not allowed' }));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let body = '';
|
|
148
|
+
req.on('data', chunk => { body += chunk; });
|
|
149
|
+
req.on('end', async () => {
|
|
150
|
+
try {
|
|
151
|
+
const rpc = JSON.parse(body);
|
|
152
|
+
if (!rpc.method || typeof rpc.method !== 'string') {
|
|
153
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
154
|
+
res.end(JSON.stringify({ ok: false, error: 'method required' }));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!ALLOWED_METHODS.includes(rpc.method)) {
|
|
159
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
160
|
+
res.end(JSON.stringify({ ok: false, error: `Method not allowed: ${rpc.method}` }));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const config = getConfig();
|
|
165
|
+
let payload;
|
|
166
|
+
|
|
167
|
+
if (rpc.method === 'health') {
|
|
168
|
+
payload = { status: 'ok', node: process.version, uptime: process.uptime() };
|
|
169
|
+
} else if (rpc.method === 'status') {
|
|
170
|
+
payload = { gateway: config.gatewayUrl, provider: config.provider, model: config.model };
|
|
171
|
+
} else if (rpc.method === 'config.get') {
|
|
172
|
+
const key = rpc.params?.key;
|
|
173
|
+
payload = key ? { [key]: key.split('.').reduce((o, k) => o?.[k], config) } : config;
|
|
174
|
+
} else if (rpc.method === 'plugins.list') {
|
|
175
|
+
const { loadTools } = require('../utils/tool-runner');
|
|
176
|
+
payload = { tools: Object.keys(loadTools()) };
|
|
177
|
+
} else {
|
|
178
|
+
payload = { message: `Method "${rpc.method}" called`, params: rpc.params };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
182
|
+
res.end(JSON.stringify({ ok: true, id: rpc.id || 'rpc-1', payload }));
|
|
183
|
+
} catch (err) {
|
|
184
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
185
|
+
res.end(JSON.stringify({ ok: false, error: 'Invalid JSON' }));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
serverInstance = server;
|
|
191
|
+
serverInstance.port = port;
|
|
192
|
+
|
|
193
|
+
server.listen(port, () => {
|
|
194
|
+
console.log(chalk.green(`\n ✅ Admin RPC server started on http://localhost:${port}\n`));
|
|
195
|
+
console.log(chalk.gray(' POST requests with JSON body:'));
|
|
196
|
+
console.log(chalk.white(' { "method": "health", "id": "req-1" }'));
|
|
197
|
+
console.log(chalk.white(' { "method": "config.get", "params": { "key": "provider" } }'));
|
|
198
|
+
console.log(chalk.gray('\n Press Ctrl+C to stop\n'));
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
server.on('error', (err) => {
|
|
202
|
+
console.log(chalk.red(`\n ❌ Server error: ${err.message}\n`));
|
|
203
|
+
serverInstance = null;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function stopAdmin() {
|
|
208
|
+
if (!serverInstance) {
|
|
209
|
+
console.log(chalk.yellow('\n ⚠️ Server çalışmıyor\n'));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
serverInstance.close(() => {
|
|
214
|
+
console.log(chalk.gray('\n 🛑 Admin RPC server durduruldu\n'));
|
|
215
|
+
serverInstance = null;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = adminRpc;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
async function agent(args) {
|
|
4
|
+
const opts = {};
|
|
5
|
+
for (let i = 0; i < args.length; i++) {
|
|
6
|
+
if (args[i] === '--to' || args[i] === '-t') opts.to = args[++i];
|
|
7
|
+
else if (args[i] === '--message' || args[i] === '-m') opts.message = args[++i];
|
|
8
|
+
else if (args[i] === '--channel' || args[i] === '-c') opts.channel = args[++i];
|
|
9
|
+
else if (args[i] === '--deliver') opts.deliver = true;
|
|
10
|
+
else if (args[i] === '--model') opts.model = args[++i];
|
|
11
|
+
else if (args[i] === '--provider') opts.provider = args[++i];
|
|
12
|
+
else if (!opts.action) opts.action = args[i];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!opts.action || opts.action === 'help') return showHelp();
|
|
16
|
+
if (opts.action === 'run') return runAgent(opts);
|
|
17
|
+
|
|
18
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${opts.action}\n`));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function runAgent(opts) {
|
|
23
|
+
const { getConfig } = require('../utils/config');
|
|
24
|
+
const config = getConfig();
|
|
25
|
+
|
|
26
|
+
const provider = opts.provider || config.provider || 'openai';
|
|
27
|
+
const model = opts.model || config.model || 'gpt-4o';
|
|
28
|
+
const message = opts.message || 'Hello';
|
|
29
|
+
|
|
30
|
+
console.log(chalk.cyan(`\n 🤖 Agent Turn\n`));
|
|
31
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
32
|
+
console.log(` ${chalk.white('Message:')} ${message}`);
|
|
33
|
+
if (opts.to) console.log(` ${chalk.white('To:')} ${opts.to}`);
|
|
34
|
+
if (opts.channel) console.log(` ${chalk.white('Channel:')} ${opts.channel}`);
|
|
35
|
+
console.log(` ${chalk.white('Provider:')} ${provider}`);
|
|
36
|
+
console.log(` ${chalk.white('Model:')} ${model}`);
|
|
37
|
+
console.log(chalk.gray('\n Running...\n'));
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const apiKey = config[`${provider}ApiKey`] || process.env[`${provider.toUpperCase()}_API_KEY`];
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
console.log(chalk.red(` ❌ ${provider} API key gerekli\n`));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const baseUrl = provider === 'openai' ? 'https://api.openai.com/v1' : `https://api.${provider}.com/v1`;
|
|
47
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
|
|
50
|
+
body: JSON.stringify({ model, messages: [{ role: 'user', content: message }], max_tokens: 2048 })
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (!response.ok) throw new Error(`API error ${response.status}`);
|
|
54
|
+
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
const reply = data.choices?.[0]?.message?.content || 'No response';
|
|
57
|
+
|
|
58
|
+
console.log(chalk.white(' Response:'));
|
|
59
|
+
console.log(chalk.gray(` ${reply.substring(0, 500)}`));
|
|
60
|
+
|
|
61
|
+
if (opts.deliver && opts.channel) {
|
|
62
|
+
console.log(chalk.gray(`\n 📨 Delivering via ${opts.channel}...`));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log();
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.log(chalk.red(` ❌ ${err.message}\n`));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function showHelp() {
|
|
73
|
+
console.log(chalk.cyan('\n 🤖 Agent\n'));
|
|
74
|
+
console.log(chalk.gray(' Run one agent turn via the Gateway'));
|
|
75
|
+
console.log(chalk.gray('\n Usage: natureco agent [options]'));
|
|
76
|
+
console.log(chalk.gray('\n Options:'));
|
|
77
|
+
console.log(chalk.cyan(' run') + chalk.gray(' Run an agent turn'));
|
|
78
|
+
console.log(chalk.cyan(' --message, -m <text>') + chalk.gray(' Message to send'));
|
|
79
|
+
console.log(chalk.cyan(' --to, -t <target>') + chalk.gray(' Target channel/contact'));
|
|
80
|
+
console.log(chalk.cyan(' --channel, -c <name>') + chalk.gray(' Channel to use'));
|
|
81
|
+
console.log(chalk.cyan(' --deliver') + chalk.gray(' Deliver reply via channel'));
|
|
82
|
+
console.log(chalk.cyan(' --model <model>') + chalk.gray(' Model override'));
|
|
83
|
+
console.log(chalk.cyan(' --provider <name>') + chalk.gray(' Provider override'));
|
|
84
|
+
console.log(chalk.gray('\n Examples:'));
|
|
85
|
+
console.log(chalk.gray(' natureco agent run --message "Summarize this"'));
|
|
86
|
+
console.log(chalk.gray(' natureco agent run --to +1234 --message "Hi" --deliver\n'));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = agent;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
|
+
|
|
4
|
+
function approvals(args) {
|
|
5
|
+
const [action, ...params] = args || [];
|
|
6
|
+
|
|
7
|
+
if (!action || action === 'list') return listApprovals();
|
|
8
|
+
if (action === 'pending') return listPending();
|
|
9
|
+
if (action === 'approve') return approveReq(params[0]);
|
|
10
|
+
if (action === 'reject') return rejectReq(params[0]);
|
|
11
|
+
if (action === 'set-policy') return setPolicy(params[0]);
|
|
12
|
+
|
|
13
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
14
|
+
console.log(chalk.gray(' Kullanım: natureco approvals [list|pending|approve|reject|set-policy]\n'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function listApprovals() {
|
|
19
|
+
const config = getConfig();
|
|
20
|
+
const policy = config.execApprovalPolicy || 'auto';
|
|
21
|
+
console.log(chalk.cyan('\n 📋 Exec Approvals\n'));
|
|
22
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
23
|
+
console.log(` ${chalk.white('Policy:')} ${chalk.cyan(policy)}`);
|
|
24
|
+
console.log(chalk.gray('\n Pending: use') + chalk.cyan(' natureco approvals pending'));
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function listPending() {
|
|
29
|
+
console.log(chalk.cyan('\n ⏳ Pending Approvals\n'));
|
|
30
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
31
|
+
console.log(chalk.gray(' No pending approvals.\n'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function approveReq(id) {
|
|
35
|
+
console.log(chalk.green(`\n ✅ Approved: ${id || 'all pending'}\n`));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function rejectReq(id) {
|
|
39
|
+
console.log(chalk.gray(`\n ❌ Rejected: ${id || 'all pending'}\n`));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setPolicy(policy) {
|
|
43
|
+
if (!policy || !['auto', 'always-ask', 'trusted'].includes(policy)) {
|
|
44
|
+
console.log(chalk.red('\n ❌ Policy must be: auto, always-ask, or trusted\n'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const config = getConfig();
|
|
48
|
+
config.execApprovalPolicy = policy;
|
|
49
|
+
saveConfig(config);
|
|
50
|
+
console.log(chalk.green(`\n ✅ Approval policy: ${policy}\n`));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = approvals;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const NATURECO_DIR = path.join(os.homedir(), '.natureco');
|
|
8
|
+
|
|
9
|
+
function backup(args) {
|
|
10
|
+
const [action, ...params] = args || [];
|
|
11
|
+
|
|
12
|
+
if (!action || action === 'create') return createBackup();
|
|
13
|
+
if (action === 'list') return listBackups();
|
|
14
|
+
if (action === 'restore') return restoreBackup(params.join(' '));
|
|
15
|
+
if (action === 'verify') return verifyBackup(params.join(' '));
|
|
16
|
+
|
|
17
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
18
|
+
console.log(chalk.gray(' Kullanım: natureco backup [create|list|restore|verify]\n'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createBackup() {
|
|
23
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
24
|
+
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
27
|
+
const backupFile = path.join(backupDir, `natureco-backup-${timestamp}.tar.gz`);
|
|
28
|
+
|
|
29
|
+
console.log(chalk.cyan('\n 💾 Creating backup...\n'));
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(NATURECO_DIR)) {
|
|
32
|
+
try {
|
|
33
|
+
execSync(`tar -czf "${backupFile}" -C "${path.dirname(NATURECO_DIR)}" "${path.basename(NATURECO_DIR)}"`, {
|
|
34
|
+
stdio: 'pipe',
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
timeout: 30000
|
|
37
|
+
});
|
|
38
|
+
const size = fs.statSync(backupFile).size;
|
|
39
|
+
console.log(chalk.green(` ✅ Backup created: ${backupFile}`));
|
|
40
|
+
console.log(chalk.gray(` Size: ${(size / 1024).toFixed(1)} KB`));
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.log(chalk.yellow(' ⚠️ tar backup failed, trying copy...'));
|
|
43
|
+
const fallbackFile = backupFile.replace('.tar.gz', '.json');
|
|
44
|
+
const config = require('../utils/config').getConfig();
|
|
45
|
+
fs.writeFileSync(fallbackFile, JSON.stringify(config, null, 2));
|
|
46
|
+
console.log(chalk.green(` ✅ Config backup: ${fallbackFile}`));
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
console.log(chalk.yellow(' ⚠️ No NatureCo directory found\n'));
|
|
50
|
+
}
|
|
51
|
+
console.log();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function listBackups() {
|
|
55
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
56
|
+
console.log(chalk.cyan('\n 📋 Backups\n'));
|
|
57
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(backupDir)) {
|
|
60
|
+
console.log(chalk.gray(' No backups found.\n'));
|
|
61
|
+
console.log(chalk.gray(' Create one: ') + chalk.cyan('natureco backup create\n'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const files = fs.readdirSync(backupDir).filter(f => f.startsWith('natureco-backup'));
|
|
66
|
+
if (files.length === 0) {
|
|
67
|
+
console.log(chalk.gray(' No backups found.\n'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const f of files.sort().reverse()) {
|
|
72
|
+
const stat = fs.statSync(path.join(backupDir, f));
|
|
73
|
+
const size = (stat.size / 1024).toFixed(1);
|
|
74
|
+
const date = stat.birthtime.toLocaleString();
|
|
75
|
+
console.log(` ${chalk.cyan('●')} ${chalk.white(f)} ${chalk.gray(`(${size} KB, ${date})`)}`);
|
|
76
|
+
}
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function restoreBackup(file) {
|
|
81
|
+
if (!file) {
|
|
82
|
+
console.log(chalk.red('\n ❌ Backup file gerekli\n'));
|
|
83
|
+
console.log(chalk.cyan(' natureco backup list'));
|
|
84
|
+
console.log(chalk.cyan(' natureco backup restore <filename>\n'));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
89
|
+
const backupFile = path.join(backupDir, file);
|
|
90
|
+
|
|
91
|
+
if (!fs.existsSync(backupFile)) {
|
|
92
|
+
console.log(chalk.red(`\n ❌ Backup bulunamadı: ${backupFile}\n`));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(chalk.yellow(`\n ⚠️ Restoring ${file}...\n`));
|
|
97
|
+
try {
|
|
98
|
+
execSync(`tar -xzf "${backupFile}" -C "${os.homedir()}"`, { stdio: 'pipe', timeout: 15000 });
|
|
99
|
+
console.log(chalk.green(' ✅ Restore complete\n'));
|
|
100
|
+
} catch {
|
|
101
|
+
console.log(chalk.red(' ❌ Restore failed\n'));
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function verifyBackup(file) {
|
|
107
|
+
if (!file) {
|
|
108
|
+
console.log(chalk.red('\n ❌ Backup file gerekli\n'));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
113
|
+
const backupFile = path.join(backupDir, file);
|
|
114
|
+
|
|
115
|
+
if (!fs.existsSync(backupFile)) {
|
|
116
|
+
console.log(chalk.red(`\n ❌ Backup bulunamadı: ${backupFile}\n`));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const stat = fs.statSync(backupFile);
|
|
121
|
+
console.log(chalk.green(`\n ✅ Backup verified: ${file} (${(stat.size / 1024).toFixed(1)} KB)\n`));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = backup;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
|
+
const dns = require('dns');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function discoverGateway() {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
const interfaces = os.networkInterfaces();
|
|
9
|
+
let gateway = null;
|
|
10
|
+
|
|
11
|
+
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
12
|
+
if (!addrs) continue;
|
|
13
|
+
for (const addr of addrs) {
|
|
14
|
+
if (addr.family === 'IPv4' && !addr.internal) {
|
|
15
|
+
// Try common gateway addresses
|
|
16
|
+
const parts = addr.address.split('.');
|
|
17
|
+
for (const gw of [
|
|
18
|
+
`${parts[0]}.${parts[1]}.${parts[2]}.1`,
|
|
19
|
+
`${parts[0]}.${parts[1]}.${parts[2]}.254`
|
|
20
|
+
]) {
|
|
21
|
+
const sock = new (require('net').Socket)();
|
|
22
|
+
sock.setTimeout(500);
|
|
23
|
+
sock.on('connect', () => { sock.destroy(); if (!gateway) gateway = gw; });
|
|
24
|
+
sock.on('error', () => {});
|
|
25
|
+
sock.on('timeout', () => sock.destroy());
|
|
26
|
+
sock.connect(80, gw);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setTimeout(() => resolve(gateway), 1000);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function bonjour(args) {
|
|
37
|
+
const [action, ...params] = (args || []);
|
|
38
|
+
|
|
39
|
+
if (!action || action === 'scan') return scanNetwork();
|
|
40
|
+
if (action === 'discover') return discoverServices();
|
|
41
|
+
if (action === 'status') return statusBonjour();
|
|
42
|
+
|
|
43
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
44
|
+
console.log(chalk.gray(' Kullanım: natureco bonjour [scan|discover|status]\n'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function scanNetwork() {
|
|
49
|
+
console.log(chalk.cyan('\n Ağ taranıyor...\n'));
|
|
50
|
+
|
|
51
|
+
const interfaces = os.networkInterfaces();
|
|
52
|
+
const found = [];
|
|
53
|
+
|
|
54
|
+
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
55
|
+
if (!addrs) continue;
|
|
56
|
+
for (const addr of addrs) {
|
|
57
|
+
if (addr.family === 'IPv4' && !addr.internal) {
|
|
58
|
+
found.push({
|
|
59
|
+
interface: name,
|
|
60
|
+
address: addr.address,
|
|
61
|
+
netmask: addr.netmask,
|
|
62
|
+
mac: addr.mac
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (found.length === 0) {
|
|
69
|
+
console.log(chalk.gray(' Ağ arayüzü bulunamadı.\n'));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const gateway = await discoverGateway();
|
|
74
|
+
|
|
75
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
76
|
+
console.log(chalk.cyan.bold('\n Ağ Arayüzleri\n'));
|
|
77
|
+
|
|
78
|
+
found.forEach(f => {
|
|
79
|
+
console.log(chalk.white(` ${f.interface}`));
|
|
80
|
+
console.log(chalk.gray(` IP: ${f.address}`));
|
|
81
|
+
console.log(chalk.gray(` MAC: ${f.mac}`));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (gateway) {
|
|
85
|
+
console.log(chalk.gray('\n Varsayılan ağ geçidi: ') + chalk.cyan(gateway));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(chalk.gray('\n Service discovery için: ') + chalk.cyan('natureco bonjour discover\n'));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function discoverServices() {
|
|
92
|
+
console.log(chalk.cyan('\n Servis keşfi başlatılıyor...\n'));
|
|
93
|
+
|
|
94
|
+
// Try common ports
|
|
95
|
+
const commonServices = [
|
|
96
|
+
{ name: 'HTTP', port: 80 },
|
|
97
|
+
{ name: 'HTTPS', port: 443 },
|
|
98
|
+
{ name: 'SSH', port: 22 },
|
|
99
|
+
{ name: 'NatureCo Gateway', port: 3848 },
|
|
100
|
+
{ name: 'Dashboard', port: 3849 },
|
|
101
|
+
{ name: 'OpenClaw', port: 3000 },
|
|
102
|
+
{ name: 'MCP', port: 3100 }
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const config = getConfig();
|
|
106
|
+
const additionalPorts = config.discoveryPorts || [];
|
|
107
|
+
const allServices = [...commonServices, ...additionalPorts.map(p => ({ name: `Port ${p}`, port: p }))];
|
|
108
|
+
|
|
109
|
+
const interfaces = os.networkInterfaces();
|
|
110
|
+
const results = [];
|
|
111
|
+
|
|
112
|
+
for (const [, addrs] of Object.entries(interfaces)) {
|
|
113
|
+
if (!addrs) continue;
|
|
114
|
+
for (const addr of addrs) {
|
|
115
|
+
if (addr.family === 'IPv4' && !addr.internal) {
|
|
116
|
+
const base = addr.address.split('.').slice(0, 3).join('.');
|
|
117
|
+
for (let i = 1; i <= 5; i++) {
|
|
118
|
+
const host = `${base}.${i}`;
|
|
119
|
+
for (const svc of allServices) {
|
|
120
|
+
try {
|
|
121
|
+
await new Promise((resolve, reject) => {
|
|
122
|
+
const sock = new (require('net').Socket)();
|
|
123
|
+
sock.setTimeout(200);
|
|
124
|
+
sock.on('connect', () => {
|
|
125
|
+
sock.destroy();
|
|
126
|
+
results.push({ host, port: svc.port, service: svc.name });
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
sock.on('error', () => reject());
|
|
130
|
+
sock.on('timeout', () => reject());
|
|
131
|
+
sock.connect(svc.port, host);
|
|
132
|
+
});
|
|
133
|
+
} catch {}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (results.length === 0) {
|
|
141
|
+
console.log(chalk.gray(' Servis bulunamadı.\n'));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
146
|
+
console.log(chalk.cyan.bold('\n Bulunan Servisler\n'));
|
|
147
|
+
|
|
148
|
+
results.forEach(r => {
|
|
149
|
+
console.log(` ${chalk.green('●')} ${chalk.white(r.service)} ${chalk.gray(`→ ${r.host}:${r.port}`)}`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
console.log(chalk.gray('\n Özel port eklemek: ') + chalk.cyan('natureco config set discoveryPorts [3000,4000]\n'));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function statusBonjour() {
|
|
156
|
+
console.log(chalk.gray('\n Bonjour/mDNS Servis Keşfi\n'));
|
|
157
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
158
|
+
console.log(chalk.gray(' Ağ keşif aracı — NatureCo servislerini ve gateway\'i bulur.'));
|
|
159
|
+
console.log(chalk.gray(' Komutlar:'));
|
|
160
|
+
console.log(chalk.cyan(' scan ') + chalk.gray('Ağ arayüzlerini ve IP\'leri listele'));
|
|
161
|
+
console.log(chalk.cyan(' discover ') + chalk.gray('Yerel ağda NatureCo servislerini ara'));
|
|
162
|
+
console.log(chalk.gray('\n Port yapılandırması:'));
|
|
163
|
+
console.log(chalk.gray(' Varsayılan: 3848 (Gateway), 3849 (Dashboard)'));
|
|
164
|
+
console.log(chalk.gray(' Özel: ') + chalk.cyan('natureco config set discoveryPorts [3000,4000]\n'));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = bonjour;
|