natureco-cli 2.23.30 → 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.
Files changed (67) hide show
  1. package/bin/natureco.js +166 -163
  2. package/package.json +1 -1
  3. package/src/commands/acp.js +39 -0
  4. package/src/commands/admin-rpc.js +83 -0
  5. package/src/commands/agent.js +214 -23
  6. package/src/commands/agents.js +114 -30
  7. package/src/commands/approvals.js +172 -11
  8. package/src/commands/browser.js +815 -0
  9. package/src/commands/capability.js +195 -22
  10. package/src/commands/channels.js +422 -267
  11. package/src/commands/chat.js +5 -8
  12. package/src/commands/clawbot.js +19 -0
  13. package/src/commands/code.js +3 -2
  14. package/src/commands/commitments.js +125 -9
  15. package/src/commands/completion.js +40 -32
  16. package/src/commands/config.js +219 -30
  17. package/src/commands/configure.js +84 -67
  18. package/src/commands/cron.js +239 -19
  19. package/src/commands/daemon.js +34 -4
  20. package/src/commands/dashboard.js +47 -374
  21. package/src/commands/devices.js +53 -26
  22. package/src/commands/directory.js +146 -14
  23. package/src/commands/dns.js +148 -10
  24. package/src/commands/docs.js +119 -26
  25. package/src/commands/doctor.js +143 -492
  26. package/src/commands/exec-policy.js +57 -48
  27. package/src/commands/gateway.js +492 -249
  28. package/src/commands/health.js +141 -11
  29. package/src/commands/help.js +24 -25
  30. package/src/commands/hooks.js +141 -87
  31. package/src/commands/infer.js +1442 -41
  32. package/src/commands/logs.js +122 -99
  33. package/src/commands/mcp.js +121 -309
  34. package/src/commands/memory.js +128 -0
  35. package/src/commands/message.js +720 -140
  36. package/src/commands/models.js +39 -1
  37. package/src/commands/node.js +77 -77
  38. package/src/commands/nodes.js +278 -22
  39. package/src/commands/onboard.js +115 -56
  40. package/src/commands/pairing.js +108 -107
  41. package/src/commands/path.js +206 -0
  42. package/src/commands/plugins.js +35 -1
  43. package/src/commands/proxy.js +159 -8
  44. package/src/commands/qr.js +55 -13
  45. package/src/commands/reset.js +101 -94
  46. package/src/commands/secrets.js +104 -21
  47. package/src/commands/sessions.js +110 -51
  48. package/src/commands/setup.js +102 -649
  49. package/src/commands/skills.js +67 -1
  50. package/src/commands/status.js +101 -127
  51. package/src/commands/tasks.js +208 -100
  52. package/src/commands/terminal.js +130 -12
  53. package/src/commands/transcripts.js +24 -1
  54. package/src/commands/tui.js +41 -0
  55. package/src/commands/uninstall.js +73 -92
  56. package/src/commands/update.js +146 -91
  57. package/src/commands/webhooks.js +58 -66
  58. package/src/commands/wiki.js +783 -0
  59. package/src/utils/agents-md.js +85 -0
  60. package/src/utils/api.js +39 -40
  61. package/src/utils/format.js +144 -0
  62. package/src/utils/headless.js +2 -1
  63. package/src/utils/parallel-tools.js +106 -0
  64. package/src/utils/sub-agent.js +148 -0
  65. package/src/utils/token-budget.js +304 -0
  66. package/src/utils/tool-runner.js +7 -5
  67. package/src/utils/web-fetch.js +107 -0
@@ -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 || {};
@@ -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
- let nodeServer = null;
6
+ const NODES_FILE = path.join(os.homedir(), '.natureco', 'nodes.json');
6
7
 
