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.
Files changed (96) hide show
  1. package/README.md +94 -11
  2. package/bin/natureco.js +470 -10
  3. package/package.json +10 -6
  4. package/src/commands/admin-rpc.js +219 -0
  5. package/src/commands/agent.js +89 -0
  6. package/src/commands/approvals.js +53 -0
  7. package/src/commands/backup.js +124 -0
  8. package/src/commands/bonjour.js +167 -0
  9. package/src/commands/capability.js +64 -0
  10. package/src/commands/channels.js +94 -4
  11. package/src/commands/chat.js +11 -25
  12. package/src/commands/clickclack.js +130 -0
  13. package/src/commands/commitments.js +32 -0
  14. package/src/commands/completion.js +76 -0
  15. package/src/commands/config.js +111 -68
  16. package/src/commands/configure.js +93 -0
  17. package/src/commands/crestodian.js +92 -0
  18. package/src/commands/daemon.js +60 -0
  19. package/src/commands/device-pair.js +248 -0
  20. package/src/commands/devices.js +110 -0
  21. package/src/commands/directory.js +47 -0
  22. package/src/commands/dns.js +58 -0
  23. package/src/commands/docs.js +43 -0
  24. package/src/commands/doctor.js +121 -16
  25. package/src/commands/exec-policy.js +71 -0
  26. package/src/commands/gateway-server.js +1175 -30
  27. package/src/commands/gateway.js +11 -20
  28. package/src/commands/health.js +18 -0
  29. package/src/commands/help.js +6 -0
  30. package/src/commands/imessage.js +169 -0
  31. package/src/commands/infer.js +73 -0
  32. package/src/commands/irc.js +119 -0
  33. package/src/commands/mattermost.js +164 -0
  34. package/src/commands/memory-cmd.js +134 -1
  35. package/src/commands/message.js +30 -4
  36. package/src/commands/migrate.js +213 -2
  37. package/src/commands/models.js +584 -216
  38. package/src/commands/node.js +98 -0
  39. package/src/commands/nodes.js +106 -0
  40. package/src/commands/oc-path.js +200 -0
  41. package/src/commands/onboard.js +70 -0
  42. package/src/commands/open-prose.js +67 -0
  43. package/src/commands/plugins.js +415 -172
  44. package/src/commands/policy.js +176 -0
  45. package/src/commands/proxy.js +155 -0
  46. package/src/commands/qr.js +28 -0
  47. package/src/commands/sandbox.js +125 -0
  48. package/src/commands/secrets.js +118 -0
  49. package/src/commands/security.js +149 -1
  50. package/src/commands/setup.js +114 -10
  51. package/src/commands/signal.js +495 -0
  52. package/src/commands/skills.js +20 -29
  53. package/src/commands/sms.js +168 -0
  54. package/src/commands/system.js +53 -0
  55. package/src/commands/tasks.js +328 -79
  56. package/src/commands/terminal.js +21 -0
  57. package/src/commands/thread-ownership.js +157 -0
  58. package/src/commands/transcripts.js +72 -0
  59. package/src/commands/voice.js +82 -0
  60. package/src/commands/vydra.js +98 -0
  61. package/src/commands/webhooks.js +79 -0
  62. package/src/commands/whatsapp.js +7 -21
  63. package/src/commands/workboard.js +207 -0
  64. package/src/tools/audio_understanding.js +154 -0
  65. package/src/tools/bash.js +63 -29
  66. package/src/tools/browser.js +112 -0
  67. package/src/tools/canvas.js +104 -0
  68. package/src/tools/document_extract.js +84 -0
  69. package/src/tools/duckduckgo.js +54 -0
  70. package/src/tools/exa_search.js +66 -0
  71. package/src/tools/firecrawl.js +104 -0
  72. package/src/tools/image_generation.js +99 -0
  73. package/src/tools/llm_task.js +118 -0
  74. package/src/tools/media_understanding.js +128 -0
  75. package/src/tools/music_generation.js +113 -0
  76. package/src/tools/parallel_search.js +77 -0
  77. package/src/tools/phone_control.js +80 -0
  78. package/src/tools/phone_control_enhanced.js +184 -0
  79. package/src/tools/searxng.js +61 -0
  80. package/src/tools/speech_to_text.js +135 -0
  81. package/src/tools/text_to_speech.js +105 -0
  82. package/src/tools/thread_ownership.js +88 -0
  83. package/src/tools/video_generation.js +72 -0
  84. package/src/tools/web_readability.js +104 -0
  85. package/src/utils/api.js +3 -20
  86. package/src/utils/approvals.js +297 -0
  87. package/src/utils/background.js +223 -66
  88. package/src/utils/baileys.js +21 -0
  89. package/src/utils/config.js +141 -10
  90. package/src/utils/errors.js +148 -0
  91. package/src/utils/inquirer-wrapper.js +1 -2
  92. package/src/utils/memory.js +200 -0
  93. package/src/utils/path-utils.js +13 -13
  94. package/src/utils/plugin-registry.js +238 -0
  95. package/src/utils/secrets.js +177 -0
  96. package/src/utils/skills.js +10 -23
