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.
Files changed (69) hide show
  1. package/bin/natureco.js +178 -167
  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/ask.js +1 -1
  9. package/src/commands/browser.js +815 -0
  10. package/src/commands/capability.js +195 -22
  11. package/src/commands/channels.js +422 -267
  12. package/src/commands/chat.js +5 -8
  13. package/src/commands/clawbot.js +19 -0
  14. package/src/commands/code.js +3 -2
  15. package/src/commands/commitments.js +125 -9
  16. package/src/commands/completion.js +40 -32
  17. package/src/commands/config.js +228 -30
  18. package/src/commands/configure.js +84 -67
  19. package/src/commands/cron.js +239 -19
  20. package/src/commands/daemon.js +34 -4
  21. package/src/commands/dashboard.js +47 -374
  22. package/src/commands/devices.js +53 -26
  23. package/src/commands/directory.js +146 -14
  24. package/src/commands/dns.js +148 -10
  25. package/src/commands/docs.js +119 -26
  26. package/src/commands/doctor.js +143 -492
  27. package/src/commands/exec-policy.js +57 -48
  28. package/src/commands/gateway.js +492 -249
  29. package/src/commands/health.js +141 -11
  30. package/src/commands/help.js +24 -25
  31. package/src/commands/hooks.js +141 -87
  32. package/src/commands/infer.js +1442 -41
  33. package/src/commands/logs.js +122 -99
  34. package/src/commands/mcp.js +121 -309
  35. package/src/commands/memory.js +128 -0
  36. package/src/commands/message.js +720 -140
  37. package/src/commands/models.js +39 -1
  38. package/src/commands/node.js +77 -77
  39. package/src/commands/nodes.js +278 -22
  40. package/src/commands/onboard.js +115 -56
  41. package/src/commands/pairing.js +108 -107
  42. package/src/commands/path.js +206 -0
  43. package/src/commands/plugins.js +35 -1
  44. package/src/commands/proxy.js +159 -8
  45. package/src/commands/qr.js +55 -13
  46. package/src/commands/reset.js +101 -94
  47. package/src/commands/secrets.js +104 -21
  48. package/src/commands/sessions.js +110 -51
  49. package/src/commands/setup.js +229 -649
  50. package/src/commands/skills.js +67 -1
  51. package/src/commands/status.js +101 -127
  52. package/src/commands/tasks.js +208 -100
  53. package/src/commands/terminal.js +130 -12
  54. package/src/commands/transcripts.js +24 -1
  55. package/src/commands/tui.js +41 -0
  56. package/src/commands/uninstall.js +73 -92
  57. package/src/commands/update.js +146 -91
  58. package/src/commands/web-fetch.js +34 -0
  59. package/src/commands/webhooks.js +58 -66
  60. package/src/commands/wiki.js +783 -0
  61. package/src/utils/agents-md.js +85 -0
  62. package/src/utils/api.js +40 -41
  63. package/src/utils/format.js +144 -0
  64. package/src/utils/headless.js +2 -1
  65. package/src/utils/parallel-tools.js +106 -0
  66. package/src/utils/sub-agent.js +148 -0
  67. package/src/utils/token-budget.js +304 -0
  68. package/src/utils/tool-runner.js +7 -5
  69. package/src/utils/web-fetch.js +107 -0
@@ -1,70 +1,129 @@
1
1
  const chalk = require('chalk');
2
- const readline = require('readline');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
3
5
 
4
- function rlQuestion(query) {
5
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6
- return new Promise(resolve => {
7
- rl.question(query, answer => { rl.close(); resolve(answer.trim()); });
8
- });
6
+ const BASE_DIR = path.join(os.homedir(), '.natureco');
7
+ const CONFIG_FILE = path.join(BASE_DIR, 'config.json');
8
+
9
+ const STEPS = ['gateway', 'auth', 'workspace', 'channels', 'skills', 'health'];
10
+
11
+ function getConfig() {
12
+ if (!fs.existsSync(CONFIG_FILE)) return {};
13
+ try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); }
14
+ catch { return {}; }
15
+ }
16
+
17
+ function saveConfig(data) {
18
+ if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
19
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
9
20
  }
10
21
 
