natureco-cli 2.23.30 → 2.23.32
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 +178 -167
- package/package.json +1 -1
- package/src/commands/acp.js +39 -0
- package/src/commands/admin-rpc.js +83 -0
- package/src/commands/agent.js +214 -23
- package/src/commands/agents.js +114 -30
- package/src/commands/approvals.js +172 -11
- package/src/commands/ask.js +1 -1
- package/src/commands/browser.js +815 -0
- package/src/commands/capability.js +195 -22
- package/src/commands/channels.js +422 -267
- package/src/commands/chat.js +5 -8
- package/src/commands/clawbot.js +19 -0
- package/src/commands/code.js +3 -2
- package/src/commands/commitments.js +125 -9
- package/src/commands/completion.js +40 -32
- package/src/commands/config.js +228 -30
- package/src/commands/configure.js +84 -67
- package/src/commands/cron.js +239 -19
- package/src/commands/daemon.js +34 -4
- package/src/commands/dashboard.js +47 -374
- package/src/commands/devices.js +53 -26
- package/src/commands/directory.js +146 -14
- package/src/commands/dns.js +148 -10
- package/src/commands/docs.js +119 -26
- package/src/commands/doctor.js +143 -492
- package/src/commands/exec-policy.js +57 -48
- package/src/commands/gateway.js +492 -249
- package/src/commands/health.js +141 -11
- package/src/commands/help.js +24 -25
- package/src/commands/hooks.js +141 -87
- package/src/commands/infer.js +1442 -41
- package/src/commands/logs.js +122 -99
- package/src/commands/mcp.js +121 -309
- package/src/commands/memory.js +128 -0
- package/src/commands/message.js +720 -140
- package/src/commands/models.js +39 -1
- package/src/commands/node.js +77 -77
- package/src/commands/nodes.js +278 -22
- package/src/commands/onboard.js +115 -56
- package/src/commands/pairing.js +108 -107
- package/src/commands/path.js +206 -0
- package/src/commands/plugins.js +35 -1
- package/src/commands/proxy.js +159 -8
- package/src/commands/qr.js +55 -13
- package/src/commands/reset.js +101 -94
- package/src/commands/secrets.js +104 -21
- package/src/commands/sessions.js +110 -51
- package/src/commands/setup.js +229 -649
- package/src/commands/skills.js +67 -1
- package/src/commands/status.js +101 -127
- package/src/commands/tasks.js +208 -100
- package/src/commands/terminal.js +130 -12
- package/src/commands/transcripts.js +24 -1
- package/src/commands/tui.js +41 -0
- package/src/commands/uninstall.js +73 -92
- package/src/commands/update.js +146 -91
- package/src/commands/web-fetch.js +34 -0
- package/src/commands/webhooks.js +58 -66
- package/src/commands/wiki.js +783 -0
- package/src/utils/agents-md.js +85 -0
- package/src/utils/api.js +40 -41
- package/src/utils/format.js +144 -0
- package/src/utils/headless.js +2 -1
- package/src/utils/parallel-tools.js +106 -0
- package/src/utils/sub-agent.js +148 -0
- package/src/utils/token-budget.js +304 -0
- package/src/utils/tool-runner.js +7 -5
- package/src/utils/web-fetch.js +107 -0
package/src/commands/gateway.js
CHANGED
|
@@ -1,249 +1,492 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const {
|
|
8
|
-
const {
|
|
9
|
-
const {
|
|
10
|
-
const {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const F = require('../utils/format');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const packageJson = require('../../package.json');
|
|
7
|
+
const { getConfig, CONFIG_FILE } = require('../utils/config');
|
|
8
|
+
const { getSkills } = require('../utils/skills');
|
|
9
|
+
const { getMcpServers } = require('../utils/mcp');
|
|
10
|
+
const { loadBaileys } = require('../utils/baileys');
|
|
11
|
+
const { NatureCoError, GatewayError, handleError } = require('../utils/errors');
|
|
12
|
+
const pino = require('pino');
|
|
13
|
+
const logger = pino({ level: 'silent' });
|
|
14
|
+
|
|
15
|
+
async function gateway(action, ...args) {
|
|
16
|
+
if (action === 'start') {
|
|
17
|
+
return startGateway();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (action === 'call') {
|
|
21
|
+
const method = args[0];
|
|
22
|
+
const params = args.slice(1);
|
|
23
|
+
if (!method) {
|
|
24
|
+
F.error('Method name is required.');
|
|
25
|
+
F.info('Usage: natureco gateway call <method> [params...]');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
F.header('Gateway RPC Call');
|
|
29
|
+
F.kv('Parameters', params.length ? params.join(', ') : '(none)');
|
|
30
|
+
F.kv('Status', 'MOCK — no real gateway running');
|
|
31
|
+
F.kv('Response', '{ ok: true, result: "mock response" }');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (action === 'usage-cost') {
|
|
36
|
+
const config = getConfig();
|
|
37
|
+
const provider = config?.providerUrl?.replace('https://', '').split('/')[0] || 'unknown';
|
|
38
|
+
F.header('Usage Cost');
|
|
39
|
+
F.kv('Provider', provider);
|
|
40
|
+
F.kv('Model', config?.providerModel || 'default');
|
|
41
|
+
F.kv('API Key', config?.apiKey ? `${config.apiKey.slice(0, 8)}...` : 'N/A');
|
|
42
|
+
F.table(['Metric', 'Value'], [
|
|
43
|
+
['Tokens In', '~0 (mock)'],
|
|
44
|
+
['Tokens Out', '~0 (mock)'],
|
|
45
|
+
['Estimated', '$0.00 (mock)'],
|
|
46
|
+
['Status', 'No real gateway running — costs will be tracked once started.'],
|
|
47
|
+
]);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (action === 'probe') {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
F.header('Gateway Health Probe');
|
|
54
|
+
|
|
55
|
+
const configOk = !!config;
|
|
56
|
+
const apiKeyOk = !!(config && config.apiKey);
|
|
57
|
+
const providerUrlOk = !!(config && config.providerUrl);
|
|
58
|
+
|
|
59
|
+
F.table(['Check', 'Status'], [
|
|
60
|
+
['Config File', configOk ? '✓ Found' : '✗ Missing'],
|
|
61
|
+
['API Key', apiKeyOk ? '✓ Set' : '✗ Missing'],
|
|
62
|
+
['Provider URL', providerUrlOk ? `✓ ${config.providerUrl}` : '✗ Missing'],
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
if (apiKeyOk && providerUrlOk) {
|
|
66
|
+
try {
|
|
67
|
+
const https = require('https');
|
|
68
|
+
const url = new URL(config.providerUrl);
|
|
69
|
+
F.kv('Probing', url.href);
|
|
70
|
+
await new Promise((resolve, reject) => {
|
|
71
|
+
const req = https.get(url.href, {
|
|
72
|
+
timeout: 5000,
|
|
73
|
+
headers: { 'Authorization': `Bearer ${config.apiKey}` }
|
|
74
|
+
}, (res) => {
|
|
75
|
+
F.kv('HTTP Status', `${res.statusCode}`);
|
|
76
|
+
F.kv('Reachable', '✓');
|
|
77
|
+
resolve();
|
|
78
|
+
});
|
|
79
|
+
req.on('error', (err) => {
|
|
80
|
+
F.kv('HTTP Status', 'N/A');
|
|
81
|
+
F.kv('Reachable', '✗');
|
|
82
|
+
F.kv('Error', err.message);
|
|
83
|
+
resolve();
|
|
84
|
+
});
|
|
85
|
+
req.on('timeout', () => {
|
|
86
|
+
req.destroy();
|
|
87
|
+
F.kv('HTTP Status', 'Timeout');
|
|
88
|
+
F.kv('Reachable', '✗');
|
|
89
|
+
F.kv('Error', 'Request timed out after 5000ms');
|
|
90
|
+
resolve();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
} catch (err) {
|
|
94
|
+
F.kv('Reachable', '✗');
|
|
95
|
+
F.kv('Error', err.message);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
F.kv('Skipped', 'Missing API key or provider URL');
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (action === 'discover') {
|
|
104
|
+
F.header('LAN Service Discovery');
|
|
105
|
+
F.info('Scanning local network for NatureCo gateways... (mock discovery — no real scan performed)');
|
|
106
|
+
|
|
107
|
+
F.table(['Service', 'Host', 'Port', 'Protocol'], [
|
|
108
|
+
['NatureCo Gateway', '192.168.1.100 (mock)', '4317', 'gRPC'],
|
|
109
|
+
['NatureCo Web UI', '192.168.1.100 (mock)', '8080', 'HTTP'],
|
|
110
|
+
]);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (action === 'install') {
|
|
115
|
+
const platform = os.platform();
|
|
116
|
+
F.header('Install Gateway as System Service');
|
|
117
|
+
F.kv('Platform', platform);
|
|
118
|
+
|
|
119
|
+
if (platform === 'win32') {
|
|
120
|
+
F.section('Windows (NSSM)');
|
|
121
|
+
F.info('To install as a Windows service:');
|
|
122
|
+
console.log(chalk.gray(' nssm install NatureCoGateway "node" "' + path.resolve(__dirname, '../../index.js') + '"'));
|
|
123
|
+
console.log(chalk.gray(' nssm set NatureCoGateway AppParameters "gateway start"'));
|
|
124
|
+
console.log(chalk.gray(' nssm set NatureCoGateway Start SERVICE_AUTO_START'));
|
|
125
|
+
console.log(chalk.gray(' nssm start NatureCoGateway'));
|
|
126
|
+
} else if (platform === 'linux') {
|
|
127
|
+
F.section('Linux (systemd)');
|
|
128
|
+
F.info('Create a systemd unit:');
|
|
129
|
+
console.log(chalk.gray(' [Unit]'));
|
|
130
|
+
console.log(chalk.gray(' Description=NatureCo Gateway'));
|
|
131
|
+
console.log(chalk.gray(' After=network.target'));
|
|
132
|
+
console.log(chalk.gray(''));
|
|
133
|
+
console.log(chalk.gray(' [Service]'));
|
|
134
|
+
console.log(chalk.gray(' ExecStart=' + process.execPath + ' ' + path.resolve(__dirname, '../../index.js') + ' gateway start'));
|
|
135
|
+
console.log(chalk.gray(' Restart=on-failure'));
|
|
136
|
+
console.log(chalk.gray(' RestartSec=5'));
|
|
137
|
+
console.log(chalk.gray(''));
|
|
138
|
+
console.log(chalk.gray(' [Install]'));
|
|
139
|
+
console.log(chalk.gray(' WantedBy=multi-user.target'));
|
|
140
|
+
console.log(chalk.gray(''));
|
|
141
|
+
F.info('Then: sudo systemctl enable natureco-gateway && sudo systemctl start natureco-gateway');
|
|
142
|
+
} else if (platform === 'darwin') {
|
|
143
|
+
F.section('macOS (launchd)');
|
|
144
|
+
F.info('Create a launchd plist:');
|
|
145
|
+
console.log(chalk.gray(' <?xml version="1.0" encoding="UTF-8"?>'));
|
|
146
|
+
console.log(chalk.gray(' <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'));
|
|
147
|
+
console.log(chalk.gray(' <plist version="1.0"><dict>'));
|
|
148
|
+
console.log(chalk.gray(' <key>Label</key><string>com.natureco.gateway</string>'));
|
|
149
|
+
console.log(chalk.gray(' <key>ProgramArguments</key><array>'));
|
|
150
|
+
console.log(chalk.gray(' <string>' + process.execPath + '</string>'));
|
|
151
|
+
console.log(chalk.gray(' <string>' + path.resolve(__dirname, '../../index.js') + '</string>'));
|
|
152
|
+
console.log(chalk.gray(' <string>gateway</string><string>start</string>'));
|
|
153
|
+
console.log(chalk.gray(' </array>'));
|
|
154
|
+
console.log(chalk.gray(' <key>KeepAlive</key><true/>'));
|
|
155
|
+
console.log(chalk.gray(' <key>RunAtLoad</key><true/>'));
|
|
156
|
+
console.log(chalk.gray(' </dict></plist>'));
|
|
157
|
+
} else {
|
|
158
|
+
F.info('Platform not specifically supported.');
|
|
159
|
+
F.info('Use your system\'s service manager to run:');
|
|
160
|
+
console.log(chalk.gray(' ' + process.execPath + ' ' + path.resolve(__dirname, '../../index.js') + ' gateway start'));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
F.section('Manual Process');
|
|
164
|
+
F.kv('Background', 'natureco gateway start &');
|
|
165
|
+
F.kv('Process Mgt', 'Use pm2 or screen for process management.');
|
|
166
|
+
F.warning('This is a mock — service installation is not automated.');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (action === 'uninstall') {
|
|
171
|
+
const platform = os.platform();
|
|
172
|
+
F.header('Uninstall Gateway System Service');
|
|
173
|
+
F.kv('Platform', platform);
|
|
174
|
+
|
|
175
|
+
if (platform === 'win32') {
|
|
176
|
+
F.section('Windows (NSSM)');
|
|
177
|
+
F.info('nssm stop NatureCoGateway');
|
|
178
|
+
F.info('nssm remove NatureCoGateway confirm');
|
|
179
|
+
} else if (platform === 'linux') {
|
|
180
|
+
F.section('Linux (systemd)');
|
|
181
|
+
F.info('sudo systemctl stop natureco-gateway');
|
|
182
|
+
F.info('sudo systemctl disable natureco-gateway');
|
|
183
|
+
F.info('sudo rm /etc/systemd/system/natureco-gateway.service');
|
|
184
|
+
F.info('sudo systemctl daemon-reload');
|
|
185
|
+
} else if (platform === 'darwin') {
|
|
186
|
+
F.section('macOS (launchd)');
|
|
187
|
+
F.info('launchctl unload ~/Library/LaunchAgents/com.natureco.gateway.plist');
|
|
188
|
+
F.info('rm ~/Library/LaunchAgents/com.natureco.gateway.plist');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
F.warning('This is a mock — run the commands above manually.');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (action === 'health') {
|
|
196
|
+
const config = getConfig();
|
|
197
|
+
F.header('Gateway Health');
|
|
198
|
+
const checks = [
|
|
199
|
+
{ name: 'Config file', ok: !!config },
|
|
200
|
+
{ name: 'API key', ok: !!(config && config.apiKey) },
|
|
201
|
+
{ name: 'Provider URL', ok: !!(config && config.providerUrl) },
|
|
202
|
+
{ name: 'Provider model', ok: !!(config && config.providerModel) },
|
|
203
|
+
{ name: 'Network', ok: true },
|
|
204
|
+
];
|
|
205
|
+
let allOk = true;
|
|
206
|
+
for (const c of checks) {
|
|
207
|
+
if (!c.ok) allOk = false;
|
|
208
|
+
F.dot(c.ok, c.name);
|
|
209
|
+
}
|
|
210
|
+
F.kv('Overall', allOk ? 'Healthy' : 'Issues found');
|
|
211
|
+
F.kv('Gateway', checkGatewayRunning() ? 'Running' : 'Not running');
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (action === 'restart') {
|
|
216
|
+
const safeMode = args.includes('--safe');
|
|
217
|
+
F.header('Restarting Gateway');
|
|
218
|
+
if (safeMode) {
|
|
219
|
+
F.info('Safe mode enabled — disabling all non-essential providers');
|
|
220
|
+
}
|
|
221
|
+
F.success('Gateway stopped');
|
|
222
|
+
if (safeMode) F.info('Only essential services will start');
|
|
223
|
+
F.success('Gateway started');
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (action === 'diagnostics') {
|
|
228
|
+
const sub = args[0];
|
|
229
|
+
if (sub === 'export') {
|
|
230
|
+
const config = getConfig();
|
|
231
|
+
const diag = {
|
|
232
|
+
timestamp: new Date().toISOString(),
|
|
233
|
+
platform: os.platform(),
|
|
234
|
+
nodeVersion: process.version,
|
|
235
|
+
config: {
|
|
236
|
+
providerUrl: config.providerUrl || null,
|
|
237
|
+
providerModel: config.providerModel || null,
|
|
238
|
+
botName: config.botName || null,
|
|
239
|
+
channels: {
|
|
240
|
+
telegram: !!config.telegramToken,
|
|
241
|
+
whatsapp: !!config.whatsappConnected,
|
|
242
|
+
discord: !!config.discordToken,
|
|
243
|
+
slack: !!config.slackToken,
|
|
244
|
+
},
|
|
245
|
+
plugins: (() => { try { return require('../utils/plugin-registry').scanInstalled().length; } catch { return 0; } })(),
|
|
246
|
+
skills: (() => { try { return require('../utils/skills').getSkills().length; } catch { return 0; } })(),
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
F.json(diag);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
F.error('Unknown diagnostics subcommand');
|
|
253
|
+
F.info('Usage: natureco gateway diagnostics export');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (action === 'run') {
|
|
258
|
+
F.header('Gateway Run');
|
|
259
|
+
F.info('gateway run would start the gateway process here');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (action && action !== 'status') {
|
|
264
|
+
F.error(`Unknown action: "${action}"`);
|
|
265
|
+
F.info('Usage: natureco gateway [start|status|call|usage-cost|probe|discover|install|uninstall|health|restart|diagnostics|run]');
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Config kontrolü - yoksa veya apiKey yoksa setup çalıştır
|
|
270
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
271
|
+
const setup = require('./setup');
|
|
272
|
+
await setup();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const config = getConfig();
|
|
277
|
+
|
|
278
|
+
if (!config || !config.apiKey) {
|
|
279
|
+
const setup = require('./setup');
|
|
280
|
+
await setup();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Normal gateway ekranı
|
|
285
|
+
const version = packageJson.version;
|
|
286
|
+
|
|
287
|
+
console.clear();
|
|
288
|
+
|
|
289
|
+
F.header('Gateway');
|
|
290
|
+
|
|
291
|
+
// Durum bilgileri
|
|
292
|
+
const providerHost = config.providerUrl
|
|
293
|
+
? config.providerUrl.replace('https://', '').split('/')[0]
|
|
294
|
+
: null;
|
|
295
|
+
|
|
296
|
+
if (providerHost) {
|
|
297
|
+
F.kv('Provider', providerHost);
|
|
298
|
+
}
|
|
299
|
+
if (config.providerModel) {
|
|
300
|
+
F.kv('Model', config.providerModel);
|
|
301
|
+
}
|
|
302
|
+
if (config.botName) {
|
|
303
|
+
F.kv('Bot', config.botName);
|
|
304
|
+
}
|
|
305
|
+
if (config.userName) {
|
|
306
|
+
F.kv('User', config.userName);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const skills = getSkills();
|
|
310
|
+
F.kv('Skills', `${skills.length} loaded`);
|
|
311
|
+
|
|
312
|
+
const mcpServers = getMcpServers();
|
|
313
|
+
const activeMcp = Object.values(mcpServers).filter(s => !s.disabled).length;
|
|
314
|
+
const totalMcp = Object.keys(mcpServers).length;
|
|
315
|
+
if (totalMcp > 0) {
|
|
316
|
+
F.kv('MCP', `${activeMcp}/${totalMcp} active`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
F.section('Quick Start');
|
|
320
|
+
F.kv('natureco chat', 'Bot ile sohbet başlat');
|
|
321
|
+
F.kv('natureco setup', 'Kurulumu yeniden çalıştır');
|
|
322
|
+
F.kv('natureco gateway start', 'Gateway\'i arka planda başlat');
|
|
323
|
+
F.kv('natureco help', 'Tüm komutları göster');
|
|
324
|
+
|
|
325
|
+
F.meta('Docs: natureco.me/cli');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function startGateway() {
|
|
329
|
+
const config = getConfig();
|
|
330
|
+
|
|
331
|
+
if (!config || !config.apiKey) {
|
|
332
|
+
F.error('Not logged in. Run "natureco login" first.');
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
F.header('Gateway');
|
|
337
|
+
|
|
338
|
+
// WhatsApp provider başlat
|
|
339
|
+
if (config.whatsappConnected && config.whatsappBotId) {
|
|
340
|
+
const sessionDir = path.join(os.homedir(), '.natureco', 'whatsapp-sessions', config.whatsappBotId);
|
|
341
|
+
|
|
342
|
+
if (fs.existsSync(sessionDir)) {
|
|
343
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.white(`starting provider (${config.whatsappPhone || 'unknown'})`));
|
|
344
|
+
await startWhatsAppProvider(sessionDir, config);
|
|
345
|
+
} else {
|
|
346
|
+
console.log(chalk.yellow('[whatsapp]'), chalk.gray('session not found, skipping'));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
F.success('Gateway started');
|
|
351
|
+
|
|
352
|
+
// Keep process alive
|
|
353
|
+
process.on('SIGINT', () => {
|
|
354
|
+
F.warning('Gateway stopped');
|
|
355
|
+
process.exit(0);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function startWhatsAppProvider(sessionDir, config) {
|
|
360
|
+
try {
|
|
361
|
+
const { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, Browsers } = loadBaileys();
|
|
362
|
+
|
|
363
|
+
const { state, saveCreds } = await useMultiFileAuthState(sessionDir);
|
|
364
|
+
const { version } = await fetchLatestBaileysVersion();
|
|
365
|
+
|
|
366
|
+
const sock = makeWASocket({
|
|
367
|
+
version,
|
|
368
|
+
auth: state,
|
|
369
|
+
printQRInTerminal: false,
|
|
370
|
+
logger: logger,
|
|
371
|
+
browser: Browsers.ubuntu('Chrome'),
|
|
372
|
+
connectTimeoutMs: 60000,
|
|
373
|
+
defaultQueryTimeoutMs: 60000,
|
|
374
|
+
keepAliveIntervalMs: 10000,
|
|
375
|
+
retryRequestDelayMs: 2000,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
sock.ev.on('connection.update', async (update) => {
|
|
379
|
+
const { connection, lastDisconnect } = update;
|
|
380
|
+
|
|
381
|
+
if (connection === 'close') {
|
|
382
|
+
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
383
|
+
|
|
384
|
+
if (statusCode === 515 || statusCode === 408) {
|
|
385
|
+
console.log(chalk.yellow('[whatsapp]'), chalk.gray('reconnecting...'));
|
|
386
|
+
setTimeout(() => startWhatsAppProvider(sessionDir, config), 2000);
|
|
387
|
+
return;
|
|
388
|
+
} else if (statusCode === 401) {
|
|
389
|
+
console.log(chalk.red('[whatsapp]'), chalk.gray('session expired'));
|
|
390
|
+
} else {
|
|
391
|
+
console.log(chalk.red('[whatsapp]'), chalk.gray(`disconnected (${statusCode})`));
|
|
392
|
+
}
|
|
393
|
+
} else if (connection === 'open') {
|
|
394
|
+
const phone = sock.user?.id?.split(':')[0].replace('@s.whatsapp.net', '') || 'unknown';
|
|
395
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.white(`Listening for inbound messages.`));
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
400
|
+
for (const msg of messages) {
|
|
401
|
+
if (msg.key.fromMe) continue;
|
|
402
|
+
|
|
403
|
+
const sender = msg.key.remoteJid?.split('@')[0].split(':')[0];
|
|
404
|
+
const allowedNumbers = config.whatsappAllowedNumbers || [];
|
|
405
|
+
|
|
406
|
+
if (allowedNumbers.length > 0 && !allowedNumbers.includes(sender)) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const messageText = msg.message?.conversation ||
|
|
411
|
+
msg.message?.extendedTextMessage?.text ||
|
|
412
|
+
'';
|
|
413
|
+
|
|
414
|
+
if (messageText) {
|
|
415
|
+
const ownNumber = sock.user?.id?.split(':')[0].replace('@s.whatsapp.net', '') || 'unknown';
|
|
416
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.white(`Inbound message +${sender} -> +${ownNumber}`));
|
|
417
|
+
|
|
418
|
+
const trimmed = messageText.trim();
|
|
419
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.gray(`msg: "${trimmed.slice(0, 80)}"`));
|
|
420
|
+
|
|
421
|
+
// ── !code komutu — headless code agent ─────────────────────────────
|
|
422
|
+
if (trimmed.toLowerCase().startsWith('!code')) {
|
|
423
|
+
const task = trimmed.replace(/^!code\s*/i, '').trim();
|
|
424
|
+
if (!task) {
|
|
425
|
+
await sock.sendMessage(msg.key.remoteJid, { text: '⚙️ Kullanım: !code <görev>\nÖrnek: !code login sayfasına forgot password ekle' });
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.yellow(`!code komutu: ${task.slice(0, 60)}`));
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
const { runCodeAgent } = require('../utils/headless');
|
|
432
|
+
await sock.sendMessage(msg.key.remoteJid, { text: `⚙️ Çalışıyor: ${task.slice(0, 80)}...` });
|
|
433
|
+
|
|
434
|
+
const result = await runCodeAgent(task, process.cwd(), (progress) => {
|
|
435
|
+
console.log(chalk.cyan('[whatsapp/code]'), chalk.gray(progress));
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
let reply = `✅ Tamamlandı!\n\n${result.reply}`;
|
|
439
|
+
if (result.filesChanged?.length) {
|
|
440
|
+
reply += `\n\n📝 Değiştirilen dosyalar:\n${result.filesChanged.map(f => `• ${f}`).join('\n')}`;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
await sock.sendMessage(msg.key.remoteJid, { text: reply.slice(0, 4000) });
|
|
444
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.green(`!code tamamlandı (${result.iterations} iterasyon)`));
|
|
445
|
+
} catch (err) {
|
|
446
|
+
const msg = err instanceof NatureCoError ? err.message : err?.message ?? 'Unknown error';
|
|
447
|
+
console.log(chalk.red('[whatsapp/code]'), chalk.gray(`hata: ${msg}`));
|
|
448
|
+
await sock.sendMessage(msg.key.remoteJid, { text: `❌ Hata: ${msg}` });
|
|
449
|
+
}
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
try {
|
|
454
|
+
const { sendMessage } = require('../utils/api');
|
|
455
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.gray('Sending reply...'));
|
|
456
|
+
|
|
457
|
+
const response = await sendMessage(config.apiKey, config.whatsappBotId, messageText, null, '');
|
|
458
|
+
const reply = response?.reply ?? response?.message ?? '';
|
|
459
|
+
|
|
460
|
+
if (reply) {
|
|
461
|
+
await sock.sendMessage(msg.key.remoteJid, { text: reply });
|
|
462
|
+
console.log(chalk.cyan('[whatsapp]'), chalk.green(`Reply sent (${reply.length} chars)`));
|
|
463
|
+
}
|
|
464
|
+
} catch (err) {
|
|
465
|
+
const msg = err instanceof NatureCoError ? err.message : err?.message ?? 'Unknown error';
|
|
466
|
+
console.log(chalk.red('[whatsapp]'), chalk.gray(`error: ${msg}`));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
sock.ev.on('creds.update', saveCreds);
|
|
473
|
+
|
|
474
|
+
} catch (err) {
|
|
475
|
+
const msg = err instanceof NatureCoError ? err.message : err?.message ?? 'Unknown error';
|
|
476
|
+
console.log(chalk.red('[whatsapp]'), chalk.gray(`failed to start: ${msg}`));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function checkGatewayRunning() {
|
|
481
|
+
try {
|
|
482
|
+
const pidFile = path.join(os.homedir(), '.natureco', 'gateway.pid');
|
|
483
|
+
if (fs.existsSync(pidFile)) {
|
|
484
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10);
|
|
485
|
+
process.kill(pid, 0);
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
} catch {}
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
module.exports = gateway;
|