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/models.js
CHANGED
|
@@ -116,9 +116,11 @@ async function models(args) {
|
|
|
116
116
|
}
|
|
117
117
|
if (action === 'aliases') return manageAliases(params);
|
|
118
118
|
if (action === 'fallbacks') return manageFallbacks(params);
|
|
119
|
+
if (action === 'set-image') return setImageModel(params[0]);
|
|
120
|
+
if (action === 'image-fallbacks') return manageImageFallbacks(params);
|
|
119
121
|
|
|
120
122
|
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
121
|
-
console.log(chalk.gray(' Kullanım: natureco models [list|set|scan|aliases|fallbacks]\n'));
|
|
123
|
+
console.log(chalk.gray(' Kullanım: natureco models [list|set|scan|aliases|fallbacks|set-image|image-fallbacks]\n'));
|
|
122
124
|
process.exit(1);
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -469,6 +471,42 @@ function manageFallbacks(params) {
|
|
|
469
471
|
console.log(chalk.gray('\n Kullanım: natureco models fallbacks [list|set <model-id>|clear]\n'));
|
|
470
472
|
}
|
|
471
473
|
|
|
474
|
+
function setImageModel(modelId) {
|
|
475
|
+
if (!modelId) {
|
|
476
|
+
console.log(chalk.cyan('\n Current image model: ') + chalk.white(getConfig().imageModel || 'not set'));
|
|
477
|
+
console.log(chalk.gray('\n Usage: natureco models set-image <model-id>\n'));
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const config = getConfig();
|
|
481
|
+
config.imageModel = modelId;
|
|
482
|
+
saveConfig(config);
|
|
483
|
+
console.log(chalk.green(`\n ✓ Image model set: ${modelId}\n`));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function manageImageFallbacks(params) {
|
|
487
|
+
const config = getConfig();
|
|
488
|
+
if (params.length === 0 || params[0] === 'list') {
|
|
489
|
+
console.log(chalk.cyan.bold('\n Image Model Fallbacks\n'));
|
|
490
|
+
console.log(chalk.gray(' Primary : ') + chalk.white(config.imageModel || 'not set'));
|
|
491
|
+
console.log(chalk.gray(' Fallback : ') + chalk.white(config.imageFallbackModel || 'not set'));
|
|
492
|
+
console.log(chalk.gray('\n Set: natureco models image-fallbacks set <model-id>'));
|
|
493
|
+
console.log(chalk.gray(' Clear: natureco models image-fallbacks clear\n'));
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (params[0] === 'set' && params[1]) {
|
|
497
|
+
config.imageFallbackModel = params[1];
|
|
498
|
+
saveConfig(config);
|
|
499
|
+
console.log(chalk.green(`\n ✓ Image fallback set: ${params[1]}\n`));
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (params[0] === 'clear') {
|
|
503
|
+
delete config.imageFallbackModel;
|
|
504
|
+
saveConfig(config);
|
|
505
|
+
console.log(chalk.green('\n ✓ Image fallback cleared\n'));
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
472
510
|
function resolveModel(input) {
|
|
473
511
|
const config = getConfig();
|
|
474
512
|
const aliases = config.modelAliases || {};
|
package/src/commands/node.js
CHANGED
|
@@ -1,98 +1,98 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
2
4
|
const os = require('os');
|
|
3
|
-
const http = require('http');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const NODES_FILE = path.join(os.homedir(), '.natureco', 'nodes.json');
|
|
6
7
|
|
|
7
|
-
function
|
|
8
|
+
function loadNodes() {
|
|
9
|
+
if (!fs.existsSync(NODES_FILE)) return {};
|
|
10
|
+
try { return JSON.parse(fs.readFileSync(NODES_FILE, 'utf8')); }
|
|
11
|
+
catch { return {}; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function saveNodes(nodes) {
|
|
15
|
+
const dir = path.dirname(NODES_FILE);
|
|
16
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
fs.writeFileSync(NODES_FILE, JSON.stringify(nodes, null, 2), 'utf8');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function node(args) {
|
|
8
21
|
const [action, ...params] = args || [];
|
|
9
22
|
|
|
10
|
-
if (!action || action === 'status') return
|
|
11
|
-
if (action === '
|
|
12
|
-
if (action === '
|
|
13
|
-
if (action === '
|
|
23
|
+
if (!action || action === 'status') return cmdStatus(params[0]);
|
|
24
|
+
if (action === 'run') return cmdRun(params[0], params.slice(1));
|
|
25
|
+
if (action === 'install') return cmdInstall();
|
|
26
|
+
if (action === 'uninstall') return cmdUninstall(params[0]);
|
|
27
|
+
if (action === 'stop') return cmdStop(params[0]);
|
|
28
|
+
if (action === 'restart') return cmdRestart(params[0]);
|
|
14
29
|
|
|
15
|
-
console.log(chalk.red(`\n
|
|
16
|
-
console.log(chalk.gray('
|
|
30
|
+
console.log(chalk.red(`\n Unknown node action: ${action}\n`));
|
|
31
|
+
console.log(chalk.gray(' Usage: natureco node <action> [params]'));
|
|
32
|
+
console.log(chalk.gray(' Actions: run <id>, status <id>, install, uninstall, stop <id>, restart <id>\n'));
|
|
17
33
|
process.exit(1);
|
|
18
34
|
}
|
|
19
35
|
|
|
20
|
-
function
|
|
21
|
-
console.log(chalk.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.log(
|
|
25
|
-
console.log(
|
|
26
|
-
console.log(
|
|
27
|
-
console.log(` ${chalk.white('CPU:')} ${os.cpus()[0]?.model || 'unknown'}`);
|
|
28
|
-
console.log(chalk.gray('\n Start: ') + chalk.cyan('natureco node start [port]'));
|
|
29
|
-
console.log(chalk.gray(' Info: ') + chalk.cyan('natureco node info'));
|
|
30
|
-
console.log();
|
|
36
|
+
function cmdRun(id) {
|
|
37
|
+
if (!id) { console.log(chalk.red('\n Usage: natureco node run <id>\n')); process.exit(1); }
|
|
38
|
+
const nodes = loadNodes();
|
|
39
|
+
const n = nodes[id];
|
|
40
|
+
if (!n) { console.log(chalk.yellow(`\n Node "${id}" not found.\n`)); return; }
|
|
41
|
+
console.log(chalk.cyan(`\n Running command on node "${id}"...\n`));
|
|
42
|
+
console.log(chalk.gray(' (Stub — command execution not implemented)\n'));
|
|
31
43
|
}
|
|
32
44
|
|
|
33
|
-
function
|
|
34
|
-
if (
|
|
35
|
-
|
|
45
|
+
function cmdStatus(id) {
|
|
46
|
+
if (!id) { console.log(chalk.red('\n Usage: natureco node status <id>\n')); process.exit(1); }
|
|
47
|
+
const nodes = loadNodes();
|
|
48
|
+
const n = nodes[id];
|
|
49
|
+
|
|
50
|
+
console.log(chalk.cyan(`\n Node: ${id || '(all)'}\n`));
|
|
51
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
52
|
+
|
|
53
|
+
if (!n) {
|
|
54
|
+
console.log(chalk.yellow(` Node "${id}" not found.\n`));
|
|
36
55
|
return;
|
|
37
56
|
}
|
|
38
57
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
hostname: os.hostname(),
|
|
46
|
-
platform: process.platform,
|
|
47
|
-
node: process.version,
|
|
48
|
-
uptime: Math.floor(process.uptime()),
|
|
49
|
-
memory: { free: os.freemem(), total: os.totalmem() },
|
|
50
|
-
cpus: os.cpus().length,
|
|
51
|
-
loadavg: os.loadavg()
|
|
52
|
-
}));
|
|
53
|
-
} else {
|
|
54
|
-
res.writeHead(404);
|
|
55
|
-
res.end('Not Found');
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
server.listen(port, () => {
|
|
60
|
-
nodeServer = server;
|
|
61
|
-
nodeServer.port = server.address().port;
|
|
62
|
-
console.log(chalk.green(`\n ✅ Node host running on http://localhost:${nodeServer.port}\n`));
|
|
63
|
-
console.log(chalk.gray(` Health endpoint: http://localhost:${nodeServer.port}/health\n`));
|
|
64
|
-
console.log(chalk.gray(' Press Ctrl+C to stop.\n'));
|
|
65
|
-
});
|
|
58
|
+
console.log(` ${chalk.white('ID:')} ${chalk.cyan(n.id || id)}`);
|
|
59
|
+
console.log(` ${chalk.white('Host:')} ${chalk.white(n.host || n.hostname || '—')}`);
|
|
60
|
+
console.log(` ${chalk.white('Port:')} ${chalk.white(n.port || '—')}`);
|
|
61
|
+
console.log(` ${chalk.white('Status:')} ${n.online ? chalk.green('online') : chalk.gray('offline')}`);
|
|
62
|
+
console.log(` ${chalk.white('Version:')} ${chalk.gray(n.version || '—')}`);
|
|
63
|
+
console.log('');
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
nodeServer.close(() => {
|
|
74
|
-
console.log(chalk.gray('\n 🛑 Node host stopped\n'));
|
|
75
|
-
nodeServer = null;
|
|
76
|
-
});
|
|
66
|
+
function cmdInstall() {
|
|
67
|
+
console.log(chalk.cyan('\n Installing node software...\n'));
|
|
68
|
+
console.log(chalk.gray(' (Stub — installation not implemented)\n'));
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
function
|
|
80
|
-
console.log(chalk.
|
|
81
|
-
|
|
82
|
-
console.log(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
console.log(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
console.log(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(
|
|
95
|
-
|
|
71
|
+
function cmdUninstall(id) {
|
|
72
|
+
if (!id) { console.log(chalk.red('\n Usage: natureco node uninstall <id>\n')); process.exit(1); }
|
|
73
|
+
const nodes = loadNodes();
|
|
74
|
+
if (!nodes[id]) { console.log(chalk.yellow(`\n Node "${id}" not found.\n`)); return; }
|
|
75
|
+
delete nodes[id];
|
|
76
|
+
saveNodes(nodes);
|
|
77
|
+
console.log(chalk.gray(`\n Node "${id}" uninstalled.\n`));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function cmdStop(id) {
|
|
81
|
+
if (!id) { console.log(chalk.red('\n Usage: natureco node stop <id>\n')); process.exit(1); }
|
|
82
|
+
const nodes = loadNodes();
|
|
83
|
+
if (!nodes[id]) { console.log(chalk.yellow(`\n Node "${id}" not found.\n`)); return; }
|
|
84
|
+
nodes[id].online = false;
|
|
85
|
+
saveNodes(nodes);
|
|
86
|
+
console.log(chalk.gray(`\n Node "${id}" stopped.\n`));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function cmdRestart(id) {
|
|
90
|
+
if (!id) { console.log(chalk.red('\n Usage: natureco node restart <id>\n')); process.exit(1); }
|
|
91
|
+
const nodes = loadNodes();
|
|
92
|
+
if (!nodes[id]) { console.log(chalk.yellow(`\n Node "${id}" not found.\n`)); return; }
|
|
93
|
+
nodes[id].online = true;
|
|
94
|
+
saveNodes(nodes);
|
|
95
|
+
console.log(chalk.gray(`\n Node "${id}" restarted.\n`));
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
module.exports =
|
|
98
|
+
module.exports = node;
|
package/src/commands/nodes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const F = require('../utils/format');
|
|
2
3
|
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
4
|
const crypto = require('crypto');
|
|
4
5
|
|
|
@@ -11,9 +12,151 @@ function nodes(args) {
|
|
|
11
12
|
if (action === 'reject') return rejectNode(params[0]);
|
|
12
13
|
if (action === 'remove') return removeNode(params[0]);
|
|
13
14
|
if (action === 'rename') return renameNode(params[0], params.slice(1).join(' '));
|
|
15
|
+
if (action === 'invoke') return invokeNode(params[0], params[1], params.slice(2));
|
|
16
|
+
if (action === 'notify') return notifyNode(params[0], params.slice(1).join(' '));
|
|
17
|
+
if (action === 'push') return pushNode(params[0]);
|
|
18
|
+
if (action === 'canvas') {
|
|
19
|
+
const sub = params[0];
|
|
20
|
+
if (sub === 'a2ui') {
|
|
21
|
+
if (params[1] === 'push') {
|
|
22
|
+
const nodeId = params[2];
|
|
23
|
+
const url = params[3];
|
|
24
|
+
if (!nodeId || !url) {
|
|
25
|
+
F.error('Node ID and URL required');
|
|
26
|
+
F.info('Usage: natureco nodes canvas a2ui push <nodeId> <url>');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
F.info(`Would push A2UI from ${url} to node ${nodeId}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (params[1] === 'reset') {
|
|
33
|
+
const id = params[2] || 'default';
|
|
34
|
+
F.info(`Would reset A2UI for node ${id}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
F.error(`Unknown canvas a2ui command: ${params[1]}`);
|
|
38
|
+
F.info('Usage: natureco nodes canvas a2ui [push|reset]');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
if (sub === 'snapshot') {
|
|
42
|
+
const nodeId = params[1];
|
|
43
|
+
if (!nodeId) {
|
|
44
|
+
F.error('Node ID required');
|
|
45
|
+
F.info('Usage: natureco nodes canvas snapshot <nodeId>');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
F.info(`Would snapshot canvas on node ${nodeId}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (sub === 'present') {
|
|
52
|
+
const nodeId = params[1];
|
|
53
|
+
const url = params[2];
|
|
54
|
+
if (!nodeId || !url) {
|
|
55
|
+
F.error('Node ID and URL required');
|
|
56
|
+
F.info('Usage: natureco nodes canvas present <nodeId> <url>');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
F.info(`Would present ${url} on node ${nodeId}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (sub === 'hide') {
|
|
63
|
+
const nodeId = params[1];
|
|
64
|
+
if (!nodeId) {
|
|
65
|
+
F.error('Node ID required');
|
|
66
|
+
F.info('Usage: natureco nodes canvas hide <nodeId>');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
F.info(`Would hide canvas on node ${nodeId}`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (sub === 'navigate') {
|
|
73
|
+
const nodeId = params[1];
|
|
74
|
+
const url = params[2];
|
|
75
|
+
if (!nodeId || !url) {
|
|
76
|
+
F.error('Node ID and URL required');
|
|
77
|
+
F.info('Usage: natureco nodes canvas navigate <nodeId> <url>');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
F.info(`Would navigate node ${nodeId} to ${url}`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (sub === 'eval') {
|
|
84
|
+
const nodeId = params[1];
|
|
85
|
+
const code = params.slice(2).join(' ');
|
|
86
|
+
if (!nodeId || !code) {
|
|
87
|
+
F.error('Node ID and code required');
|
|
88
|
+
F.info('Usage: natureco nodes canvas eval <nodeId> <code>');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
F.info(`Would eval on node ${nodeId}: ${code}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
return canvasNode(sub, params[1]);
|
|
95
|
+
}
|
|
96
|
+
if (action === 'camera') {
|
|
97
|
+
const sub = params[0];
|
|
98
|
+
if (sub === 'list') {
|
|
99
|
+
const nodeId = params[1];
|
|
100
|
+
F.info(`Would list cameras${nodeId ? ' on node ' + nodeId : ''}`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (sub === 'snap') {
|
|
104
|
+
const nodeId = params[1];
|
|
105
|
+
if (!nodeId) {
|
|
106
|
+
F.error('Node ID required');
|
|
107
|
+
F.info('Usage: natureco nodes camera snap <nodeId>');
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
F.info(`Would take snapshot on node ${nodeId}`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (sub === 'clip') {
|
|
114
|
+
const nodeId = params[1];
|
|
115
|
+
if (!nodeId) {
|
|
116
|
+
F.error('Node ID required');
|
|
117
|
+
F.info('Usage: natureco nodes camera clip <nodeId>');
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
F.info(`Would record clip on node ${nodeId}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
return cameraNode(sub, params[1]);
|
|
124
|
+
}
|
|
125
|
+
if (action === 'screen') {
|
|
126
|
+
const sub = params[0];
|
|
127
|
+
if (sub === 'record') {
|
|
128
|
+
const nodeId = params[1];
|
|
129
|
+
if (!nodeId) {
|
|
130
|
+
F.error('Node ID required');
|
|
131
|
+
F.info('Usage: natureco nodes screen record <nodeId>');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
F.info(`Would start screen recording on node ${nodeId}`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
return screenNode(sub, params[1]);
|
|
138
|
+
}
|
|
139
|
+
if (action === 'location') {
|
|
140
|
+
const sub = params[0];
|
|
141
|
+
if (sub === 'get') {
|
|
142
|
+
const nodeId = params[1];
|
|
143
|
+
if (!nodeId) {
|
|
144
|
+
F.error('Node ID required');
|
|
145
|
+
F.info('Usage: natureco nodes location get <nodeId>');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
F.kv('Node', nodeId);
|
|
149
|
+
F.kv('Latitude', '41.0082 (mock)');
|
|
150
|
+
F.kv('Longitude', '28.9784 (mock)');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
return locationNode(sub);
|
|
154
|
+
}
|
|
155
|
+
if (action === 'status') return nodeStatus(params[0]);
|
|
156
|
+
if (action === 'describe') return nodeDescribe(params[0]);
|
|
14
157
|
|
|
15
|
-
|
|
16
|
-
|
|
158
|
+
F.error(`Unknown command: ${action}`);
|
|
159
|
+
F.info('Usage: natureco nodes [list|pair|approve|reject|remove|rename|invoke|notify|push|canvas|camera|screen|location|status|describe]');
|
|
17
160
|
process.exit(1);
|
|
18
161
|
}
|
|
19
162
|
|
|
@@ -21,26 +164,26 @@ function listNodes() {
|
|
|
21
164
|
const config = getConfig();
|
|
22
165
|
const nodes = config.pairedNodes || [];
|
|
23
166
|
|
|
24
|
-
|
|
25
|
-
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
167
|
+
F.header('Nodes');
|
|
26
168
|
|
|
27
169
|
if (nodes.length === 0) {
|
|
28
|
-
|
|
170
|
+
F.info('No paired nodes.');
|
|
29
171
|
return;
|
|
30
172
|
}
|
|
31
173
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
174
|
+
F.table(['ID', 'Name', 'Status', 'LastSeen'],
|
|
175
|
+
nodes.map(n => [
|
|
176
|
+
n.id,
|
|
177
|
+
n.name || n.id,
|
|
178
|
+
'online (mock)',
|
|
179
|
+
n.pairedAt ? new Date(n.pairedAt).toLocaleString() : '—',
|
|
180
|
+
])
|
|
181
|
+
);
|
|
39
182
|
}
|
|
40
183
|
|
|
41
184
|
function pairNode(url) {
|
|
42
185
|
if (!url) {
|
|
43
|
-
|
|
186
|
+
F.error('Node URL required');
|
|
44
187
|
process.exit(1);
|
|
45
188
|
}
|
|
46
189
|
|
|
@@ -53,20 +196,22 @@ function pairNode(url) {
|
|
|
53
196
|
config.pairedNodes.push({ id, url, key, name: url, pairedAt: new Date().toISOString() });
|
|
54
197
|
saveConfig(config);
|
|
55
198
|
|
|
56
|
-
|
|
199
|
+
F.success(`Node paired: ${url}`);
|
|
200
|
+
F.info('Use the following link or scan the QR code in the NatureCo mobile app to link this device.');
|
|
201
|
+
F.kv('Pair Code', key);
|
|
57
202
|
}
|
|
58
203
|
|
|
59
204
|
function approveNode(id) {
|
|
60
|
-
|
|
205
|
+
F.success(`Node approved: ${id}`);
|
|
61
206
|
}
|
|
62
207
|
|
|
63
208
|
function rejectNode(id) {
|
|
64
|
-
|
|
209
|
+
F.error(`Node rejected: ${id}`);
|
|
65
210
|
}
|
|
66
211
|
|
|
67
212
|
function removeNode(id) {
|
|
68
213
|
if (!id) {
|
|
69
|
-
|
|
214
|
+
F.error('Node ID required');
|
|
70
215
|
process.exit(1);
|
|
71
216
|
}
|
|
72
217
|
|
|
@@ -75,32 +220,143 @@ function removeNode(id) {
|
|
|
75
220
|
const idx = nodes.findIndex(n => n.id === id);
|
|
76
221
|
|
|
77
222
|
if (idx === -1) {
|
|
78
|
-
|
|
223
|
+
F.error(`Node not found: ${id}`);
|
|
79
224
|
process.exit(1);
|
|
80
225
|
}
|
|
81
226
|
|
|
82
227
|
nodes.splice(idx, 1);
|
|
83
228
|
config.pairedNodes = nodes;
|
|
84
229
|
saveConfig(config);
|
|
85
|
-
|
|
230
|
+
F.success(`Node removed: ${id}`);
|
|
86
231
|
}
|
|
87
232
|
|
|
88
233
|
function renameNode(id, name) {
|
|
89
234
|
if (!id || !name) {
|
|
90
|
-
|
|
235
|
+
F.error('Node ID and name required');
|
|
91
236
|
process.exit(1);
|
|
92
237
|
}
|
|
93
238
|
|
|
94
239
|
const config = getConfig();
|
|
95
240
|
const node = (config.pairedNodes || []).find(n => n.id === id);
|
|
96
241
|
if (!node) {
|
|
97
|
-
|
|
242
|
+
F.error(`Node not found: ${id}`);
|
|
98
243
|
process.exit(1);
|
|
99
244
|
}
|
|
100
245
|
|
|
101
246
|
node.name = name;
|
|
102
247
|
saveConfig(config);
|
|
103
|
-
|
|
248
|
+
F.success(`Node renamed: ${name}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function invokeNode(nodeId, method, params) {
|
|
252
|
+
if (!nodeId || !method) {
|
|
253
|
+
F.error('Node ID and method required');
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
F.kv('Node', nodeId);
|
|
257
|
+
F.kv('Method', method);
|
|
258
|
+
F.kv('Params', (params || []).join(', '));
|
|
259
|
+
F.kv('Result', '[mock] invocation sent');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function notifyNode(nodeId, message) {
|
|
263
|
+
if (!nodeId || !message) {
|
|
264
|
+
F.error('Node ID and message required');
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
F.info(`Notify: ${nodeId} → "${message}"`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function pushNode(nodeId) {
|
|
271
|
+
if (!nodeId) {
|
|
272
|
+
F.error('Node ID required');
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
F.info(`Push config to: ${nodeId}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function canvasNode(nodeId, sessionId) {
|
|
279
|
+
if (!nodeId) {
|
|
280
|
+
F.error('Node ID required');
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
F.info(`Canvas share: ${nodeId}${sessionId ? ' session: ' + sessionId : ''}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function cameraNode(nodeId, action) {
|
|
287
|
+
if (!nodeId) {
|
|
288
|
+
F.error('Node ID required');
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
const act = action || 'open';
|
|
292
|
+
F.info(`Camera ${act}: ${nodeId}`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function screenNode(nodeId, action) {
|
|
296
|
+
if (!nodeId) {
|
|
297
|
+
F.error('Node ID required');
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
const act = action || 'view';
|
|
301
|
+
F.info(`Screen ${act}: ${nodeId}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function locationNode(nodeId) {
|
|
305
|
+
if (!nodeId) {
|
|
306
|
+
F.error('Node ID required');
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
F.kv('Node', nodeId);
|
|
310
|
+
F.kv('Latitude', '41.0082 (mock)');
|
|
311
|
+
F.kv('Longitude', '28.9784 (mock)');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function nodeStatus(nodeId) {
|
|
315
|
+
if (!nodeId) {
|
|
316
|
+
F.error('Node ID required');
|
|
317
|
+
F.info('Usage: natureco nodes status <nodeId>');
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
const config = getConfig();
|
|
321
|
+
const node = (config.pairedNodes || []).find(n => n.id === nodeId || n.name === nodeId);
|
|
322
|
+
if (!node) {
|
|
323
|
+
F.warning(`Node not found: ${nodeId}`);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
F.header(`Node Status: ${node.name || node.id}`);
|
|
327
|
+
F.kv('ID', node.id);
|
|
328
|
+
F.kv('Name', node.name);
|
|
329
|
+
F.kv('URL', node.url || 'local');
|
|
330
|
+
F.kv('Status', 'connected (mock)');
|
|
331
|
+
F.kv('Latency', '~12ms (mock)');
|
|
332
|
+
F.kv('Uptime', '~3h (mock)');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function nodeDescribe(nodeId) {
|
|
336
|
+
if (!nodeId) {
|
|
337
|
+
F.error('Node ID required');
|
|
338
|
+
F.info('Usage: natureco nodes describe <nodeId>');
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
const config = getConfig();
|
|
342
|
+
const node = (config.pairedNodes || []).find(n => n.id === nodeId || n.name === nodeId);
|
|
343
|
+
if (!node) {
|
|
344
|
+
F.warning(`Node not found: ${nodeId}`);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
F.header(`Node Details: ${node.name || node.id}`);
|
|
348
|
+
F.table(['Property', 'Value'], [
|
|
349
|
+
['ID', node.id],
|
|
350
|
+
['Name', node.name],
|
|
351
|
+
['URL', node.url || 'local'],
|
|
352
|
+
['Key', node.key ? node.key.substring(0, 8) + '...' : 'none'],
|
|
353
|
+
['Paired At', node.pairedAt ? new Date(node.pairedAt).toLocaleString() : 'unknown'],
|
|
354
|
+
['OS', 'linux (mock)'],
|
|
355
|
+
['Version', '2.23.32 (mock)'],
|
|
356
|
+
['CPU', '4 vCPU (mock)'],
|
|
357
|
+
['Memory', '8 GB (mock)'],
|
|
358
|
+
['Services', 'gateway, mcp, file-sync (mock)'],
|
|
359
|
+
]);
|
|
104
360
|
}
|
|
105
361
|
|
|
106
362
|
module.exports = nodes;
|