7
- function nodeCmd(args) {
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 statusNode();
11
- if (action === 'start') return startNode(params[0]);
12
- if (action === 'stop') return stopNode();
13
- if (action === 'info') return infoNode();
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 Bilinmeyen komut: ${action}\n`));
16
- console.log(chalk.gray(' Kullanım: natureco node [status|start|stop|info]\n'));
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 statusNode() {
21
- console.log(chalk.cyan('\n 🖥️ Node Host\n'));
22
- console.log(chalk.gray(' ' + '─'.repeat(48)));
23
- console.log(` ${chalk.white('Status:')} ${nodeServer ? chalk.green('Running on port ' + nodeServer.port) : chalk.gray('idle')}`);
24
- console.log(` ${chalk.white('Host:')} ${os.hostname()}`);
25
- console.log(` ${chalk.white('Platform:')} ${process.platform}`);
26
- console.log(` ${chalk.white('Memory:')} ${Math.round(os.freemem() / 1024 / 1024)}MB free`);
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 startNode(portStr) {
34
- if (nodeServer) {
35
- console.log(chalk.yellow('\n ⚠️ Node host already running\n'));
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
- const port = parseInt(portStr, 10) || 0;
40
- const server = http.createServer((req, res) => {
41
- if (req.url === '/health' || req.url === '/') {
42
- res.writeHead(200, { 'Content-Type': 'application/json' });
43
- res.end(JSON.stringify({
44
- status: 'ok',
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 stopNode() {
69
- if (!nodeServer) {
70
- console.log(chalk.yellow('\n ⚠️ Node host not running\n'));
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 infoNode() {
80
- console.log(chalk.cyan('\n 🖥️ Node Info\n'));
81
- console.log(chalk.gray(' ' + '─'.repeat(48)));
82
- console.log(` ${chalk.white('Node:')} ${process.version}`);
83
- console.log(` ${chalk.white('Platform:')} ${process.platform} ${os.release()}`);
84
- console.log(` ${chalk.white('Arch:')} ${process.arch}`);
85
- console.log(` ${chalk.white('Hostname:')} ${os.hostname()}`);
86
- console.log(` ${chalk.white('CPUs:')} ${os.cpus().length}`);
87
- for (let i = 0; i < Math.min(os.cpus().length, 4); i++) {
88
- console.log(` ${chalk.gray(`${i}: ${os.cpus()[i].model}`)}`);
89
- }
90
- if (os.cpus().length > 4) console.log(` ${chalk.gray(`… and ${os.cpus().length - 4} more`)}`);
91
- console.log(` ${chalk.white('Memory:')} ${Math.round(os.totalmem() / 1024 / 1024 / 1024)}GB total, ${Math.round(os.freemem() / 1024 / 1024)}MB free`);
92
- console.log(` ${chalk.white('Load:')} ${os.loadavg().map(l => l.toFixed(2)).join(', ')}`);
93
- console.log(` ${chalk.white('Uptime:')} ${Math.floor(os.uptime() / 3600)}h ${Math.floor((os.uptime() % 3600) / 60)}m`);
94
- console.log(` ${chalk.white('Interfaces:')} ${Object.keys(os.networkInterfaces()).filter(k => k !== 'lo').join(', ') || 'none'}`);
95
- console.log();
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 = nodeCmd;
98
+ module.exports = node;
@@ -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
- console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
16
- console.log(chalk.gray(' Kullanım: natureco nodes [list|pair|approve|reject|remove|rename]\n'));
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
- console.log(chalk.cyan('\n 🖥️ Paired Nodes\n'));
25
- console.log(chalk.gray(' ' + '─'.repeat(48)));
167
+ F.header('Nodes');
26
168
 
27
169
  if (nodes.length === 0) {
28
- console.log(chalk.gray(' No paired nodes.\n'));
170
+ F.info('No paired nodes.');
29
171
  return;
30
172
  }
31
173
 
32
- for (const n of nodes) {
33
- console.log(` ${chalk.green('●')} ${chalk.white(n.name || n.id)}`);
34
- console.log(` ${chalk.gray('ID:')} ${n.id}`);
35
- console.log(` ${chalk.gray('URL:')} ${n.url || 'local'}`);
36
- console.log(` ${chalk.gray('Key:')} ${n.key ? n.key.substring(0, 8) + '…' : 'none'}`);
37
- }
38
- console.log();
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
- console.log(chalk.red('\n ❌ Node URL gerekli\n'));
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
- console.log(chalk.green(`\n ✅ Node paired: ${url}\n`));
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
- console.log(chalk.green(`\n ✅ Node approved: ${id}\n`));
205
+ F.success(`Node approved: ${id}`);
61
206
  }
62
207
 
63
208
  function rejectNode(id) {
64
- console.log(chalk.gray(`\n ❌ Node rejected: ${id}\n`));
209
+ F.error(`Node rejected: ${id}`);
65
210
  }
66
211
 
67
212
  function removeNode(id) {
68
213
  if (!id) {
69
- console.log(chalk.red('\n ❌ Node ID gerekli\n'));
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
- console.log(chalk.red(`\n ❌ Node bulunamadı: ${id}\n`));
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
- console.log(chalk.gray(`\n 🗑️ Node removed: ${id}\n`));
230
+ F.success(`Node removed: ${id}`);
86
231
  }
87
232
 
88
233
  function renameNode(id, name) {
89
234
  if (!id || !name) {
90
- console.log(chalk.red('\n ❌ Node ID ve name gerekli\n'));
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
- console.log(chalk.red(`\n ❌ Node bulunamadı: ${id}\n`));
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
- console.log(chalk.green(`\n ✅ Node renamed: ${name}\n`));
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.31 (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;