11
- async function onboard(args) {
12
- console.log(chalk.cyan('\n πŸš€ NatureCo Onboarding\n'));
13
- console.log(chalk.gray(' Welcome! Let\'s get you set up step by step.\n'));
22
+ function onboard(params) {
23
+ try {
24
+ const [action] = params || [];
14
25
 
15
- const { getConfig, saveConfig } = require('../utils/config');
16
- const config = getConfig();
26
+ if (!action || action === 'status') return cmdStatus();
27
+ if (action === 'gateway') return cmdGateway();
28
+ if (action === 'auth') return cmdAuth();
29
+ if (action === 'workspace') return cmdWorkspace();
30
+ if (action === 'channels') return cmdChannels();
31
+ if (action === 'skills') return cmdSkills();
32
+ if (action === 'health') return cmdHealth();
17
33
 
18
- const start = await rlQuestion(' Begin onboarding? [Y/n]: ');
19
- if (start.toLowerCase() === 'n') {
20
- console.log(chalk.gray('\n Skipped. You can always run: natureco onboard\n'));
21
- return;
34
+ console.log(chalk.red(`\n Unknown onboard action: ${action}\n`));
35
+ console.log(chalk.gray(' Usage: natureco onboard [gateway|auth|workspace|channels|skills|health|status]\n'));
36
+ } catch (err) {
37
+ console.log(chalk.red(`\n Onboard error: ${err.message}\n`));
22
38
  }
39
+ }
40
+
41
+ function cmdStatus() {
42
+ const cfg = getConfig();
43
+ console.log(chalk.cyan('\n Onboarding Status\n'));
44
+
45
+ const status = {
46
+ gateway: cfg.gatewayUrl ? 'done' : 'pending',
47
+ auth: cfg.providerApiKey ? 'done' : 'pending',
48
+ workspace: cfg.workspacePath ? 'done' : 'pending',
49
+ channels: cfg.channels ? 'done' : 'pending',
50
+ skills: cfg.skills && cfg.skills.list && cfg.skills.list.length > 0 ? 'done' : 'pending',
51
+ health: cfg.setupCompleted ? 'done' : 'pending',
52
+ };
53
+
54
+ for (const step of STEPS) {
55
+ const icon = status[step] === 'done' ? chalk.green('βœ“') : chalk.yellow('β—‹');
56
+ console.log(` ${icon} ${step}`);
57
+ }
58
+ console.log('');
59
+ }
60
+
61
+ function cmdGateway() {
62
+ const cfg = getConfig();
63
+ console.log(chalk.cyan('\n Gateway Setup\n'));
64
+ console.log(chalk.gray(' To configure the gateway, run:'));
65
+ console.log(chalk.cyan(' natureco configure gateway'));
66
+ console.log(chalk.gray(' Or start the gateway:'));
67
+ console.log(chalk.cyan(' natureco gateway start\n'));
68
+ cfg.gatewayUrl = 'ws://localhost:3848';
69
+ saveConfig(cfg);
70
+ console.log(chalk.green(' Gateway step marked as done.\n'));
71
+ }
72
+
73
+ function cmdAuth() {
74
+ const cfg = getConfig();
75
+ console.log(chalk.cyan('\n Auth Setup\n'));
76
+ console.log(chalk.gray(' To configure authentication, run:'));
77
+ console.log(chalk.cyan(' natureco configure auth'));
78
+ console.log(chalk.gray(' Or set your API key in config.\n'));
79
+ cfg.authConfigured = true;
80
+ saveConfig(cfg);
81
+ console.log(chalk.green(' Auth step marked as done.\n'));
82
+ }
23
83
 
24
- // Step 1: Provider
25
- console.log(chalk.cyan('\n Step 1: AI Provider\n'));
26
- const provider = await rlQuestion(` Provider (${config.provider || 'openai'}): `);
27
- const model = await rlQuestion(` Model (${config.model || 'gpt-4o'}): `);
28
- config.provider = provider || config.provider || 'openai';
29
- config.model = model || config.model || 'gpt-4o';
30
- saveConfig(config);
31
- console.log(chalk.green(` βœ… ${config.provider}/${config.model}`));
32
-
33
- // Step 2: API Key
34
- if (!config.openaiApiKey && !config.anthropicApiKey) {
35
- console.log(chalk.cyan('\n Step 2: API Key\n'));
36
- const apiKey = await rlQuestion(` Enter your ${config.provider} API key: `);
37
- if (apiKey) {
38
- config[`${config.provider}ApiKey`] = apiKey;
39
- saveConfig(config);
40
- console.log(chalk.green(' βœ… API Key saved'));
41
- }
84
+ function cmdWorkspace() {
85
+ const cfg = getConfig();
86
+ const wsPath = cfg.workspacePath || path.join(os.homedir(), 'natureco-workspace');
87
+ if (!fs.existsSync(wsPath)) fs.mkdirSync(wsPath, { recursive: true });
88
+ cfg.workspacePath = wsPath;
89
+ saveConfig(cfg);
90
+ console.log(chalk.green('\n Workspace ready at: ' + wsPath + '\n'));
91
+ }
92
+
93
+ function cmdChannels() {
94
+ console.log(chalk.cyan('\n Channels Setup\n'));
95
+ console.log(chalk.gray(' Available channels:'));
96
+ const channels = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage'];
97
+ for (const ch of channels) {
98
+ console.log(chalk.gray(' natureco ' + ch + ' connect'));
42
99
  }
100
+ console.log('');
101
+ }
43
102
 
44
- // Step 3: Gateway
45
- console.log(chalk.cyan('\n Step 3: Gateway\n'));
46
- const gUrl = await rlQuestion(` Gateway URL (${config.gatewayUrl || 'ws://localhost:3848'}): `);
47
- const gPort = await rlQuestion(` Port (${config.gatewayPort || 3848}): `);
48
- config.gatewayUrl = gUrl || config.gatewayUrl || 'ws://localhost:3848';
49
- config.gatewayPort = parseInt(gPort) || config.gatewayPort || 3848;
50
- saveConfig(config);
51
- console.log(chalk.green(' βœ… Gateway configured'));
52
-
53
- // Step 4: Workspace
54
- console.log(chalk.cyan('\n Step 4: Workspace\n'));
55
- const wsPath = await rlQuestion(` Workspace path (${process.cwd()}): `);
56
- if (wsPath) {
57
- config.workspacePath = wsPath;
58
- saveConfig(config);
103
+ function cmdSkills() {
104
+ console.log(chalk.cyan('\n Skills Setup\n'));
105
+ console.log(chalk.gray(' To manage skills, run:'));
106
+ console.log(chalk.cyan(' natureco skills list'));
107
+ console.log(chalk.cyan(' natureco skills add <name>\n'));
108
+ }
109
+
110
+ function cmdHealth() {
111
+ const cfg = getConfig();
112
+ console.log(chalk.cyan('\n Health Check\n'));
113
+
114
+ const checks = [
115
+ { label: 'Config exists', pass: fs.existsSync(CONFIG_FILE) },
116
+ { label: 'Gateway configured', pass: !!cfg.gatewayUrl },
117
+ { label: 'Auth configured', pass: !!cfg.providerApiKey },
118
+ { label: 'Workspace configured', pass: !!cfg.workspacePath },
119
+ ];
120
+
121
+ for (const c of checks) {
122
+ console.log(` ${c.pass ? chalk.green('βœ“') : chalk.yellow('β—‹')} ${c.label}`);
59
123
  }
60
- console.log(chalk.green(' βœ… Workspace set'));
61
-
62
- console.log(chalk.green('\n πŸŽ‰ Onboarding complete!\n'));
63
- console.log(chalk.gray(' Next steps:'));
64
- console.log(chalk.cyan(' natureco chat') + chalk.gray(' Start chatting'));
65
- console.log(chalk.cyan(' natureco channels add') + chalk.gray(' Connect messaging channels'));
66
- console.log(chalk.cyan(' natureco doctor') + chalk.gray(' Health check'));
67
- console.log(chalk.cyan(' natureco configure') + chalk.gray(' More settings\n'));
124
+
125
+ const done = checks.filter(c => c.pass).length;
126
+ console.log(chalk.gray(`\n ${done}/${checks.length} checks passed\n`));
68
127
  }
69
128
 
70
129
  module.exports = onboard;
@@ -1,107 +1,108 @@
1
- const chalk = require('chalk');
2
- const { getConfig, saveConfig } = require('../utils/config');
3
-
4
- async function pairing(args) {
5
- const [action, ...params] = (args || []);
6
-
7
- if (!action || action === 'list') return listPairing();
8
- if (action === 'approve') return approvePairing(params[0], params[1]);
9
- if (action === 'reject') return rejectPairing(params[0]);
10
-
11
- console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
12
- console.log(chalk.gray(' KullanΔ±m: natureco pairing [list|approve|reject]\n'));
13
- process.exit(1);
14
- }
15
-
16
- function listPairing() {
17
- const config = getConfig();
18
- const pending = config.pendingPairings || [];
19
-
20
- console.log('');
21
- console.log(chalk.gray(' ' + '─'.repeat(48)));
22
- console.log(chalk.cyan.bold('\n Bekleyen Eşleştirmeler\n'));
23
-
24
- if (pending.length === 0) {
25
- console.log(chalk.gray(' Bekleyen eşleştirme yok.\n'));
26
- console.log(chalk.gray(' Telegram bağlamak için: ') + chalk.cyan('natureco telegram connect'));
27
- console.log(chalk.gray(' WhatsApp bağlamak için: ') + chalk.cyan('natureco whatsapp connect\n'));
28
- return;
29
- }
30
-
31
- pending.forEach((p, i) => {
32
- console.log(chalk.white(` ${i + 1}. ${p.channel} β€” ${p.id}`));
33
- console.log(chalk.gray(` Kod: ${p.code} Β· ${new Date(p.createdAt).toLocaleString('tr-TR')}`));
34
- console.log('');
35
- });
36
-
37
- console.log(chalk.gray(' Onaylamak iΓ§in: ') + chalk.cyan('natureco pairing approve <kanal> <kod>'));
38
- console.log(chalk.gray(' Reddetmek iΓ§in: ') + chalk.cyan('natureco pairing reject <kod>\n'));
39
- }
40
-
41
- function approvePairing(channel, code) {
42
- if (!channel || !code) {
43
- console.log(chalk.red('\n ❌ Kanal ve kod gerekli\n'));
44
- console.log(chalk.gray(' KullanΔ±m: natureco pairing approve <telegram|whatsapp> <KOD>\n'));
45
- process.exit(1);
46
- }
47
-
48
- const config = getConfig();
49
- const pending = config.pendingPairings || [];
50
- const idx = pending.findIndex(p => p.code === code && p.channel === channel);
51
-
52
- if (idx === -1) {
53
- console.log(chalk.yellow(`\n ⚠ Eşleştirme bulunamadı: ${channel} ${code}\n`));
54
- console.log(chalk.gray(' Bekleyen listesi: ') + chalk.cyan('natureco pairing list\n'));
55
- return;
56
- }
57
-
58
- const pairing = pending[idx];
59
- pending.splice(idx, 1);
60
-
61
- // Onaylanan kanalΔ± izin listesine ekle
62
- if (channel === 'telegram') {
63
- const allowed = config.telegramAllowedChats || [];
64
- if (!allowed.includes(pairing.id)) {
65
- allowed.push(pairing.id);
66
- config.telegramAllowedChats = allowed;
67
- }
68
- } else if (channel === 'whatsapp') {
69
- const allowed = config.whatsappAllowedNumbers || [];
70
- const num = pairing.id.replace(/\D/g, '');
71
- if (!allowed.includes(num)) {
72
- allowed.push(num);
73
- config.whatsappAllowedNumbers = allowed;
74
- }
75
- }
76
-
77
- config.pendingPairings = pending;
78
- saveConfig(config);
79
-
80
- console.log(chalk.green(`\n βœ“ Eşleştirme onaylandΔ±: ${channel} β€” ${pairing.id}\n`));
81
- console.log(chalk.gray(' Gateway\'i yeniden başlatın: ') + chalk.cyan('natureco gateway stop && natureco gateway start\n'));
82
- }
83
-
84
- function rejectPairing(code) {
85
- if (!code) {
86
- console.log(chalk.red('\n ❌ Kod gerekli\n'));
87
- console.log(chalk.gray(' KullanΔ±m: natureco pairing reject <KOD>\n'));
88
- process.exit(1);
89
- }
90
-
91
- const config = getConfig();
92
- const pending = config.pendingPairings || [];
93
- const idx = pending.findIndex(p => p.code === code);
94
-
95
- if (idx === -1) {
96
- console.log(chalk.yellow(`\n ⚠ Eşleştirme bulunamadı: ${code}\n`));
97
- return;
98
- }
99
-
100
- pending.splice(idx, 1);
101
- config.pendingPairings = pending;
102
- saveConfig(config);
103
-
104
- console.log(chalk.gray(`\n β—‹ Eşleştirme reddedildi: ${code}\n`));
105
- }
106
-
107
- module.exports = pairing;
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const PAIRINGS_FILE = path.join(os.homedir(), '.natureco', 'pairings.json');
7
+
8
+ function loadPairings() {
9
+ if (!fs.existsSync(PAIRINGS_FILE)) return [];
10
+ try { return JSON.parse(fs.readFileSync(PAIRINGS_FILE, 'utf8')); }
11
+ catch { return []; }
12
+ }
13
+
14
+ function savePairings(pairings) {
15
+ const dir = path.dirname(PAIRINGS_FILE);
16
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
17
+ fs.writeFileSync(PAIRINGS_FILE, JSON.stringify(pairings, null, 2), 'utf8');
18
+ }
19
+
20
+ function genId() {
21
+ return Date.now().toString(36) + Math.random().toString(36).slice(2, 8).toUpperCase();
22
+ }
23
+
24
+ function pairing(args) {
25
+ const [action, ...params] = args || [];
26
+
27
+ if (!action || action === 'list') return cmdList();
28
+ if (action === 'approve') return cmdApprove(params[0]);
29
+ if (action === 'reject') return cmdReject(params[0]);
30
+ if (action === 'generate') return cmdGenerate();
31
+
32
+ console.log(chalk.red(`\n Unknown pairing action: ${action}\n`));
33
+ console.log(chalk.gray(' Usage: natureco pairing <action> [params]'));
34
+ console.log(chalk.gray(' Actions: list, approve <id>, reject <id>, generate\n'));
35
+ process.exit(1);
36
+ }
37
+
38
+ function cmdList() {
39
+ const pairings = loadPairings();
40
+ const pending = pairings.filter(p => p.status === 'pending');
41
+
42
+ console.log(chalk.cyan(`\n Pending Pairings (${pending.length})\n`));
43
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
44
+
45
+ if (pending.length === 0) {
46
+ console.log(chalk.gray(' No pending pairings.\n'));
47
+ return;
48
+ }
49
+
50
+ for (const p of pending) {
51
+ console.log(` ${chalk.white(p.id)}`);
52
+ console.log(chalk.gray(` Code: ${p.code}`));
53
+ console.log(chalk.gray(` Node: ${p.nodeName || 'β€”'}`));
54
+ console.log(chalk.gray(` Since: ${p.createdAt ? new Date(p.createdAt).toLocaleString() : 'β€”'}`));
55
+ }
56
+ console.log('');
57
+ }
58
+
59
+ function cmdApprove(id) {
60
+ if (!id) { console.log(chalk.red('\n Usage: natureco pairing approve <id>\n')); process.exit(1); }
61
+
62
+ const pairings = loadPairings();
63
+ const p = pairings.find(x => x.id === id && x.status === 'pending');
64
+
65
+ if (!p) { console.log(chalk.yellow(`\n No pending pairing with id "${id}".\n`)); return; }
66
+
67
+ p.status = 'approved';
68
+ p.approvedAt = new Date().toISOString();
69
+ savePairings(pairings);
70
+ console.log(chalk.green(`\n Pairing "${id}" approved.\n`));
71
+ }
72
+
73
+ function cmdReject(id) {
74
+ if (!id) { console.log(chalk.red('\n Usage: natureco pairing reject <id>\n')); process.exit(1); }
75
+
76
+ const pairings = loadPairings();
77
+ const idx = pairings.findIndex(x => x.id === id && x.status === 'pending');
78
+
79
+ if (idx === -1) { console.log(chalk.yellow(`\n No pending pairing with id "${id}".\n`)); return; }
80
+
81
+ pairings.splice(idx, 1);
82
+ savePairings(pairings);
83
+ console.log(chalk.gray(`\n Pairing "${id}" rejected.\n`));
84
+ }
85
+
86
+ function cmdGenerate() {
87
+ const code = genId();
88
+ const pairings = loadPairings();
89
+
90
+ const entry = {
91
+ id: `pair_${Date.now().toString(36)}`,
92
+ code,
93
+ status: 'pending',
94
+ createdAt: new Date().toISOString(),
95
+ };
96
+
97
+ pairings.push(entry);
98
+ savePairings(pairings);
99
+
100
+ console.log(chalk.cyan('\n Pairing Code Generated\n'));
101
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
102
+ console.log(` ${chalk.white('Code:')} ${chalk.green(code)}`);
103
+ console.log(` ${chalk.white('ID:')} ${chalk.gray(entry.id)}`);
104
+ console.log('');
105
+ console.log(chalk.gray(' Share this code with the node to pair.\n'));
106
+ }
107
+
108
+ module.exports = pairing;
@@ -0,0 +1,206 @@
1
+ const chalk = require('chalk');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+
6
+ const PATHS_FILE = path.join(os.homedir(), '.natureco', 'paths.json');
7
+
8
+ function loadPaths() {
9
+ try {
10
+ if (fs.existsSync(PATHS_FILE)) return JSON.parse(fs.readFileSync(PATHS_FILE, 'utf8'));
11
+ } catch {}
12
+ return {};
13
+ }
14
+
15
+ function savePaths(data) {
16
+ const dir = path.dirname(PATHS_FILE);
17
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
18
+ fs.writeFileSync(PATHS_FILE, JSON.stringify(data, null, 2));
19
+ }
20
+
21
+ function pathCmd(args) {
22
+ const [action, ...params] = args || [];
23
+
24
+ if (!action) return listPaths();
25
+ if (action === 'resolve') return resolvePath(params.join('/'));
26
+ if (action === 'find') return findPath(params[0]);
27
+ if (action === 'set') return setPath(params[0], params.slice(1).join(' '));
28
+ if (action === 'validate') return validatePath(params[0]);
29
+ if (action === 'emit') return emitPath(params[0]);
30
+
31
+ console.log(chalk.red(`\n ❌ Unknown path action: ${action}\n`));
32
+ console.log(chalk.gray(' Usage: natureco path <resolve|find|set|validate|emit> [args]\n'));
33
+ process.exit(1);
34
+ }
35
+
36
+ function listPaths() {
37
+ const paths = loadPaths();
38
+ const entries = Object.entries(paths);
39
+
40
+ console.log(chalk.cyan('\n πŸ“ Registered Paths\n'));
41
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
42
+
43
+ if (entries.length === 0) {
44
+ console.log(chalk.gray(' No paths registered.\n'));
45
+ console.log(chalk.gray(' Register a path:'));
46
+ console.log(chalk.cyan(' natureco path set <name> <path>\n'));
47
+ return;
48
+ }
49
+
50
+ for (const [name, p] of entries) {
51
+ const exists = fs.existsSync(p);
52
+ const icon = exists ? chalk.green('●') : chalk.red('β—‹');
53
+ console.log(` ${icon} ${chalk.white(name)}`);
54
+ console.log(` ${chalk.gray('Path:')} ${chalk.cyan(p)}`);
55
+ console.log(` ${chalk.gray('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
56
+ }
57
+ console.log();
58
+ }
59
+
60
+ function resolvePath(uri) {
61
+ if (!uri) {
62
+ console.log(chalk.red('\n ❌ URI gerekli\n'));
63
+ console.log(chalk.gray(' Usage: natureco path resolve nc://path\n'));
64
+ process.exit(1);
65
+ }
66
+
67
+ const fullUri = uri.startsWith('nc://') ? uri : `nc://${uri}`;
68
+ const parts = fullUri.replace('nc://', '').split('/').filter(Boolean);
69
+ const name = parts[0];
70
+ const sub = parts.slice(1).join('/');
71
+
72
+ const registry = loadPaths();
73
+ const registered = registry[name];
74
+
75
+ if (registered) {
76
+ const resolved = sub ? path.join(registered, sub) : registered;
77
+ const exists = fs.existsSync(resolved);
78
+
79
+ console.log(chalk.cyan('\n πŸ“ Path Resolution\n'));
80
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
81
+ console.log(` ${chalk.white('URI:')} ${chalk.cyan(fullUri)}`);
82
+ console.log(` ${chalk.white('Name:')} ${chalk.white(name)}`);
83
+ console.log(` ${chalk.white('Path:')} ${chalk.white(resolved)}`);
84
+ console.log(` ${chalk.white('From registry:')} ${chalk.gray(registered)}`);
85
+ console.log(` ${chalk.white('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
86
+ console.log();
87
+ return;
88
+ }
89
+
90
+ const resolved = path.resolve(uri);
91
+ const exists = fs.existsSync(resolved);
92
+
93
+ console.log(chalk.cyan('\n πŸ“ Path Resolution\n'));
94
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
95
+ console.log(` ${chalk.white('URI:')} ${chalk.cyan(fullUri)}`);
96
+ console.log(` ${chalk.white('Path:')} ${chalk.white(resolved)}`);
97
+ console.log(` ${chalk.white('From registry:')} ${chalk.gray('No')}`);
98
+ console.log(` ${chalk.white('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
99
+ console.log();
100
+ }
101
+
102
+ function findPath(name) {
103
+ if (!name) {
104
+ console.log(chalk.red('\n ❌ Name gerekli\n'));
105
+ process.exit(1);
106
+ }
107
+
108
+ const paths = loadPaths();
109
+ const entry = paths[name];
110
+
111
+ if (!entry) {
112
+ console.log(chalk.yellow(`\n πŸ” Path not found: ${name}\n`));
113
+ console.log(chalk.gray(' Register it:'));
114
+ console.log(chalk.cyan(` natureco path set ${name} <path>\n`));
115
+ return;
116
+ }
117
+
118
+ const exists = fs.existsSync(entry);
119
+
120
+ console.log(chalk.cyan('\n πŸ” Path Lookup\n'));
121
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
122
+ console.log(` ${chalk.white('Name:')} ${chalk.cyan(name)}`);
123
+ console.log(` ${chalk.white('Path:')} ${chalk.white(entry)}`);
124
+ console.log(` ${chalk.white('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
125
+ console.log();
126
+ }
127
+
128
+ function setPath(name, targetPath) {
129
+ if (!name) {
130
+ console.log(chalk.red('\n ❌ Name gerekli\n'));
131
+ process.exit(1);
132
+ }
133
+ if (!targetPath) {
134
+ console.log(chalk.red('\n ❌ Path gerekli\n'));
135
+ process.exit(1);
136
+ }
137
+
138
+ const resolved = path.resolve(targetPath);
139
+ const paths = loadPaths();
140
+ paths[name] = resolved;
141
+ savePaths(paths);
142
+
143
+ console.log(chalk.green(`\n βœ… Path registered: ${name}\n`));
144
+ console.log(chalk.gray(` Name: ${chalk.white(name)}`));
145
+ console.log(chalk.gray(` Path: ${chalk.cyan(resolved)}\n`));
146
+ }
147
+
148
+ function validatePath(name) {
149
+ if (!name) {
150
+ console.log(chalk.red('\n ❌ Name gerekli\n'));
151
+ process.exit(1);
152
+ }
153
+
154
+ const paths = loadPaths();
155
+ const entry = paths[name];
156
+
157
+ if (!entry) {
158
+ console.log(chalk.yellow(`\n ⚠️ Not registered: ${name}\n`));
159
+ process.exit(1);
160
+ }
161
+
162
+ const exists = fs.existsSync(entry);
163
+
164
+ console.log(chalk.cyan('\n βœ… Path Validation\n'));
165
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
166
+ console.log(` ${chalk.white('Name:')} ${chalk.cyan(name)}`);
167
+ console.log(` ${chalk.white('Path:')} ${chalk.white(entry)}`);
168
+ console.log(` ${chalk.white('Exists:')} ${exists ? chalk.green('Yes') : chalk.red('No')}`);
169
+
170
+ if (exists) {
171
+ try {
172
+ const stat = fs.statSync(entry);
173
+ console.log(` ${chalk.white('Type:')} ${stat.isDirectory() ? chalk.blue('Directory') : chalk.gray('File')}`);
174
+ console.log(` ${chalk.white('Size:')} ${chalk.gray(stat.isDirectory() ? '-' : `${(stat.size / 1024).toFixed(1)} KB`)}`);
175
+ } catch {}
176
+ }
177
+
178
+ console.log();
179
+ }
180
+
181
+ function emitPath(name) {
182
+ if (!name) {
183
+ console.log(chalk.red('\n ❌ Name gerekli\n'));
184
+ process.exit(1);
185
+ }
186
+
187
+ const paths = loadPaths();
188
+ const entry = paths[name];
189
+
190
+ if (!entry) {
191
+ console.log(chalk.yellow(`\n ⚠️ Not registered: ${name}\n`));
192
+ process.exit(1);
193
+ }
194
+
195
+ const uri = `nc://${name}`;
196
+
197
+ console.log(chalk.cyan('\n πŸ”— Clickable URI\n'));
198
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
199
+ console.log(` ${chalk.white('Name:')} ${chalk.cyan(name)}`);
200
+ console.log(` ${chalk.white('URI:')} ${chalk.bold.green(uri)}`);
201
+ console.log(` ${chalk.white('Path:')} ${chalk.gray(entry)}`);
202
+ console.log();
203
+ console.log(chalk.gray(' Copy the URI above to use in nc://-aware tools.\n'));
204
+ }
205
+
206
+ module.exports = pathCmd;
@@ -21,9 +21,10 @@ async function plugins(args) {
21
21
  if (action === 'search') return searchHandler(params.join(' '), opts);
22
22
  if (action === 'doctor') return doctorHandler();
23
23
  if (action === 'registry') return registryHandler(opts);
24
+ if (action === 'marketplace') return marketplaceHandler(opts);
24
25
 
25
26
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
26
- console.log(chalk.gray(' KullanΔ±m: natureco plugins [list|install|uninstall|enable|disable|info|update|search|doctor|registry]\n'));
27
+ console.log(chalk.gray(' KullanΔ±m: natureco plugins [list|install|uninstall|enable|disable|info|update|search|doctor|registry|marketplace]\n'));
27
28
  process.exit(1);
28
29
  } catch (err) {
29
30
  handleError(err);
@@ -412,4 +413,37 @@ function registryHandler(opts) {
412
413
  console.log('');
413
414
  }
414
415
 
416
+ async function marketplaceHandler(opts) {
417
+ console.log(chalk.cyan.bold('\n Plugin Marketplace\n'));
418
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
419
+ console.log(chalk.gray('\n Fetching available plugins...\n'));
420
+
421
+ try {
422
+ const res = await fetch('https://natureco.me/api/plugins?limit=' + (opts.limit || 20), {
423
+ signal: AbortSignal.timeout(5000),
424
+ });
425
+ if (res.ok) {
426
+ const data = await res.json();
427
+ const plugins = data.plugins || data.results || [];
428
+ if (plugins.length === 0) {
429
+ console.log(chalk.yellow(' No plugins available in marketplace.\n'));
430
+ return;
431
+ }
432
+ console.log(chalk.white(' Available Plugins (' + plugins.length + ')\n'));
433
+ for (const p of plugins.slice(0, opts.limit || 20)) {
434
+ console.log(chalk.cyan(' ' + (p.name || p.id)));
435
+ if (p.description) console.log(chalk.gray(' ' + p.description.slice(0, 80)));
436
+ console.log(chalk.gray(' Install: natureco plugins install ' + (p.id || p.name)));
437
+ console.log('');
438
+ }
439
+ } else {
440
+ console.log(chalk.yellow(' Marketplace unavailable (HTTP ' + res.status + ')\n'));
441
+ console.log(chalk.gray(' Try: natureco plugins search <query>\n'));
442
+ }
443
+ } catch (err) {
444
+ console.log(chalk.yellow(' Marketplace unavailable: ' + err.message + '\n'));
445
+ console.log(chalk.gray(' Try: natureco plugins search <query>\n'));
446
+ }
447
+ }
448
+
415
449
  module.exports = plugins;