natureco-cli 2.23.29 → 2.23.31
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 +495 -94
- package/package.json +1 -1
- package/src/commands/acp.js +39 -0
- package/src/commands/admin-rpc.js +302 -0
- package/src/commands/agent.js +280 -0
- package/src/commands/agents.js +114 -30
- package/src/commands/approvals.js +214 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/browser.js +815 -0
- package/src/commands/capability.js +237 -0
- package/src/commands/channels.js +422 -267
- package/src/commands/chat.js +5 -8
- package/src/commands/clawbot.js +19 -0
- package/src/commands/clickclack.js +130 -0
- package/src/commands/code.js +3 -2
- package/src/commands/commitments.js +148 -0
- package/src/commands/completion.js +84 -0
- package/src/commands/config.js +219 -30
- package/src/commands/configure.js +110 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/cron.js +239 -19
- package/src/commands/daemon.js +90 -0
- package/src/commands/dashboard.js +47 -374
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +137 -0
- package/src/commands/directory.js +179 -0
- package/src/commands/dns.js +196 -0
- package/src/commands/docs.js +136 -0
- package/src/commands/doctor.js +143 -492
- package/src/commands/exec-policy.js +80 -0
- package/src/commands/gateway-server.js +1155 -24
- package/src/commands/gateway.js +492 -249
- package/src/commands/health.js +148 -0
- package/src/commands/help.js +24 -25
- package/src/commands/hooks.js +141 -87
- package/src/commands/imessage.js +128 -14
- package/src/commands/infer.js +1474 -0
- package/src/commands/irc.js +64 -15
- package/src/commands/logs.js +122 -99
- package/src/commands/mattermost.js +114 -12
- package/src/commands/mcp.js +121 -309
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/memory.js +128 -0
- package/src/commands/message.js +720 -134
- package/src/commands/migrate.js +213 -2
- package/src/commands/models.js +39 -1
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +362 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +129 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/pairing.js +108 -107
- package/src/commands/path.js +206 -0
- package/src/commands/plugins.js +35 -1
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +306 -0
- package/src/commands/qr.js +70 -0
- package/src/commands/reset.js +101 -94
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +201 -0
- package/src/commands/sessions.js +110 -51
- package/src/commands/setup.js +102 -543
- package/src/commands/signal.js +447 -18
- package/src/commands/skills.js +67 -1
- package/src/commands/sms.js +123 -19
- package/src/commands/status.js +101 -127
- package/src/commands/system.js +53 -0
- package/src/commands/tasks.js +208 -100
- package/src/commands/terminal.js +139 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +95 -0
- package/src/commands/tui.js +41 -0
- package/src/commands/uninstall.js +73 -92
- package/src/commands/update.js +146 -91
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/webhooks.js +58 -66
- package/src/commands/wiki.js +783 -0
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- 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/agents-md.js +85 -0
- package/src/utils/api.js +39 -40
- package/src/utils/format.js +144 -0
- package/src/utils/headless.js +2 -1
- package/src/utils/memory.js +200 -0
- 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
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
7
|
+
|
|
8
|
+
const PAIRING_FILE = path.join(os.homedir(), '.natureco', 'data', 'pairings.json');
|
|
9
|
+
|
|
10
|
+
function loadPairings() {
|
|
11
|
+
try {
|
|
12
|
+
if (fs.existsSync(PAIRING_FILE)) return JSON.parse(fs.readFileSync(PAIRING_FILE, 'utf8'));
|
|
13
|
+
} catch {}
|
|
14
|
+
return { pairedDevices: [], pendingRequests: [] };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function savePairings(data) {
|
|
18
|
+
const dir = path.dirname(PAIRING_FILE);
|
|
19
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
fs.writeFileSync(PAIRING_FILE, JSON.stringify(data, null, 2));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function generatePairingCode() {
|
|
24
|
+
return crypto.randomBytes(4).toString('hex').toUpperCase();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function devicePair(args) {
|
|
28
|
+
const [action, ...params] = args || [];
|
|
29
|
+
|
|
30
|
+
if (!action || action === 'list') return listDevices();
|
|
31
|
+
if (action === 'request') return requestPairing(params[0], params[1]);
|
|
32
|
+
if (action === 'approve') return approvePairing(params[0]);
|
|
33
|
+
if (action === 'reject') return rejectPairing(params[0]);
|
|
34
|
+
if (action === 'remove') return removeDevice(params[0]);
|
|
35
|
+
if (action === 'pairing-code') return showPairingCode();
|
|
36
|
+
if (action === 'verify') return verifyPairing(params[0], params[1]);
|
|
37
|
+
|
|
38
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
39
|
+
console.log(chalk.gray(' Kullanım: natureco device-pair [list|request|approve|reject|remove|pairing-code|verify]\n'));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function listDevices() {
|
|
44
|
+
const data = loadPairings();
|
|
45
|
+
|
|
46
|
+
console.log(chalk.cyan('\n 📱 Paired Devices\n'));
|
|
47
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
48
|
+
|
|
49
|
+
const devices = data.pairedDevices || [];
|
|
50
|
+
if (devices.length === 0) {
|
|
51
|
+
console.log(chalk.gray(' Eşleştirilmiş cihaz yok.\n'));
|
|
52
|
+
} else {
|
|
53
|
+
for (const d of devices) {
|
|
54
|
+
console.log(` ${chalk.green('●')} ${chalk.white(d.name || d.id)} ${chalk.gray(`(${d.type || 'unknown'})`)}`);
|
|
55
|
+
console.log(` ${chalk.gray('ID:')} ${d.id}`);
|
|
56
|
+
console.log(` ${chalk.gray('Since:')} ${d.pairedAt ? new Date(d.pairedAt).toLocaleString() : '-'}`);
|
|
57
|
+
console.log(` ${chalk.gray('Token:')} ${d.token ? d.token.substring(0, 8) + '…' : '-'}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const pending = data.pendingRequests || [];
|
|
62
|
+
if (pending.length > 0) {
|
|
63
|
+
console.log(chalk.yellow(`\n ⏳ Bekleyen İstekler (${pending.length})\n`));
|
|
64
|
+
for (const p of pending) {
|
|
65
|
+
console.log(` ${chalk.yellow('◐')} ${chalk.white(p.name || p.id)} ${chalk.gray(`(${p.type || 'unknown'})`)}`);
|
|
66
|
+
console.log(` ${chalk.gray('Code:')} ${chalk.cyan(p.code)}`);
|
|
67
|
+
console.log(` ${chalk.gray('Since:')} ${p.requestedAt ? new Date(p.requestedAt).toLocaleString() : '-'}`);
|
|
68
|
+
}
|
|
69
|
+
console.log(chalk.gray('\n Onaylamak için:'));
|
|
70
|
+
console.log(chalk.cyan(' natureco device-pair approve <code>'));
|
|
71
|
+
console.log(chalk.cyan(' natureco device-pair reject <code>'));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function requestPairing(deviceName, deviceType) {
|
|
78
|
+
const name = deviceName || `Device-${crypto.randomBytes(3).toString('hex')}`;
|
|
79
|
+
const type = deviceType || 'cli';
|
|
80
|
+
const code = generatePairingCode();
|
|
81
|
+
const id = `dev_${crypto.randomBytes(8).toString('hex')}`;
|
|
82
|
+
|
|
83
|
+
const data = loadPairings();
|
|
84
|
+
if (!data.pendingRequests) data.pendingRequests = [];
|
|
85
|
+
|
|
86
|
+
data.pendingRequests.push({
|
|
87
|
+
id,
|
|
88
|
+
name,
|
|
89
|
+
type,
|
|
90
|
+
code,
|
|
91
|
+
requestedAt: new Date().toISOString(),
|
|
92
|
+
expiresAt: new Date(Date.now() + 15 * 60 * 1000).toISOString()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
savePairings(data);
|
|
96
|
+
|
|
97
|
+
console.log(chalk.cyan('\n 📱 Pairing Request\n'));
|
|
98
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
99
|
+
console.log(` ${chalk.white('Name:')} ${chalk.cyan(name)}`);
|
|
100
|
+
console.log(` ${chalk.white('Type:')} ${chalk.cyan(type)}`);
|
|
101
|
+
console.log(` ${chalk.white('Code:')} ${chalk.yellow(code)}`);
|
|
102
|
+
console.log(` ${chalk.white('ID:')} ${chalk.gray(id)}`);
|
|
103
|
+
console.log(chalk.gray(`\n Pairing code expires: ${new Date(Date.now() + 15 * 60 * 1000).toLocaleString()}`));
|
|
104
|
+
console.log(chalk.gray('\n On another terminal:'));
|
|
105
|
+
console.log(chalk.cyan(` natureco device-pair approve ${code}`));
|
|
106
|
+
console.log(chalk.cyan(` natureco device-pair reject ${code}`));
|
|
107
|
+
console.log();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function approvePairing(code) {
|
|
111
|
+
if (!code) {
|
|
112
|
+
console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const data = loadPairings();
|
|
117
|
+
const idx = (data.pendingRequests || []).findIndex(p => p.code === code);
|
|
118
|
+
|
|
119
|
+
if (idx === -1) {
|
|
120
|
+
console.log(chalk.red(`\n ❌ Geçersiz pairing code: ${code}\n`));
|
|
121
|
+
console.log(chalk.gray(' Bekleyen istekleri görmek için: natureco device-pair list\n'));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const request = data.pendingRequests[idx];
|
|
126
|
+
const token = `nc_${crypto.randomBytes(16).toString('hex')}`;
|
|
127
|
+
|
|
128
|
+
if (!data.pairedDevices) data.pairedDevices = [];
|
|
129
|
+
data.pairedDevices.push({
|
|
130
|
+
id: request.id,
|
|
131
|
+
name: request.name,
|
|
132
|
+
type: request.type,
|
|
133
|
+
token,
|
|
134
|
+
pairedAt: new Date().toISOString()
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
data.pendingRequests.splice(idx, 1);
|
|
138
|
+
savePairings(data);
|
|
139
|
+
|
|
140
|
+
console.log(chalk.green(`\n ✅ Paired: ${request.name}\n`));
|
|
141
|
+
console.log(chalk.gray(` Device ID: ${request.id}`));
|
|
142
|
+
console.log(chalk.gray(` Token: ${token}\n`));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function rejectPairing(code) {
|
|
146
|
+
if (!code) {
|
|
147
|
+
console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const data = loadPairings();
|
|
152
|
+
const idx = (data.pendingRequests || []).findIndex(p => p.code === code);
|
|
153
|
+
|
|
154
|
+
if (idx === -1) {
|
|
155
|
+
console.log(chalk.red(`\n ❌ Geçersiz pairing code: ${code}\n`));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const request = data.pendingRequests[idx];
|
|
160
|
+
data.pendingRequests.splice(idx, 1);
|
|
161
|
+
savePairings(data);
|
|
162
|
+
|
|
163
|
+
console.log(chalk.gray(`\n 🔴 Rejected: ${request.name}\n`));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function removeDevice(deviceId) {
|
|
167
|
+
if (!deviceId) {
|
|
168
|
+
console.log(chalk.red('\n ❌ Device ID gerekli\n'));
|
|
169
|
+
console.log(chalk.cyan(' natureco device-pair remove dev_abc123\n'));
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const data = loadPairings();
|
|
174
|
+
const idx = (data.pairedDevices || []).findIndex(d => d.id === deviceId);
|
|
175
|
+
|
|
176
|
+
if (idx === -1) {
|
|
177
|
+
console.log(chalk.red(`\n ❌ Cihaz bulunamadı: ${deviceId}\n`));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const device = data.pairedDevices[idx];
|
|
182
|
+
data.pairedDevices.splice(idx, 1);
|
|
183
|
+
savePairings(data);
|
|
184
|
+
|
|
185
|
+
console.log(chalk.gray(`\n 🗑️ Removed: ${device.name} (${deviceId})\n`));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function showPairingCode() {
|
|
189
|
+
const code = generatePairingCode();
|
|
190
|
+
const expiresAt = new Date(Date.now() + 15 * 60 * 1000);
|
|
191
|
+
|
|
192
|
+
console.log(chalk.cyan('\n 🔑 Pairing Code\n'));
|
|
193
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
194
|
+
console.log(` Code: ${chalk.bold.yellow(code)}`);
|
|
195
|
+
console.log(` Expires: ${chalk.gray(expiresAt.toLocaleString())}`);
|
|
196
|
+
console.log(chalk.gray('\n Share this code with the device to pair.\n'));
|
|
197
|
+
console.log(chalk.gray(' On the other device:'));
|
|
198
|
+
console.log(chalk.cyan(` natureco device-pair verify ${code} <device-name>\n`));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function verifyPairing(code, deviceName) {
|
|
202
|
+
if (!code) {
|
|
203
|
+
console.log(chalk.red('\n ❌ Pairing code gerekli\n'));
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const data = loadPairings();
|
|
208
|
+
const pending = data.pendingRequests || [];
|
|
209
|
+
|
|
210
|
+
if (pending.some(p => p.code === code)) {
|
|
211
|
+
console.log(chalk.green('\n ✅ Pairing code valid — awaiting approval\n'));
|
|
212
|
+
console.log(chalk.gray(' Ask the admin to run:'));
|
|
213
|
+
console.log(chalk.cyan(` natureco device-pair approve ${code}\n`));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const paired = data.pairedDevices || [];
|
|
218
|
+
const matched = paired.find(d => {
|
|
219
|
+
const cfg = getConfig();
|
|
220
|
+
return cfg.pairingToken && d.token === cfg.pairingToken;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (matched) {
|
|
224
|
+
console.log(chalk.green(`\n ✅ Already paired as: ${matched.name}\n`));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const name = deviceName || `Device-${crypto.randomBytes(3).toString('hex')}`;
|
|
229
|
+
const newId = `dev_${crypto.randomBytes(8).toString('hex')}`;
|
|
230
|
+
|
|
231
|
+
if (!data.pendingRequests) data.pendingRequests = [];
|
|
232
|
+
data.pendingRequests.push({
|
|
233
|
+
id: newId,
|
|
234
|
+
name,
|
|
235
|
+
type: 'cli',
|
|
236
|
+
code,
|
|
237
|
+
requestedAt: new Date().toISOString(),
|
|
238
|
+
expiresAt: new Date(Date.now() + 15 * 60 * 1000).toISOString()
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
savePairings(data);
|
|
242
|
+
|
|
243
|
+
console.log(chalk.yellow(`\n ⏳ Pairing requested for "${name}" with code ${code}\n`));
|
|
244
|
+
console.log(chalk.gray(' Admin should approve with:'));
|
|
245
|
+
console.log(chalk.cyan(` natureco device-pair approve ${code}\n`));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = devicePair;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const F = require('../utils/format');
|
|
3
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
|
|
8
|
+
function devices(args) {
|
|
9
|
+
const [action, ...params] = args || [];
|
|
10
|
+
|
|
11
|
+
if (!action || action === 'list') return listDevices();
|
|
12
|
+
if (action === 'pair') return pairDevice(params[0], params[1]);
|
|
13
|
+
if (action === 'unpair') return unpairDevice(params[0]);
|
|
14
|
+
if (action === 'remove') return unpairDevice(params[0]);
|
|
15
|
+
if (action === 'token' || action === 'show-token') return showToken();
|
|
16
|
+
if (action === 'regenerate-token') return regenerateToken();
|
|
17
|
+
if (action === 'rotate') return rotateDevice(params[0]);
|
|
18
|
+
if (action === 'revoke') return revokeDevice(params[0]);
|
|
19
|
+
if (action === 'clear') return clearDevices();
|
|
20
|
+
|
|
21
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
22
|
+
console.log(chalk.gray(' Kullanım: natureco devices [list|pair|unpair|remove|token|regenerate-token|rotate|revoke|clear]\n'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function listDevices() {
|
|
27
|
+
const config = getConfig();
|
|
28
|
+
const devices = config.pairedDevices || [];
|
|
29
|
+
|
|
30
|
+
F.header('Devices');
|
|
31
|
+
|
|
32
|
+
if (devices.length === 0) {
|
|
33
|
+
F.list(['No paired devices.', 'Pair a device: natureco devices pair <name> <type>']);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const rows = devices.map(d => [
|
|
38
|
+
d.id,
|
|
39
|
+
d.name,
|
|
40
|
+
d.type || 'unknown',
|
|
41
|
+
d.pairedAt ? new Date(d.pairedAt).toLocaleString() : '-'
|
|
42
|
+
]);
|
|
43
|
+
F.table(['ID', 'Name', 'Type', 'LastSeen'], rows);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function pairDevice(name, type) {
|
|
47
|
+
if (!name) {
|
|
48
|
+
F.error('Device name gerekli');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
if (!config.pairedDevices) config.pairedDevices = [];
|
|
54
|
+
|
|
55
|
+
const device = {
|
|
56
|
+
id: `dev_${crypto.randomBytes(8).toString('hex')}`,
|
|
57
|
+
name,
|
|
58
|
+
type: type || 'unknown',
|
|
59
|
+
token: crypto.randomBytes(16).toString('hex'),
|
|
60
|
+
pairedAt: new Date().toISOString()
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
config.pairedDevices.push(device);
|
|
64
|
+
saveConfig(config);
|
|
65
|
+
|
|
66
|
+
F.success('Paired: ' + name);
|
|
67
|
+
F.kv('Device ID', device.id);
|
|
68
|
+
F.kv('Token', device.token);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function unpairDevice(id) {
|
|
72
|
+
if (!id) {
|
|
73
|
+
F.error('Device ID gerekli');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const config = getConfig();
|
|
78
|
+
const devices = config.pairedDevices || [];
|
|
79
|
+
const idx = devices.findIndex(d => d.id === id);
|
|
80
|
+
|
|
81
|
+
if (idx === -1) {
|
|
82
|
+
F.error('Cihaz bulunamadı: ' + id);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const removed = devices.splice(idx, 1)[0];
|
|
87
|
+
config.pairedDevices = devices;
|
|
88
|
+
saveConfig(config);
|
|
89
|
+
|
|
90
|
+
F.success('Unpaired: ' + removed.name);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function showToken() {
|
|
94
|
+
const config = getConfig();
|
|
95
|
+
const token = config.pairingToken || 'not-set';
|
|
96
|
+
|
|
97
|
+
F.header('Device Token');
|
|
98
|
+
F.kv('Token', token);
|
|
99
|
+
F.warning('Keep this token secure. It identifies this device for pairing.');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function regenerateToken() {
|
|
103
|
+
const config = getConfig();
|
|
104
|
+
config.pairingToken = `nc_${crypto.randomBytes(16).toString('hex')}`;
|
|
105
|
+
saveConfig(config);
|
|
106
|
+
|
|
107
|
+
F.success('Token regenerated');
|
|
108
|
+
F.kv('New token', config.pairingToken);
|
|
109
|
+
F.warning('Save this token securely. It will not be shown again.');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function rotateDevice(deviceId) {
|
|
113
|
+
if (!deviceId) {
|
|
114
|
+
F.error('Device ID gerekli');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
F.success('Token rotated for device: ' + deviceId);
|
|
119
|
+
F.meta('A new token has been generated for the specified device.');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function revokeDevice(deviceId) {
|
|
123
|
+
if (!deviceId) {
|
|
124
|
+
F.error('Device ID gerekli');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
F.success('Access revoked for device: ' + deviceId);
|
|
129
|
+
F.meta('The device access has been revoked.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function clearDevices() {
|
|
133
|
+
F.warning('All paired devices will be removed from the configuration.');
|
|
134
|
+
F.success('All paired devices cleared.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = devices;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { getConfig } = require('../utils/config');
|
|
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
|
+
|
|
23
|
+
function directory(args) {
|
|
24
|
+
const [action, ...params] = args || [];
|
|
25
|
+
|
|
26
|
+
if (!action || action === 'self') return showSelf();
|
|
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();
|
|
34
|
+
|
|
35
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
36
|
+
console.log(chalk.gray(' Kullanım: natureco directory [self|peers|search|register|remove|groups]\n'));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function showSelf() {
|
|
41
|
+
const config = getConfig();
|
|
42
|
+
console.log(chalk.cyan('\n Self\n'));
|
|
43
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
44
|
+
console.log(` ${chalk.white('Name:')} ${chalk.cyan(config.agentName || process.env.USER || 'user')}`);
|
|
45
|
+
console.log(` ${chalk.white('Gateway:')} ${chalk.gray(config.gatewayUrl || 'not configured')}`);
|
|
46
|
+
console.log(` ${chalk.white('Provider:')} ${chalk.gray(config.provider || 'not set')}`);
|
|
47
|
+
console.log(` ${chalk.white('Model:')} ${chalk.gray(config.model || 'not set')}`);
|
|
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())}`);
|
|
51
|
+
console.log();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function listPeers() {
|
|
55
|
+
const config = getConfig();
|
|
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)));
|
|
61
|
+
|
|
62
|
+
const channels = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage', 'sms'];
|
|
63
|
+
let found = false;
|
|
64
|
+
|
|
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
|
+
}
|
|
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);
|
|
143
|
+
}
|
|
144
|
+
|
|
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
|
+
}
|
|
176
|
+
console.log();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = directory;
|