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
|
@@ -1,46 +1,178 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
2
5
|
const { getConfig } = require('../utils/config');
|
|
3
6
|
|
|
7
|
+
const PEERS_FILE = path.join(os.homedir(), '.natureco', 'peers.json');
|
|
8
|
+
|
|
9
|
+
function loadPeers() {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(fs.readFileSync(PEERS_FILE, 'utf8'));
|
|
12
|
+
} catch {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function savePeers(peers) {
|
|
18
|
+
const dir = path.dirname(PEERS_FILE);
|
|
19
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
fs.writeFileSync(PEERS_FILE, JSON.stringify(peers, null, 2));
|
|
21
|
+
}
|
|
22
|
+
|
|
4
23
|
function directory(args) {
|
|
5
24
|
const [action, ...params] = args || [];
|
|
6
25
|
|
|
7
26
|
if (!action || action === 'self') return showSelf();
|
|
8
|
-
if (action === 'channels' || action === 'peers') return
|
|
27
|
+
if (action === 'channels' || action === 'peers') return listPeers();
|
|
28
|
+
if (action === 'search') return searchPeers(params.join(' '));
|
|
29
|
+
if (action === 'register') return registerPeer(params[0], params.slice(1).join(' '));
|
|
30
|
+
if (action === 'remove') return removePeer(params[0]);
|
|
31
|
+
if (action === 'groups' && params[0] === 'list') return groupsList();
|
|
32
|
+
if (action === 'groups' && params[0] === 'members') return groupsMembers(params[1]);
|
|
33
|
+
if (action === 'groups') return groupsList();
|
|
9
34
|
|
|
10
35
|
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
11
|
-
console.log(chalk.gray(' Kullanım: natureco directory [self|
|
|
36
|
+
console.log(chalk.gray(' Kullanım: natureco directory [self|peers|search|register|remove|groups]\n'));
|
|
12
37
|
process.exit(1);
|
|
13
38
|
}
|
|
14
39
|
|
|
15
40
|
function showSelf() {
|
|
16
41
|
const config = getConfig();
|
|
17
|
-
console.log(chalk.cyan('\n
|
|
42
|
+
console.log(chalk.cyan('\n Self\n'));
|
|
18
43
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
19
44
|
console.log(` ${chalk.white('Name:')} ${chalk.cyan(config.agentName || process.env.USER || 'user')}`);
|
|
20
45
|
console.log(` ${chalk.white('Gateway:')} ${chalk.gray(config.gatewayUrl || 'not configured')}`);
|
|
21
46
|
console.log(` ${chalk.white('Provider:')} ${chalk.gray(config.provider || 'not set')}`);
|
|
22
47
|
console.log(` ${chalk.white('Model:')} ${chalk.gray(config.model || 'not set')}`);
|
|
23
48
|
console.log(` ${chalk.white('User ID:')} ${chalk.gray(config.userId || 'local')}`);
|
|
49
|
+
console.log(` ${chalk.white('Peers:')} ${chalk.gray(`${loadPeers().length} registered`)}`);
|
|
50
|
+
console.log(` ${chalk.white('Host:')} ${chalk.gray(os.hostname())}`);
|
|
24
51
|
console.log();
|
|
25
52
|
}
|
|
26
53
|
|
|
27
|
-
function
|
|
54
|
+
function listPeers() {
|
|
28
55
|
const config = getConfig();
|
|
29
|
-
|
|
30
|
-
|
|
56
|
+
const peers = loadPeers();
|
|
57
|
+
|
|
58
|
+
if (peers.length === 0) {
|
|
59
|
+
console.log(chalk.cyan('\n Directory\n'));
|
|
60
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
31
61
|
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
const channels = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage', 'sms'];
|
|
63
|
+
let found = false;
|
|
34
64
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
for (const ch of channels) {
|
|
66
|
+
if (config[ch]) {
|
|
67
|
+
const info = typeof config[ch] === 'object' ? Object.keys(config[ch]).join(', ') : 'connected';
|
|
68
|
+
console.log(` ${chalk.green('●')} ${chalk.white(ch)}: ${chalk.gray(info)}`);
|
|
69
|
+
found = true;
|
|
70
|
+
}
|
|
40
71
|
}
|
|
72
|
+
|
|
73
|
+
if (!found) console.log(chalk.gray(' No channels configured.'));
|
|
74
|
+
console.log(chalk.gray('\n Register peers: ') + chalk.cyan('natureco directory register <url> [name]'));
|
|
75
|
+
console.log();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(chalk.cyan('\n Known Peers\n'));
|
|
80
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
81
|
+
peers.forEach(p => {
|
|
82
|
+
const status = p.lastSeen ? chalk.gray(`(seen: ${new Date(p.lastSeen).toLocaleDateString()})`) : '';
|
|
83
|
+
console.log(` ${chalk.green('●')} ${chalk.white(p.name || p.url)}`);
|
|
84
|
+
console.log(` ${chalk.gray(p.url)} ${status}`);
|
|
85
|
+
});
|
|
86
|
+
console.log(chalk.gray(`\n Total: ${peers.length} peers`));
|
|
87
|
+
console.log();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function searchPeers(query) {
|
|
91
|
+
if (!query) {
|
|
92
|
+
console.log(chalk.red('\n ❌ Arama sorgusu gerekli\n'));
|
|
93
|
+
console.log(chalk.gray(' Kullanım: natureco directory search <query>\n'));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const peers = loadPeers();
|
|
98
|
+
const lower = query.toLowerCase();
|
|
99
|
+
const results = peers.filter(p =>
|
|
100
|
+
(p.name && p.name.toLowerCase().includes(lower)) ||
|
|
101
|
+
(p.url && p.url.toLowerCase().includes(lower)) ||
|
|
102
|
+
(p.tags && p.tags.some(t => t.toLowerCase().includes(lower)))
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
if (results.length === 0) {
|
|
106
|
+
console.log(chalk.yellow(`\n "${query}" için eşleşen peer bulunamadı.\n`));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(chalk.cyan(`\n Search Results (${results.length}) for: "${query}"\n`));
|
|
111
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
112
|
+
results.forEach(p => {
|
|
113
|
+
console.log(` ${chalk.green('●')} ${chalk.white(p.name || p.url)}`);
|
|
114
|
+
console.log(` ${chalk.gray(p.url)}`);
|
|
115
|
+
if (p.tags) console.log(` ${chalk.gray('tags: ' + p.tags.join(', '))}`);
|
|
116
|
+
});
|
|
117
|
+
console.log();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function registerPeer(url, name) {
|
|
121
|
+
if (!url) {
|
|
122
|
+
console.log(chalk.red('\n ❌ URL gerekli\n'));
|
|
123
|
+
console.log(chalk.gray(' Kullanım: natureco directory register <url> [name]\n'));
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const peers = loadPeers();
|
|
128
|
+
if (peers.some(p => p.url === url)) {
|
|
129
|
+
console.log(chalk.yellow(`\n ⚠ Bu peer zaten kayıtlı: ${url}\n`));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
peers.push({ url, name: name || url, tags: [], addedAt: new Date().toISOString(), lastSeen: null });
|
|
134
|
+
savePeers(peers);
|
|
135
|
+
console.log(chalk.green(`\n ✓ Peer kaydedildi: ${name || url}\n`));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function removePeer(urlOrName) {
|
|
139
|
+
if (!urlOrName) {
|
|
140
|
+
console.log(chalk.red('\n ❌ URL veya isim gerekli\n'));
|
|
141
|
+
console.log(chalk.gray(' Kullanım: natureco directory remove <url|name>\n'));
|
|
142
|
+
process.exit(1);
|
|
41
143
|
}
|
|
42
144
|
|
|
43
|
-
|
|
145
|
+
let peers = loadPeers();
|
|
146
|
+
const initialLength = peers.length;
|
|
147
|
+
peers = peers.filter(p => p.url !== urlOrName && p.name !== urlOrName);
|
|
148
|
+
|
|
149
|
+
if (peers.length === initialLength) {
|
|
150
|
+
console.log(chalk.yellow(`\n ⚠ Peer bulunamadı: ${urlOrName}\n`));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
savePeers(peers);
|
|
155
|
+
console.log(chalk.green(`\n ✓ Peer kaldırıldı: ${urlOrName}\n`));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function groupsList() {
|
|
159
|
+
console.log(chalk.cyan('\n Groups: (stub)\n'));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function groupsMembers(name) {
|
|
163
|
+
if (!name) {
|
|
164
|
+
console.log(chalk.red('\n ❌ Group name gerekli\n'));
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
console.log(chalk.cyan('\n Members of group "' + name + '":\n'));
|
|
168
|
+
const peers = loadPeers().filter(p => p.tags && p.tags.includes('group:' + name));
|
|
169
|
+
if (peers.length === 0) {
|
|
170
|
+
console.log(chalk.gray(' No members found.\n'));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
for (const p of peers) {
|
|
174
|
+
console.log(` ${chalk.green('●')} ${chalk.white(p.name || p.url)}`);
|
|
175
|
+
}
|
|
44
176
|
console.log();
|
|
45
177
|
}
|
|
46
178
|
|
package/src/commands/dns.js
CHANGED
|
@@ -7,14 +7,15 @@ function dnsCmd(args) {
|
|
|
7
7
|
|
|
8
8
|
if (!action || action === 'discover') return discoverNetwork();
|
|
9
9
|
if (action === 'resolve') return resolveHost(params[0]);
|
|
10
|
+
if (action === 'services') return discoverServices();
|
|
10
11
|
|
|
11
12
|
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
12
|
-
console.log(chalk.gray(' Kullanım: natureco dns [discover|resolve]\n'));
|
|
13
|
+
console.log(chalk.gray(' Kullanım: natureco dns [discover|resolve <host>|services]\n'));
|
|
13
14
|
process.exit(1);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
function discoverNetwork() {
|
|
17
|
-
console.log(chalk.cyan('\n
|
|
18
|
+
console.log(chalk.cyan('\n Network Discovery (DNS)\n'));
|
|
18
19
|
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
19
20
|
|
|
20
21
|
const interfaces = os.networkInterfaces();
|
|
@@ -30,29 +31,166 @@ function discoverNetwork() {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const tailscaleIP = detectTailscale();
|
|
35
|
+
if (tailscaleIP) {
|
|
36
|
+
console.log(`\n ${chalk.green('●')} ${chalk.white('Tailscale')}: ${chalk.cyan(tailscaleIP)}`);
|
|
37
|
+
const hostname = os.hostname();
|
|
38
|
+
dns.resolveTxt(`_natureco._tcp.${hostname}.tailscale.net`, (err, records) => {
|
|
39
|
+
if (!err && records) {
|
|
40
|
+
console.log(` ${chalk.gray(' Service:')} ${chalk.cyan(records.flat().join(', '))}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const zerotier = detectZeroTier();
|
|
46
|
+
if (zerotier) {
|
|
47
|
+
console.log(` ${chalk.green('●')} ${chalk.white('ZeroTier')}: ${chalk.cyan(zerotier)}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(chalk.gray('\n mDNS: ') + chalk.cyan('natureco bonjour scan'));
|
|
51
|
+
console.log(chalk.gray(' Resolve: ') + chalk.cyan('natureco dns resolve <hostname>'));
|
|
52
|
+
console.log(chalk.gray(' Services: ') + chalk.cyan('natureco dns services\n'));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function detectTailscale() {
|
|
56
|
+
try {
|
|
57
|
+
const tailscaleDir = os.platform() === 'win32'
|
|
58
|
+
? os.homedir() + '\\AppData\\Local\\Tailscale'
|
|
59
|
+
: '/var/run/tailscale';
|
|
60
|
+
if (!require('fs').existsSync(tailscaleDir)) return null;
|
|
61
|
+
|
|
62
|
+
const interfaces = os.networkInterfaces();
|
|
63
|
+
for (const [, addrs] of Object.entries(interfaces)) {
|
|
64
|
+
if (!addrs) continue;
|
|
65
|
+
for (const addr of addrs) {
|
|
66
|
+
if (addr.family === 'IPv4' && addr.address.startsWith('100.')) {
|
|
67
|
+
return addr.address;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch {}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function detectZeroTier() {
|
|
76
|
+
try {
|
|
77
|
+
const interfaces = os.networkInterfaces();
|
|
78
|
+
for (const [, addrs] of Object.entries(interfaces)) {
|
|
79
|
+
if (!addrs) continue;
|
|
80
|
+
for (const addr of addrs) {
|
|
81
|
+
if (addr.family === 'IPv4' && (
|
|
82
|
+
addr.address.startsWith('10.144.') ||
|
|
83
|
+
addr.address.startsWith('10.147.')
|
|
84
|
+
)) {
|
|
85
|
+
return addr.address;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch {}
|
|
90
|
+
return null;
|
|
35
91
|
}
|
|
36
92
|
|
|
37
93
|
function resolveHost(hostname) {
|
|
38
94
|
if (!hostname) {
|
|
39
95
|
console.log(chalk.red('\n ❌ Hostname gerekli\n'));
|
|
96
|
+
console.log(chalk.gray(' Kullanım: natureco dns resolve <hostname>\n'));
|
|
40
97
|
process.exit(1);
|
|
41
98
|
}
|
|
42
99
|
|
|
43
|
-
console.log(chalk.cyan(`\n
|
|
100
|
+
console.log(chalk.cyan(`\n Resolving: ${hostname}\n`));
|
|
44
101
|
|
|
45
102
|
dns.resolve4(hostname, (err, addresses) => {
|
|
46
|
-
if (err) {
|
|
103
|
+
if (err && err.code !== 'ENODATA') {
|
|
47
104
|
console.log(chalk.red(` ❌ ${err.message}\n`));
|
|
48
105
|
return;
|
|
49
106
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
107
|
+
|
|
108
|
+
const results = [];
|
|
109
|
+
if (addresses && addresses.length > 0) {
|
|
110
|
+
for (const addr of addresses) {
|
|
111
|
+
results.push({ type: 'A', value: addr });
|
|
112
|
+
}
|
|
53
113
|
}
|
|
54
|
-
|
|
114
|
+
|
|
115
|
+
dns.resolve6(hostname, (err6, addrs6) => {
|
|
116
|
+
if (!err6 && addrs6) {
|
|
117
|
+
for (const addr of addrs6) {
|
|
118
|
+
results.push({ type: 'AAAA', value: addr });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
dns.resolveTxt(hostname, (errTxt, txts) => {
|
|
123
|
+
if (!errTxt && txts) {
|
|
124
|
+
for (const txt of txts) {
|
|
125
|
+
results.push({ type: 'TXT', value: txt.join(' ') });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
dns.resolveSrv(`_natureco._tcp.${hostname}`, (errSrv, srvs) => {
|
|
130
|
+
if (!errSrv && srvs) {
|
|
131
|
+
for (const srv of srvs) {
|
|
132
|
+
results.push({ type: 'SRV', value: `${srv.name}:${srv.port} (priority ${srv.priority}, weight ${srv.weight})` });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (results.length === 0) {
|
|
137
|
+
console.log(chalk.gray(' No DNS records found.\n'));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
142
|
+
for (const r of results) {
|
|
143
|
+
console.log(` ${chalk.white(hostname)} ${chalk.cyan(r.type)} ${chalk.gray('→')} ${chalk.white(r.value)}`);
|
|
144
|
+
}
|
|
145
|
+
console.log();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
55
149
|
});
|
|
56
150
|
}
|
|
57
151
|
|
|
152
|
+
function discoverServices() {
|
|
153
|
+
console.log(chalk.cyan('\n Service Discovery (DNS-SD)\n'));
|
|
154
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
155
|
+
|
|
156
|
+
const services = [
|
|
157
|
+
'_natureco._tcp',
|
|
158
|
+
'_natureco-gateway._tcp',
|
|
159
|
+
'_natureco-dashboard._tcp',
|
|
160
|
+
'_mcp._tcp',
|
|
161
|
+
'_openclaw._tcp',
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
let pending = services.length;
|
|
165
|
+
let found = false;
|
|
166
|
+
|
|
167
|
+
for (const svc of services) {
|
|
168
|
+
dns.resolveSrv(svc + '.local', { hints: dns.ADDRCONFIG }, (err, addresses) => {
|
|
169
|
+
if (!err && addresses && addresses.length > 0) {
|
|
170
|
+
found = true;
|
|
171
|
+
console.log(` ${chalk.green('●')} ${chalk.white(svc)}`);
|
|
172
|
+
for (const addr of addresses) {
|
|
173
|
+
dns.resolve4(addr.name, { hints: dns.ADDRCONFIG }, (err4, ips) => {
|
|
174
|
+
const ip = ips && ips.length > 0 ? `(${ips[0]})` : '';
|
|
175
|
+
console.log(` ${chalk.gray(`${addr.name}:${addr.port} ${ip}`)}`);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
pending--;
|
|
181
|
+
if (pending === 0 && !found) {
|
|
182
|
+
console.log(chalk.gray(' No NatureCo services discovered via DNS-SD.\n'));
|
|
183
|
+
console.log(chalk.gray(' Try: ') + chalk.cyan('natureco bonjour discover'));
|
|
184
|
+
console.log(chalk.gray(' Try: ') + chalk.cyan('natureco dns discover\n'));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
if (!found) {
|
|
191
|
+
console.log(chalk.gray(' Discovering... (may take a moment)\n'));
|
|
192
|
+
}
|
|
193
|
+
}, 500);
|
|
194
|
+
}
|
|
195
|
+
|
|
58
196
|
module.exports = dnsCmd;
|
package/src/commands/docs.js
CHANGED
|
@@ -1,43 +1,136 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
|
|
3
|
+
const DOC_SOURCES = [
|
|
4
|
+
{ name: 'NatureCo API', url: 'https://api.natureco.me/api/v1/docs/search?q=' },
|
|
5
|
+
{ name: 'NatureCo CLI', url: 'https://natureco.me/cli/' },
|
|
6
|
+
{ name: 'NatureCo Developers', url: 'https://developers.natureco.me/' },
|
|
7
|
+
{ name: 'OpenClaw Docs', url: 'https://docs.openclaw.ai/' },
|
|
8
|
+
];
|
|
9
|
+
|
|
3
10
|
async function docs(args) {
|
|
4
11
|
const query = args.join(' ').trim();
|
|
5
12
|
|
|
6
13
|
if (!query) {
|
|
7
|
-
|
|
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();
|
|
14
|
+
showHelp();
|
|
16
15
|
return;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
console.log(chalk.cyan(`\n
|
|
18
|
+
console.log(chalk.cyan(`\n Searching docs for: "${query}"\n`));
|
|
19
|
+
|
|
20
|
+
let found = false;
|
|
21
|
+
|
|
22
|
+
for (const source of DOC_SOURCES) {
|
|
23
|
+
try {
|
|
24
|
+
const url = source.url.includes('/docs/search')
|
|
25
|
+
? source.url + encodeURIComponent(query)
|
|
26
|
+
: source.url;
|
|
27
|
+
const response = await fetch(url + (source.url.includes('/docs/search') ? '' : '?format=json'), {
|
|
28
|
+
headers: { 'User-Agent': 'NatureCo-CLI/2.0' },
|
|
29
|
+
signal: AbortSignal.timeout(3000),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (response.ok) {
|
|
33
|
+
const text = await response.text();
|
|
34
|
+
let data;
|
|
35
|
+
try { data = JSON.parse(text); } catch { data = null; }
|
|
36
|
+
|
|
37
|
+
if (data && data.results && data.results.length > 0) {
|
|
38
|
+
found = true;
|
|
39
|
+
console.log(chalk.cyan(` ${source.name}\n`));
|
|
40
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
41
|
+
for (const r of data.results.slice(0, 5)) {
|
|
42
|
+
console.log(` ${chalk.white(r.title || r.name || 'Result')}`);
|
|
43
|
+
if (r.description) console.log(` ${chalk.gray(r.description)}`);
|
|
44
|
+
if (r.url) console.log(` ${chalk.cyan(r.url)}`);
|
|
45
|
+
console.log();
|
|
46
|
+
}
|
|
47
|
+
} else if (data && data.AbstractText) {
|
|
48
|
+
found = true;
|
|
49
|
+
console.log(chalk.cyan(` ${source.name}\n`));
|
|
50
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
51
|
+
console.log(` ${chalk.white(data.AbstractText)}`);
|
|
52
|
+
if (data.AbstractURL) console.log(`\n ${chalk.cyan(data.AbstractURL)}`);
|
|
53
|
+
console.log();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!found) {
|
|
60
|
+
try {
|
|
61
|
+
const webRes = await fetch(`https://api.duckduckgo.com/?q=${encodeURIComponent('site:natureco.me ' + query)}&format=json&no_html=1&skip_disambig=1`, {
|
|
62
|
+
headers: { 'User-Agent': 'NatureCo-CLI/2.0' },
|
|
63
|
+
signal: AbortSignal.timeout(5000),
|
|
64
|
+
});
|
|
20
65
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
66
|
+
if (webRes.ok) {
|
|
67
|
+
const webData = await webRes.json();
|
|
68
|
+
if (webData.AbstractText || webData.RelatedTopics?.length > 0) {
|
|
69
|
+
found = true;
|
|
70
|
+
console.log(chalk.cyan(' NatureCo (via DuckDuckGo)\n'));
|
|
71
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
72
|
+
if (webData.AbstractText) {
|
|
73
|
+
console.log(` ${chalk.white(webData.AbstractText)}`);
|
|
74
|
+
if (webData.AbstractURL) console.log(`\n ${chalk.cyan(webData.AbstractURL)}`);
|
|
75
|
+
} else {
|
|
76
|
+
for (const topic of webData.RelatedTopics.slice(0, 5)) {
|
|
77
|
+
if (topic.Text) {
|
|
78
|
+
console.log(` ${chalk.white(topic.Text)}`);
|
|
79
|
+
if (topic.FirstURL) console.log(` ${chalk.cyan(topic.FirstURL)}`);
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
console.log();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch {}
|
|
88
|
+
}
|
|
25
89
|
|
|
26
|
-
|
|
90
|
+
if (!found) {
|
|
91
|
+
try {
|
|
92
|
+
const htmlRes = await fetch('https://natureco.me/cli/', {
|
|
93
|
+
headers: { 'User-Agent': 'NatureCo-CLI/2.0' },
|
|
94
|
+
signal: AbortSignal.timeout(3000),
|
|
95
|
+
});
|
|
96
|
+
if (htmlRes.ok) {
|
|
97
|
+
const html = await htmlRes.text();
|
|
98
|
+
const lines = html.split('\n').filter(l => l.toLowerCase().includes(query.toLowerCase()));
|
|
99
|
+
if (lines.length > 0) {
|
|
100
|
+
found = true;
|
|
101
|
+
console.log(chalk.cyan(' NatureCo CLI Docs Page\n'));
|
|
102
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
103
|
+
for (const line of lines.slice(0, 5)) {
|
|
104
|
+
const clean = line.replace(/<[^>]*>/g, '').trim();
|
|
105
|
+
if (clean) console.log(` ${chalk.white(clean.substring(0, 120))}`);
|
|
106
|
+
}
|
|
107
|
+
console.log(`\n ${chalk.cyan('https://natureco.me/cli/')}`);
|
|
108
|
+
console.log();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch {}
|
|
112
|
+
}
|
|
27
113
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
}
|
|
114
|
+
if (!found) {
|
|
115
|
+
console.log(chalk.gray(' No documentation found for this query.'));
|
|
116
|
+
console.log(chalk.gray('\n Try browsing:'));
|
|
117
|
+
console.log(chalk.cyan(' https://natureco.me/cli/'));
|
|
118
|
+
console.log(chalk.cyan(' https://developers.natureco.me/'));
|
|
37
119
|
console.log();
|
|
38
|
-
} catch (err) {
|
|
39
|
-
console.log(chalk.red(` ❌ ${err.message}\n`));
|
|
40
120
|
}
|
|
41
121
|
}
|
|
42
122
|
|
|
123
|
+
function showHelp() {
|
|
124
|
+
console.log(chalk.cyan('\n NatureCo Docs Search\n'));
|
|
125
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
126
|
+
console.log(chalk.gray(' Search NatureCo documentation from multiple sources.\n'));
|
|
127
|
+
console.log(chalk.gray(' Usage:'));
|
|
128
|
+
console.log(chalk.cyan(' natureco docs <search query>'));
|
|
129
|
+
console.log(chalk.gray('\n Examples:'));
|
|
130
|
+
console.log(chalk.gray(' natureco docs gateway setup'));
|
|
131
|
+
console.log(chalk.gray(' natureco docs telegram channel'));
|
|
132
|
+
console.log(chalk.gray(' natureco docs api reference'));
|
|
133
|
+
console.log();
|
|
134
|
+
}
|
|
135
|
+
|
|
43
136
|
module.exports = docs;
|