@@ -0,0 +1,176 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { getConfig, saveConfig } = require('../utils/config');
6
+
7
+ function policy(args) {
8
+ const [action, ...params] = (args || []);
9
+
10
+ if (!action || action === 'check') return checkPolicy();
11
+ if (action === 'set') return setPolicy(params[0], params.slice(1).join(' '));
12
+ if (action === 'list') return listPolicies();
13
+ if (action === 'remove') return removePolicy(params[0]);
14
+
15
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
16
+ console.log(chalk.gray(' KullanΔ±m: natureco policy [check|set|list|remove]\n'));
17
+ process.exit(1);
18
+ }
19
+
20
+ const POLICY_CHECKS = [
21
+ {
22
+ id: 'node-version',
23
+ name: 'Node.js Versiyonu',
24
+ check: () => {
25
+ const v = process.version.slice(1).split('.')[0];
26
+ return parseInt(v) >= 18
27
+ ? { status: 'pass', message: `Node.js ${process.version}` }
28
+ : { status: 'fail', message: `Node.js ${process.version} (18+ gerekli)`, fix: 'Node.js gΓΌncelleyin' };
29
+ }
30
+ },
31
+ {
32
+ id: 'config-exists',
33
+ name: 'Config DosyasΔ±',
34
+ check: () => {
35
+ const configFile = path.join(os.homedir(), '.natureco', 'config.json');
36
+ if (!fs.existsSync(configFile)) {
37
+ return { status: 'fail', message: 'config.json bulunamadı', fix: 'natureco setup çalıştırın' };
38
+ }
39
+ try {
40
+ JSON.parse(fs.readFileSync(configFile, 'utf-8'));
41
+ return { status: 'pass', message: 'Config geΓ§erli JSON' };
42
+ } catch {
43
+ return { status: 'fail', message: 'Config bozuk JSON', fix: '~/.natureco/config.json dΓΌzeltin' };
44
+ }
45
+ }
46
+ },
47
+ {
48
+ id: 'api-key',
49
+ name: 'API Key',
50
+ check: () => {
51
+ const config = getConfig();
52
+ if (config.providerApiKey || config.apiKey || process.env.GROQ_API_KEY) {
53
+ return { status: 'pass', message: 'API key mevcut' };
54
+ }
55
+ return { status: 'warn', message: 'API key eksik', fix: 'natureco login veya GROQ_API_KEY env' };
56
+ }
57
+ },
58
+ {
59
+ id: 'provider-url',
60
+ name: 'Provider URL',
61
+ check: () => {
62
+ const config = getConfig();
63
+ if (config.providerUrl) {
64
+ return { status: 'pass', message: config.providerUrl };
65
+ }
66
+ return { status: 'warn', message: 'Provider ayarlanmamış', fix: 'natureco setup' };
67
+ }
68
+ },
69
+ {
70
+ id: 'git-config',
71
+ name: 'Git YapΔ±landΔ±rmasΔ±',
72
+ check: () => {
73
+ try {
74
+ const { execSync } = require('child_process');
75
+ const name = execSync('git config user.name', { encoding: 'utf-8', stdio: 'pipe' }).trim();
76
+ const email = execSync('git config user.email', { encoding: 'utf-8', stdio: 'pipe' }).trim();
77
+ if (name && email) return { status: 'pass', message: `${name} <${email}>` };
78
+ return { status: 'warn', message: 'Git user.name/email eksik', fix: 'git config --global user.name "AdΔ±nΔ±z"' };
79
+ } catch {
80
+ return { status: 'warn', message: 'Git repo değil', fix: 'git init' };
81
+ }
82
+ }
83
+ },
84
+ {
85
+ id: 'disk-space',
86
+ name: 'Disk AlanΔ±',
87
+ check: () => {
88
+ try {
89
+ const drive = path.parse(os.homedir()).root.replace(':', '');
90
+ const { execSync } = require('child_process');
91
+ const output = execSync(`powershell -Command "Get-PSDrive -Name ${drive} | Select-Object -ExpandProperty Free"`, { encoding: 'utf-8' }).trim();
92
+ const free = parseInt(output);
93
+ if (isNaN(free)) return { status: 'pass', message: 'Kontrol edilemedi' };
94
+ const freeGB = free / 1e9;
95
+ if (freeGB < 0.5) return { status: 'fail', message: `Sadece ${freeGB.toFixed(1)}GB boş`, fix: 'Disk temizliği yapın' };
96
+ return { status: 'pass', message: `${freeGB.toFixed(1)}GB boş alan` };
97
+ } catch {
98
+ return { status: 'pass', message: 'Kontrol edilemedi' };
99
+ }
100
+ }
101
+ }
102
+ ];
103
+
104
+ function checkPolicy() {
105
+ console.log(chalk.cyan.bold('\n Workspace Uyumluluk PolitikasΔ±\n'));
106
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
107
+
108
+ let passed = 0;
109
+ let failed = 0;
110
+ let warnings = 0;
111
+
112
+ for (const check of POLICY_CHECKS) {
113
+ const result = check.check();
114
+ if (result.status === 'pass') {
115
+ console.log(` ${chalk.green('βœ“')} ${check.name}: ${chalk.white(result.message)}`);
116
+ passed++;
117
+ } else if (result.status === 'fail') {
118
+ console.log(` ${chalk.red('βœ—')} ${check.name}: ${chalk.white(result.message)}`);
119
+ console.log(chalk.gray(` DΓΌzeltme: ${result.fix}`));
120
+ failed++;
121
+ } else {
122
+ console.log(` ${chalk.yellow('⚠')} ${check.name}: ${chalk.white(result.message)}`);
123
+ if (result.fix) console.log(chalk.gray(` Γ–neri: ${result.fix}`));
124
+ warnings++;
125
+ }
126
+ }
127
+
128
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
129
+ console.log(chalk.gray(` GeΓ§ti: ${passed} | UyarΔ±: ${warnings} | Hata: ${failed}\n`));
130
+ }
131
+
132
+ function setPolicy(key, value) {
133
+ if (!key) {
134
+ console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
135
+ return;
136
+ }
137
+ const config = getConfig();
138
+ if (!config.policies) config.policies = {};
139
+ config.policies[key] = value;
140
+ saveConfig(config);
141
+ console.log(chalk.green(`\n βœ“ Politika ayarlandΔ±: ${key} = ${value}\n`));
142
+ }
143
+
144
+ function listPolicies() {
145
+ const config = getConfig();
146
+ const policies = config.policies || {};
147
+
148
+ if (Object.keys(policies).length === 0) {
149
+ console.log(chalk.gray('\n TanΔ±mlΔ± politika yok.\n'));
150
+ return;
151
+ }
152
+
153
+ console.log(chalk.cyan.bold('\n TanΔ±mlΔ± Politikalar\n'));
154
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
155
+ for (const [key, value] of Object.entries(policies)) {
156
+ console.log(` ${chalk.white(key)}: ${chalk.cyan(value)}`);
157
+ }
158
+ console.log('');
159
+ }
160
+
161
+ function removePolicy(key) {
162
+ if (!key) {
163
+ console.log(chalk.red('\n ❌ Politika adı gerekli\n'));
164
+ return;
165
+ }
166
+ const config = getConfig();
167
+ if (config.policies?.[key]) {
168
+ delete config.policies[key];
169
+ saveConfig(config);
170
+ console.log(chalk.green(`\n βœ“ Politika silindi: ${key}\n`));
171
+ } else {
172
+ console.log(chalk.yellow(`\n ⚠ Politika bulunamadı: ${key}\n`));
173
+ }
174
+ }
175
+
176
+ module.exports = policy;
@@ -0,0 +1,155 @@
1
+ const chalk = require('chalk');
2
+ const http = require('http');
3
+ const https = require('https');
4
+ const { URL } = require('url');
5
+
6
+ let proxyInstance = null;
7
+ let captured = [];
8
+ let forwardUrl = null;
9
+
10
+ function proxy(args) {
11
+ const [action, ...params] = args || [];
12
+
13
+ if (!action || action === 'status') return statusProxy();
14
+ if (action === 'start') return startProxy(params);
15
+ if (action === 'stop') return stopProxy();
16
+ if (action === 'capture') return showCapture();
17
+ if (action === 'clear') return clearCapture();
18
+
19
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
20
+ console.log(chalk.gray(' KullanΔ±m: natureco proxy [status|start|stop|capture|clear]\n'));
21
+ process.exit(1);
22
+ }
23
+
24
+ function statusProxy() {
25
+ console.log(chalk.cyan('\n πŸ” Debug Proxy\n'));
26
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
27
+ console.log(` ${chalk.white('Status:')} ${proxyInstance ? chalk.green('Running') : chalk.red('Stopped')}`);
28
+ if (proxyInstance) {
29
+ console.log(` ${chalk.white('Port:')} ${proxyInstance.port}`);
30
+ console.log(` ${chalk.white('Forward:')} ${forwardUrl ? chalk.cyan(forwardUrl) : chalk.gray('(none)')}`);
31
+ console.log(` ${chalk.white('Captured:')} ${captured.length} request(s)`);
32
+ }
33
+ console.log(chalk.gray('\n Examples:'));
34
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start'));
35
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start 9090'));
36
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy start 8080 --forward http://localhost:3000'));
37
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy capture'));
38
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy clear'));
39
+ console.log(chalk.gray(' ') + chalk.cyan('natureco proxy stop'));
40
+ console.log();
41
+ }
42
+
43
+ function startProxy(params) {
44
+ if (proxyInstance) {
45
+ console.log(chalk.yellow('\n ⚠️ Proxy already running\n'));
46
+ return;
47
+ }
48
+
49
+ const port = parseInt(params[0], 10) || 8080;
50
+ const fwdIdx = params.indexOf('--forward');
51
+ if (fwdIdx !== -1 && params[fwdIdx + 1]) {
52
+ forwardUrl = params[fwdIdx + 1];
53
+ }
54
+
55
+ captured = [];
56
+
57
+ const server = http.createServer((req, res) => {
58
+ const chunks = [];
59
+ req.on('data', chunk => chunks.push(chunk));
60
+ req.on('end', () => {
61
+ const body = Buffer.concat(chunks).toString();
62
+ const entry = {
63
+ id: captured.length + 1,
64
+ timestamp: new Date().toISOString(),
65
+ method: req.method,
66
+ url: req.url,
67
+ headers: req.headers,
68
+ body: body ? body.substring(0, 2000) : null
69
+ };
70
+ captured.push(entry);
71
+ if (captured.length > 200) captured.shift();
72
+
73
+ console.log(chalk.gray(` [${entry.id}] ${chalk.cyan(req.method)} ${req.url}`));
74
+
75
+ if (forwardUrl) {
76
+ try {
77
+ const target = new URL(req.url, forwardUrl);
78
+ const proxyReq = http.request({
79
+ hostname: target.hostname,
80
+ port: target.port || 80,
81
+ path: target.pathname + target.search,
82
+ method: req.method,
83
+ headers: { ...req.headers, host: target.host }
84
+ }, proxyRes => {
85
+ let proxyBody = '';
86
+ proxyRes.on('data', c => proxyBody += c);
87
+ proxyRes.on('end', () => {
88
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
89
+ res.end(proxyBody);
90
+ });
91
+ });
92
+ proxyReq.on('error', () => {
93
+ res.writeHead(502);
94
+ res.end('Bad Gateway');
95
+ });
96
+ if (body) proxyReq.write(body);
97
+ proxyReq.end();
98
+ } catch {
99
+ res.writeHead(502);
100
+ res.end('Bad Gateway');
101
+ }
102
+ } else {
103
+ res.writeHead(200, { 'Content-Type': 'application/json' });
104
+ res.end(JSON.stringify({ ok: true, id: entry.id, captured: captured.length }));
105
+ }
106
+ });
107
+ });
108
+
109
+ proxyInstance = server;
110
+ proxyInstance.port = port;
111
+ server.listen(port, () => {
112
+ console.log(chalk.green(`\n πŸ” Debug proxy on http://localhost:${port}\n`));
113
+ if (forwardUrl) console.log(chalk.gray(` Forwarding to: ${forwardUrl}\n`));
114
+ console.log(chalk.gray(' Captured requests shown below. Press Ctrl+C to stop.\n'));
115
+ });
116
+ }
117
+
118
+ function stopProxy() {
119
+ if (!proxyInstance) {
120
+ console.log(chalk.yellow('\n ⚠️ Proxy not running\n'));
121
+ return;
122
+ }
123
+ proxyInstance.close(() => {
124
+ console.log(chalk.gray('\n πŸ›‘ Proxy stopped\n'));
125
+ proxyInstance = null;
126
+ forwardUrl = null;
127
+ });
128
+ }
129
+
130
+ function showCapture() {
131
+ if (captured.length === 0) {
132
+ console.log(chalk.gray('\n No captured requests.\n'));
133
+ return;
134
+ }
135
+
136
+ console.log(chalk.cyan(`\n πŸ“‹ Captured Requests (${captured.length})\n`));
137
+ console.log(chalk.gray(' ' + '─'.repeat(64)));
138
+
139
+ for (const entry of captured.slice(-20)) {
140
+ const time = entry.timestamp.slice(11, 19);
141
+ console.log(` ${chalk.gray(`[${entry.id}]`)} ${chalk.cyan(entry.method)} ${chalk.white(entry.url)} ${chalk.gray(time)}`);
142
+ if (entry.body) {
143
+ const preview = entry.body.length > 200 ? entry.body.substring(0, 200) + '…' : entry.body;
144
+ console.log(` ${chalk.gray(preview)}`);
145
+ }
146
+ }
147
+ console.log();
148
+ }
149
+
150
+ function clearCapture() {
151
+ captured = [];
152
+ console.log(chalk.gray('\n πŸ—‘οΈ Captured requests cleared\n'));
153
+ }
154
+
155
+ module.exports = proxy;
@@ -0,0 +1,28 @@
1
+ const chalk = require('chalk');
2
+ const crypto = require('crypto');
3
+
4
+ function qr(args) {
5
+ const data = args.join(' ') || generatePairingData();
6
+
7
+ console.log(chalk.cyan('\n πŸ“± QR Pairing Code\n'));
8
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
9
+
10
+ const code = crypto.randomBytes(4).toString('hex').toUpperCase();
11
+ const expiresAt = new Date(Date.now() + 15 * 60 * 1000);
12
+
13
+ console.log(` ${chalk.white('Pairing Code:')} ${chalk.bold.yellow(code)}`);
14
+ console.log(` ${chalk.white('Expires:')} ${chalk.gray(expiresAt.toLocaleString())}`);
15
+ console.log();
16
+ console.log(chalk.gray(' To pair a device, run on the device:'));
17
+ console.log(chalk.cyan(' natureco device-pair verify ') + chalk.yellow(code));
18
+ console.log();
19
+ console.log(chalk.gray(' Or scan with the NatureCo mobile app.'));
20
+ console.log();
21
+ }
22
+
23
+ function generatePairingData() {
24
+ const id = crypto.randomBytes(8).toString('hex');
25
+ return JSON.stringify({ id, timestamp: Date.now() });
26
+ }
27
+
28
+ module.exports = qr;
@@ -0,0 +1,125 @@
1
+ const chalk = require('chalk');
2
+ const { execSync, spawn } = require('child_process');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const SANDBOX_DIR = path.join(os.tmpdir(), 'natureco-sandboxes');
8
+
9
+ function sandbox(args) {
10
+ const [action, ...params] = args || [];
11
+
12
+ if (!action || action === 'list') return listSandboxes();
13
+ if (action === 'create') return createSandbox(params[0]);
14
+ if (action === 'destroy') return destroySandbox(params[0]);
15
+ if (action === 'exec') return execSandbox(params[0], params.slice(1).join(' '));
16
+
17
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
18
+ console.log(chalk.gray(' KullanΔ±m: natureco sandbox [list|create|destroy|exec]\n'));
19
+ process.exit(1);
20
+ }
21
+
22
+ function getDirSandboxes() {
23
+ if (!fs.existsSync(SANDBOX_DIR)) return [];
24
+ return fs.readdirSync(SANDBOX_DIR).filter(name => {
25
+ const stat = fs.statSync(path.join(SANDBOX_DIR, name));
26
+ return stat.isDirectory();
27
+ });
28
+ }
29
+
30
+ function listSandboxes() {
31
+ console.log(chalk.cyan('\n πŸ“¦ Sandbox Containers\n'));
32
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
33
+
34
+ // Dir-based sandboxes
35
+ const dirSandboxes = getDirSandboxes();
36
+ if (dirSandboxes.length > 0) {
37
+ for (const name of dirSandboxes) {
38
+ const dir = path.join(SANDBOX_DIR, name);
39
+ const files = fs.readdirSync(dir).length;
40
+ const created = fs.statSync(dir).birthtime;
41
+ console.log(` ${chalk.green('●')} ${chalk.white(name)} ${chalk.gray(`(${files} file(s), ${created.toISOString().slice(0, 10)})`)}`);
42
+ }
43
+ }
44
+
45
+ // Docker sandboxes
46
+ try {
47
+ const dockerOut = execSync('docker ps --filter "name=natureco-sandbox" --format "{{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Names}}" 2>nul', { encoding: 'utf8', timeout: 5000, stdio: 'pipe' }).trim();
48
+ if (dockerOut) {
49
+ for (const line of dockerOut.split('\n')) {
50
+ const [id, image, status, name] = line.split('\t');
51
+ console.log(` ${chalk.blue('●')} ${chalk.white(name || id)} ${chalk.gray(`${image} β€” ${status}`)}`);
52
+ }
53
+ }
54
+ } catch {}
55
+
56
+ if (dirSandboxes.length === 0) {
57
+ console.log(chalk.gray(' No sandboxes found.\n'));
58
+ console.log(chalk.gray(' Create one:') + chalk.cyan(' natureco sandbox create [name]\n'));
59
+ return;
60
+ }
61
+ console.log();
62
+ }
63
+
64
+ function createSandbox(name) {
65
+ const sandboxName = name || `sandbox-${Date.now()}`;
66
+ const dir = path.join(SANDBOX_DIR, sandboxName);
67
+
68
+ if (fs.existsSync(dir)) {
69
+ console.log(chalk.red(`\n ❌ Sandbox '${sandboxName}' already exists\n`));
70
+ process.exit(1);
71
+ }
72
+
73
+ fs.mkdirSync(dir, { recursive: true });
74
+ fs.writeFileSync(path.join(dir, '.natureco-sandbox'), JSON.stringify({ created: new Date().toISOString(), name: sandboxName }));
75
+
76
+ console.log(chalk.green(`\n βœ… Sandbox created: ${sandboxName}\n`));
77
+ console.log(chalk.gray(` Directory: ${dir}\n`));
78
+ console.log(chalk.gray(' Usage:') + chalk.cyan(` natureco sandbox exec ${sandboxName} "node -e 'console.log(\\"hello\\")'"`) + '\n');
79
+ }
80
+
81
+ function destroySandbox(name) {
82
+ if (!name) {
83
+ console.log(chalk.red('\n ❌ Sandbox name gerekli\n'));
84
+ process.exit(1);
85
+ }
86
+
87
+ const dir = path.join(SANDBOX_DIR, name);
88
+ if (fs.existsSync(dir)) {
89
+ fs.rmSync(dir, { recursive: true, force: true });
90
+ console.log(chalk.gray(` πŸ—‘οΈ Dir sandbox destroyed: ${name}\n`));
91
+ }
92
+
93
+ try {
94
+ execSync(`docker rm -f ${name} 2>nul`, { stdio: 'pipe', timeout: 10000 });
95
+ console.log(chalk.gray(` πŸ—‘οΈ Docker sandbox destroyed: ${name}\n`));
96
+ } catch {}
97
+ }
98
+
99
+ function execSandbox(name, command) {
100
+ if (!name || !command) {
101
+ console.log(chalk.red('\n ❌ Sandbox name ve command gerekli\n'));
102
+ console.log(chalk.gray(' KullanΔ±m: natureco sandbox exec <name> <command>\n'));
103
+ process.exit(1);
104
+ }
105
+
106
+ const dir = path.join(SANDBOX_DIR, name);
107
+ if (!fs.existsSync(dir)) {
108
+ console.log(chalk.red(`\n ❌ Sandbox '${name}' not found\n`));
109
+ console.log(chalk.gray(' Create one:') + chalk.cyan(` natureco sandbox create ${name}`) + '\n');
110
+ process.exit(1);
111
+ }
112
+
113
+ console.log(chalk.cyan(`\n πŸƒ Executing in sandbox '${name}': ${command}\n`));
114
+
115
+ try {
116
+ const result = execSync(command, { cwd: dir, encoding: 'utf8', timeout: 30000, stdio: 'inherit' });
117
+ return result;
118
+ } catch (err) {
119
+ if (err.status !== undefined) process.exit(err.status);
120
+ console.log(chalk.red(` ❌ ${err.message}\n`));
121
+ process.exit(1);
122
+ }
123
+ }
124
+
125
+ module.exports = sandbox;
@@ -0,0 +1,118 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, saveConfig } = require('../utils/config');
3
+
4
+ function secrets(args) {
5
+ const [action, ...params] = args || [];
6
+
7
+ if (!action || action === 'list') return listSecrets();
8
+ if (action === 'set') return setSecret(params[0], params.slice(1).join(' '));
9
+ if (action === 'get') return getSecret(params[0]);
10
+ if (action === 'unset') return unsetSecret(params[0]);
11
+ if (action === 'audit') return auditSecrets();
12
+
13
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
14
+ console.log(chalk.gray(' KullanΔ±m: natureco secrets [list|set|get|unset|audit]\n'));
15
+ process.exit(1);
16
+ }
17
+
18
+ function listSecrets() {
19
+ const config = getConfig();
20
+ const secretKeys = Object.keys(config).filter(k =>
21
+ k.toLowerCase().includes('key') || k.toLowerCase().includes('token') || k.toLowerCase().includes('secret')
22
+ );
23
+
24
+ console.log(chalk.cyan('\n πŸ” Secrets\n'));
25
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
26
+
27
+ if (secretKeys.length === 0) {
28
+ console.log(chalk.gray(' No secrets stored.\n'));
29
+ return;
30
+ }
31
+
32
+ for (const key of secretKeys.sort()) {
33
+ const val = config[key];
34
+ const masked = val ? val.substring(0, 6) + '…' + val.slice(-4) : '(empty)';
35
+ console.log(` ${chalk.white(key)}: ${chalk.gray(masked)}`);
36
+ }
37
+ console.log();
38
+ }
39
+
40
+ function setSecret(key, value) {
41
+ if (!key || !value) {
42
+ console.log(chalk.red('\n ❌ key ve value gerekli\n'));
43
+ process.exit(1);
44
+ }
45
+
46
+ const config = getConfig();
47
+ config[key] = value;
48
+ saveConfig(config);
49
+ console.log(chalk.green(`\n βœ… Secret set: ${key}\n`));
50
+ }
51
+
52
+ function getSecret(key) {
53
+ if (!key) {
54
+ console.log(chalk.red('\n ❌ key gerekli\n'));
55
+ process.exit(1);
56
+ }
57
+
58
+ const config = getConfig();
59
+ const value = config[key];
60
+
61
+ if (!value) {
62
+ console.log(chalk.yellow(`\n ⚠️ Secret not found: ${key}\n`));
63
+ return;
64
+ }
65
+
66
+ console.log(chalk.cyan(`\n ${key}: ${chalk.white(value)}\n`));
67
+ }
68
+
69
+ function unsetSecret(key) {
70
+ if (!key) {
71
+ console.log(chalk.red('\n ❌ key gerekli\n'));
72
+ process.exit(1);
73
+ }
74
+
75
+ const config = getConfig();
76
+ delete config[key];
77
+ saveConfig(config);
78
+ console.log(chalk.gray(`\n πŸ—‘οΈ Secret removed: ${key}\n`));
79
+ }
80
+
81
+ function auditSecrets() {
82
+ const config = getConfig();
83
+ const secrets = Object.keys(config).filter(k =>
84
+ k.toLowerCase().includes('key') || k.toLowerCase().includes('token') || k.toLowerCase().includes('secret')
85
+ );
86
+
87
+ const envKeys = ['OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'GROQ_API_KEY', 'TAVILY_API_KEY',
88
+ 'ELEVENLABS_API_KEY', 'DEEPGRAM_API_KEY', 'FAL_KEY', 'TOGETHER_API_KEY',
89
+ 'PUSHOVER_TOKEN', 'PUSHOVER_USER', 'NTFY_TOPIC', 'NTFY_SERVER',
90
+ 'TWILIO_SID', 'TWILIO_TOKEN', 'TWILIO_FROM', 'SUNO_API_KEY', 'UDIO_API_KEY',
91
+ 'VYDRA_API_KEY', 'SLACK_BOT_TOKEN', 'DISCORD_BOT_TOKEN', 'TELEGRAM_BOT_TOKEN',
92
+ 'WHATSAPP_API_KEY'
93
+ ];
94
+
95
+ console.log(chalk.cyan('\n πŸ” Secrets Audit\n'));
96
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
97
+
98
+ console.log(chalk.white('\n Config Secrets:'));
99
+ for (const key of secrets.sort()) {
100
+ const val = config[key];
101
+ const status = val ? chalk.green('set') : chalk.red('empty');
102
+ console.log(` ${chalk.gray('●')} ${key}: ${status}`);
103
+ }
104
+
105
+ console.log(chalk.white('\n Environment Variables:'));
106
+ let found = 0;
107
+ for (const envKey of envKeys) {
108
+ if (process.env[envKey]) {
109
+ console.log(` ${chalk.green('●')} ${envKey}: ${chalk.green('set')}`);
110
+ found++;
111
+ }
112
+ }
113
+ if (found === 0) console.log(chalk.gray(' (none set in environment)'));
114
+
115
+ console.log(chalk.gray(`\n Total: ${secrets.length} config + ${found} env\n`));
116
+ }
117
+
118
+ module.exports = secrets;