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.
Files changed (111) hide show
  1. package/README.md +94 -11
  2. package/bin/natureco.js +495 -94
  3. package/package.json +1 -1
  4. package/src/commands/acp.js +39 -0
  5. package/src/commands/admin-rpc.js +302 -0
  6. package/src/commands/agent.js +280 -0
  7. package/src/commands/agents.js +114 -30
  8. package/src/commands/approvals.js +214 -0
  9. package/src/commands/backup.js +124 -0
  10. package/src/commands/bonjour.js +167 -0
  11. package/src/commands/browser.js +815 -0
  12. package/src/commands/capability.js +237 -0
  13. package/src/commands/channels.js +422 -267
  14. package/src/commands/chat.js +5 -8
  15. package/src/commands/clawbot.js +19 -0
  16. package/src/commands/clickclack.js +130 -0
  17. package/src/commands/code.js +3 -2
  18. package/src/commands/commitments.js +148 -0
  19. package/src/commands/completion.js +84 -0
  20. package/src/commands/config.js +219 -30
  21. package/src/commands/configure.js +110 -0
  22. package/src/commands/crestodian.js +92 -0
  23. package/src/commands/cron.js +239 -19
  24. package/src/commands/daemon.js +90 -0
  25. package/src/commands/dashboard.js +47 -374
  26. package/src/commands/device-pair.js +248 -0
  27. package/src/commands/devices.js +137 -0
  28. package/src/commands/directory.js +179 -0
  29. package/src/commands/dns.js +196 -0
  30. package/src/commands/docs.js +136 -0
  31. package/src/commands/doctor.js +143 -492
  32. package/src/commands/exec-policy.js +80 -0
  33. package/src/commands/gateway-server.js +1155 -24
  34. package/src/commands/gateway.js +492 -249
  35. package/src/commands/health.js +148 -0
  36. package/src/commands/help.js +24 -25
  37. package/src/commands/hooks.js +141 -87
  38. package/src/commands/imessage.js +128 -14
  39. package/src/commands/infer.js +1474 -0
  40. package/src/commands/irc.js +64 -15
  41. package/src/commands/logs.js +122 -99
  42. package/src/commands/mattermost.js +114 -12
  43. package/src/commands/mcp.js +121 -309
  44. package/src/commands/memory-cmd.js +134 -1
  45. package/src/commands/memory.js +128 -0
  46. package/src/commands/message.js +720 -134
  47. package/src/commands/migrate.js +213 -2
  48. package/src/commands/models.js +39 -1
  49. package/src/commands/node.js +98 -0
  50. package/src/commands/nodes.js +362 -0
  51. package/src/commands/oc-path.js +200 -0
  52. package/src/commands/onboard.js +129 -0
  53. package/src/commands/open-prose.js +67 -0
  54. package/src/commands/pairing.js +108 -107
  55. package/src/commands/path.js +206 -0
  56. package/src/commands/plugins.js +35 -1
  57. package/src/commands/policy.js +176 -0
  58. package/src/commands/proxy.js +306 -0
  59. package/src/commands/qr.js +70 -0
  60. package/src/commands/reset.js +101 -94
  61. package/src/commands/sandbox.js +125 -0
  62. package/src/commands/secrets.js +201 -0
  63. package/src/commands/sessions.js +110 -51
  64. package/src/commands/setup.js +102 -543
  65. package/src/commands/signal.js +447 -18
  66. package/src/commands/skills.js +67 -1
  67. package/src/commands/sms.js +123 -19
  68. package/src/commands/status.js +101 -127
  69. package/src/commands/system.js +53 -0
  70. package/src/commands/tasks.js +208 -100
  71. package/src/commands/terminal.js +139 -0
  72. package/src/commands/thread-ownership.js +157 -0
  73. package/src/commands/transcripts.js +95 -0
  74. package/src/commands/tui.js +41 -0
  75. package/src/commands/uninstall.js +73 -92
  76. package/src/commands/update.js +146 -91
  77. package/src/commands/voice.js +82 -0
  78. package/src/commands/vydra.js +98 -0
  79. package/src/commands/webhooks.js +58 -66
  80. package/src/commands/wiki.js +783 -0
  81. package/src/commands/workboard.js +207 -0
  82. package/src/tools/audio_understanding.js +154 -0
  83. package/src/tools/browser.js +112 -0
  84. package/src/tools/canvas.js +104 -0
  85. package/src/tools/document_extract.js +84 -0
  86. package/src/tools/duckduckgo.js +54 -0
  87. package/src/tools/exa_search.js +66 -0
  88. package/src/tools/firecrawl.js +104 -0
  89. package/src/tools/image_generation.js +99 -0
  90. package/src/tools/llm_task.js +118 -0
  91. package/src/tools/media_understanding.js +128 -0
  92. package/src/tools/music_generation.js +113 -0
  93. package/src/tools/parallel_search.js +77 -0
  94. package/src/tools/phone_control.js +80 -0
  95. package/src/tools/phone_control_enhanced.js +184 -0
  96. package/src/tools/searxng.js +61 -0
  97. package/src/tools/speech_to_text.js +135 -0
  98. package/src/tools/text_to_speech.js +105 -0
  99. package/src/tools/thread_ownership.js +88 -0
  100. package/src/tools/video_generation.js +72 -0
  101. package/src/tools/web_readability.js +104 -0
  102. package/src/utils/agents-md.js +85 -0
  103. package/src/utils/api.js +39 -40
  104. package/src/utils/format.js +144 -0
  105. package/src/utils/headless.js +2 -1
  106. package/src/utils/memory.js +200 -0
  107. package/src/utils/parallel-tools.js +106 -0
  108. package/src/utils/sub-agent.js +148 -0
  109. package/src/utils/token-budget.js +304 -0
  110. package/src/utils/tool-runner.js +7 -5
  111. package/src/utils/web-fetch.js +107 -0
@@ -0,0 +1,157 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, saveConfig } = require('../utils/config');
3
+
4
+ const MENTION_TTL_MS = 300 * 1000;
5
+
6
+ function threadOwnership(args) {
7
+ const [action, ...params] = args || [];
8
+
9
+ if (!action || action === 'status') return statusOwnership();
10
+ if (action === 'list') return listOwnership();
11
+ if (action === 'assign') return assignOwnership(params[0], params[1], params[2]);
12
+ if (action === 'release') return releaseOwnership(params[0], params[1]);
13
+ if (action === 'check') return checkOwnership(params[0], params[1], params[2]);
14
+ if (action === 'agent') return setDefaultAgent(params[0]);
15
+
16
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
17
+ console.log(chalk.gray(' Kullanım: natureco thread-ownership [status|list|assign|release|check|agent]\n'));
18
+ process.exit(1);
19
+ }
20
+
21
+ function statusOwnership() {
22
+ const config = getConfig();
23
+ const to = config.threadOwnership || {};
24
+ const agents = to.agents || { default: config.agentName || 'default' };
25
+
26
+ const totalAssigned = Object.keys(to).filter(k => k !== 'agents').length;
27
+
28
+ console.log(chalk.cyan('\n 🧵 Thread Ownership\n'));
29
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
30
+ console.log(` ${chalk.white('Default Agent:')} ${chalk.cyan(agents.default || 'default')}`);
31
+ console.log(` ${chalk.white('Assigned:')} ${chalk.cyan(totalAssigned)} threads`);
32
+ console.log(` ${chalk.white('Slack Forwarder:')} ${chalk.gray(to.forwarderUrl || process.env.SLACK_FORWARDER_URL || 'not configured')}`);
33
+ console.log(` ${chalk.white('Config Path:')} ${chalk.gray('~/.natureco/config.json → threadOwnership')}`);
34
+ console.log(chalk.gray('\n Commands:'));
35
+ console.log(chalk.cyan(' list') + chalk.gray(' List assignments'));
36
+ console.log(chalk.cyan(' assign <thread> <agent> [channel]') + chalk.gray(' Assign thread'));
37
+ console.log(chalk.cyan(' release <thread> [channel]') + chalk.gray(' Release thread'));
38
+ console.log(chalk.cyan(' check <thread> <channel> <agent>') + chalk.gray(' Check if agent can claim'));
39
+ console.log(chalk.cyan(' agent <name>') + chalk.gray(' Set default agent'));
40
+ console.log();
41
+ }
42
+
43
+ function listOwnership() {
44
+ const config = getConfig();
45
+ const to = config.threadOwnership || {};
46
+ const entries = Object.entries(to).filter(([k]) => k !== 'agents' && k !== 'forwarderUrl');
47
+
48
+ console.log(chalk.cyan(`\n 🧵 Thread Assignments (${entries.length})\n`));
49
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
50
+
51
+ if (entries.length === 0) {
52
+ console.log(chalk.gray(' Atanmış thread yok.\n'));
53
+ return;
54
+ }
55
+
56
+ for (const [threadId, data] of entries) {
57
+ const agent = typeof data === 'string' ? data : data.agent || 'unknown';
58
+ const channel = typeof data === 'string' ? '-' : data.channel || '-';
59
+ const ts = typeof data === 'string' ? '-' : data.since ? new Date(data.since).toLocaleString() : '-';
60
+ console.log(` ${chalk.cyan(threadId.substring(0, 30))}`);
61
+ console.log(` ${chalk.gray('Agent:')} ${chalk.white(agent)}`);
62
+ console.log(` ${chalk.gray('Channel:')} ${chalk.white(channel)}`);
63
+ if (ts !== '-') console.log(` ${chalk.gray('Since:')} ${chalk.gray(ts)}`);
64
+ }
65
+ console.log();
66
+ }
67
+
68
+ function assignOwnership(threadId, agentName, channel) {
69
+ if (!threadId || !agentName) {
70
+ console.log(chalk.red('\n ❌ threadId ve agentName gerekli\n'));
71
+ console.log(chalk.cyan(' natureco thread-ownership assign C012345 "agent-bob" slack\n'));
72
+ process.exit(1);
73
+ }
74
+
75
+ const config = getConfig();
76
+ if (!config.threadOwnership) config.threadOwnership = {};
77
+ config.threadOwnership[threadId] = { agent: agentName, channel: channel || 'slack', since: new Date().toISOString() };
78
+ saveConfig(config);
79
+
80
+ console.log(chalk.green(`\n ✅ Thread ${threadId} → ${agentName}${channel ? ` (${channel})` : ''}\n`));
81
+ }
82
+
83
+ function releaseOwnership(threadId, channel) {
84
+ if (!threadId) {
85
+ console.log(chalk.red('\n ❌ threadId gerekli\n'));
86
+ process.exit(1);
87
+ }
88
+
89
+ const config = getConfig();
90
+ if (!config.threadOwnership) config.threadOwnership = {};
91
+
92
+ if (channel) {
93
+ const found = Object.entries(config.threadOwnership).find(([k, v]) =>
94
+ k === threadId && (typeof v === 'string' ? true : v.channel === channel)
95
+ );
96
+ if (found) delete config.threadOwnership[found[0]];
97
+ } else {
98
+ delete config.threadOwnership[threadId];
99
+ }
100
+
101
+ saveConfig(config);
102
+ console.log(chalk.gray(`\n 🔓 Thread ${threadId} serbest bırakıldı\n`));
103
+ }
104
+
105
+ function checkOwnership(threadId, channel, agentName) {
106
+ if (!threadId || !channel || !agentName) {
107
+ console.log(chalk.red('\n ❌ threadId, channel ve agentName gerekli\n'));
108
+ console.log(chalk.cyan(' natureco thread-ownership check C012345 slack agent-bob\n'));
109
+ process.exit(1);
110
+ }
111
+
112
+ const config = getConfig();
113
+ const to = config.threadOwnership || {};
114
+ const entry = Object.entries(to).find(([k, v]) => {
115
+ if (k !== threadId) return false;
116
+ if (typeof v === 'string') return true;
117
+ return v.channel === channel || !v.channel;
118
+ });
119
+
120
+ if (!entry) {
121
+ console.log(chalk.green(`\n ✅ Thread ${threadId} sahipsiz — ${agentName} alabilir\n`));
122
+ return;
123
+ }
124
+
125
+ const [, data] = entry;
126
+ const owner = typeof data === 'string' ? data : data.agent;
127
+ const since = typeof data === 'string' ? '-' : data.since ? new Date(data.since).toLocaleString() : '-';
128
+
129
+ if (owner === agentName) {
130
+ console.log(chalk.green(`\n ✅ Thread ${threadId} zaten ${agentName}'e ait\n`));
131
+ return;
132
+ }
133
+
134
+ const expired = data.since ? (Date.now() - new Date(data.since).getTime() > MENTION_TTL_MS) : false;
135
+ if (expired) {
136
+ console.log(chalk.yellow(`\n ⚠️ Thread ${threadId} süresi dolmuş (${owner}), ${agentName} alabilir\n`));
137
+ return;
138
+ }
139
+
140
+ console.log(chalk.red(`\n ❌ Thread ${threadId} ${owner}'e ait (since: ${since}) — ${agentName} alamaz\n`));
141
+ }
142
+
143
+ function setDefaultAgent(name) {
144
+ if (!name) {
145
+ console.log(chalk.red('\n ❌ Agent adı gerekli\n'));
146
+ process.exit(1);
147
+ }
148
+
149
+ const config = getConfig();
150
+ if (!config.threadOwnership) config.threadOwnership = {};
151
+ if (!config.threadOwnership.agents) config.threadOwnership.agents = {};
152
+ config.threadOwnership.agents.default = name;
153
+ saveConfig(config);
154
+ console.log(chalk.green(`\n ✅ Default agent set to: ${name}\n`));
155
+ }
156
+
157
+ module.exports = threadOwnership;
@@ -0,0 +1,95 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ function transcripts(args) {
7
+ const [action, ...params] = args || [];
8
+
9
+ if (!action || action === 'list') return listTranscripts();
10
+ if (action === 'show') return showTranscript(params[0]);
11
+ if (action === 'delete') return deleteTranscript(params[0]);
12
+
13
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
14
+ console.log(chalk.gray(' Kullanım: natureco transcripts [list|show|delete]\n'));
15
+ process.exit(1);
16
+ }
17
+
18
+ function listTranscripts() {
19
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
20
+ console.log(chalk.cyan('\n 📜 Transcripts\n'));
21
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
22
+
23
+ if (!fs.existsSync(sessionsDir)) {
24
+ console.log(chalk.gray(' No transcripts found.\n'));
25
+ return;
26
+ }
27
+
28
+ const files = fs.readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
29
+ if (files.length === 0) {
30
+ console.log(chalk.gray(' No transcripts found.\n'));
31
+ return;
32
+ }
33
+
34
+ for (const f of files.sort().reverse().slice(0, 20)) {
35
+ const stat = fs.statSync(path.join(sessionsDir, f));
36
+ const size = (stat.size / 1024).toFixed(1);
37
+ const date = stat.birthtime.toLocaleString();
38
+ const preview = f.replace('.json', '').substring(0, 40);
39
+ console.log(` ${chalk.cyan('●')} ${chalk.white(preview)} ${chalk.gray(`(${size} KB, ${date})`)}`);
40
+ }
41
+ console.log();
42
+ }
43
+
44
+ function showTranscript(id) {
45
+ if (!id) {
46
+ console.log(chalk.red('\n ❌ Transcript ID gerekli\n'));
47
+ process.exit(1);
48
+ }
49
+
50
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
51
+ const file = path.join(sessionsDir, `${id}.json`);
52
+
53
+ if (!fs.existsSync(file)) {
54
+ const alt = path.join(sessionsDir, id);
55
+ if (!fs.existsSync(alt)) {
56
+ console.log(chalk.red(`\n ❌ Transcript bulunamadı: ${id}\n`));
57
+ process.exit(1);
58
+ }
59
+ const content = fs.readFileSync(alt, 'utf8');
60
+ console.log(chalk.gray(`\n ${alt}\n`));
61
+ console.log(content.substring(0, 5000));
62
+ if (content.length > 5000) console.log(chalk.gray('\n ... (truncated)\n'));
63
+ return;
64
+ }
65
+
66
+ const content = fs.readFileSync(file, 'utf8');
67
+ console.log(chalk.gray(`\n ${file}\n`));
68
+ const parsed = JSON.parse(content);
69
+ console.log(JSON.stringify(parsed, null, 2).substring(0, 5000));
70
+ console.log();
71
+ }
72
+
73
+ function deleteTranscript(id) {
74
+ if (!id) {
75
+ console.log(chalk.red('\n ❌ Transcript ID gerekli\n'));
76
+ process.exit(1);
77
+ }
78
+
79
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
80
+ const file = path.join(sessionsDir, `${id}.json`);
81
+
82
+ let target = file;
83
+ if (!fs.existsSync(target)) {
84
+ target = path.join(sessionsDir, id);
85
+ if (!fs.existsSync(target)) {
86
+ console.log(chalk.red(`\n ❌ Transcript bulunamadı: ${id}\n`));
87
+ process.exit(1);
88
+ }
89
+ }
90
+
91
+ fs.unlinkSync(target);
92
+ console.log(chalk.green(`\n 🗑️ Transcript silindi: ${id}\n`));
93
+ }
94
+
95
+ module.exports = transcripts;
@@ -0,0 +1,41 @@
1
+ const chalk = require('chalk');
2
+
3
+ function tui(args) {
4
+ const [action, ...params] = args || [];
5
+
6
+ if (!action || action === 'start') return cmdStart();
7
+ if (action === 'local') return cmdLocal();
8
+ if (action === 'status') return cmdStatus();
9
+
10
+ console.log(chalk.red(`\n Unknown tui action: ${action}\n`));
11
+ console.log(chalk.gray(' Usage: natureco tui <action>'));
12
+ console.log(chalk.gray(' Actions: start, local, status\n'));
13
+ process.exit(1);
14
+ }
15
+
16
+ function cmdStart() {
17
+ console.log(chalk.cyan('\n TUI Launcher\n'));
18
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
19
+ console.log(chalk.gray(' TUI would launch here.'));
20
+ console.log(chalk.gray(' This is a stub — no real TUI implementation.\n'));
21
+ }
22
+
23
+ function cmdLocal() {
24
+ console.log(chalk.cyan('\n Local TUI\n'));
25
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
26
+ console.log(chalk.gray(' Local TUI would launch here.'));
27
+ console.log(chalk.gray(' This is a stub — no real TUI implementation.\n'));
28
+ }
29
+
30
+ function cmdStatus() {
31
+ console.log(chalk.cyan('\n TUI Status\n'));
32
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
33
+ console.log(` ${chalk.white('Status:')} ${chalk.gray('Not running')}`);
34
+ console.log(` ${chalk.white('Type:')} ${chalk.gray('Terminal UI')}`);
35
+ console.log('');
36
+ console.log(chalk.gray(' Start with: ') + chalk.cyan('natureco tui start'));
37
+ console.log(chalk.gray(' Local: ') + chalk.cyan('natureco tui local'));
38
+ console.log('');
39
+ }
40
+
41
+ module.exports = tui;
@@ -1,92 +1,73 @@
1
- const chalk = require('chalk');
2
- const inquirer = require('../utils/inquirer-wrapper');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const { CONFIG_DIR } = require('../utils/config');
7
-
8
- async function uninstall(args) {
9
- const all = args?.includes('--all');
10
- const yes = args?.includes('--yes') || args?.includes('-y');
11
- const dryRun = args?.includes('--dry-run');
12
-
13
- console.log('');
14
- console.log(chalk.gray(' ' + '─'.repeat(48)));
15
- console.log(chalk.red.bold('\n NatureCo CLI — Kaldırma\n'));
16
-
17
- const actions = [];
18
-
19
- // Gateway service PID
20
- const pidFile = path.join(CONFIG_DIR, 'gateway.pid');
21
- if (fs.existsSync(pidFile)) actions.push('Gateway durdurulacak');
22
-
23
- // Config ve data
24
- if (all) {
25
- actions.push(`~/.natureco/ klasörü silinecek (config, hafıza, session'lar)`);
26
- } else {
27
- actions.push('Gateway ve dashboard durdurulacak');
28
- actions.push('~/.natureco/gateway.pid ve dashboard.pid silinecek');
29
- }
30
-
31
- actions.push('npm uninstall -g natureco-cli komutu gösterilecek');
32
-
33
- if (dryRun) {
34
- console.log(chalk.yellow(' Dry-run modu — hiçbir şey silinmeyecek\n'));
35
- actions.forEach(a => console.log(chalk.gray(` • ${a}`)));
36
- console.log('');
37
- return;
38
- }
39
-
40
- console.log(chalk.yellow(' Yapılacaklar:\n'));
41
- actions.forEach(a => console.log(chalk.gray(` • ${a}`)));
42
- console.log('');
43
-
44
- if (!yes) {
45
- const { confirm } = await inquirer.prompt([{
46
- type: 'confirm',
47
- name: 'confirm',
48
- message: ' Devam etmek istediğinizden emin misiniz?',
49
- default: false,
50
- }]);
51
- if (!confirm) {
52
- console.log(chalk.gray('\n İptal edildi.\n'));
53
- return;
54
- }
55
- }
56
-
57
- // Gateway durdur
58
- if (fs.existsSync(pidFile)) {
59
- try {
60
- const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim());
61
- if (pid) process.kill(pid, 'SIGTERM');
62
- fs.unlinkSync(pidFile);
63
- console.log(chalk.green(' Gateway durduruldu'));
64
- } catch {}
65
- }
66
-
67
- // Dashboard durdur
68
- const dashPid = path.join(CONFIG_DIR, 'dashboard.pid');
69
- if (fs.existsSync(dashPid)) {
70
- try {
71
- const pid = parseInt(fs.readFileSync(dashPid, 'utf-8').trim());
72
- if (pid) process.kill(pid, 'SIGTERM');
73
- fs.unlinkSync(dashPid);
74
- console.log(chalk.green(' ✓ Dashboard durduruldu'));
75
- } catch {}
76
- }
77
-
78
- // --all ise tüm veriyi sil
79
- if (all && fs.existsSync(CONFIG_DIR)) {
80
- fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
81
- console.log(chalk.green(' ✓ ~/.natureco/ silindi'));
82
- }
83
-
84
- console.log('');
85
- console.log(chalk.green(' ✓ Temizlik tamamlandı!'));
86
- console.log('');
87
- console.log(chalk.gray(' CLI\'yi tamamen kaldırmak için:'));
88
- console.log(chalk.cyan(' npm uninstall -g natureco-cli'));
89
- console.log('');
90
- }
91
-
92
- module.exports = uninstall;
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { execSync } = require('child_process');
6
+ const readline = require('readline');
7
+
8
+ const BASE_DIR = path.join(os.homedir(), '.natureco');
9
+
10
+ function rlQuestion(query) {
11
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
12
+ return new Promise(resolve => {
13
+ rl.question(query, answer => { rl.close(); resolve(answer.trim().toLowerCase()); });
14
+ });
15
+ }
16
+
17
+ async function uninstall(params) {
18
+ try {
19
+ const [action] = params || [];
20
+
21
+ if (action === 'dry-run') return cmdDryRun();
22
+
23
+ if (!action || action === 'run') return await cmdRun();
24
+
25
+ console.log(chalk.red(`\n Unknown uninstall action: ${action}\n`));
26
+ console.log(chalk.gray(' Usage: natureco uninstall [run|dry-run]\n'));
27
+ } catch (err) {
28
+ console.log(chalk.red(`\n Uninstall error: ${err.message}\n`));
29
+ }
30
+ }
31
+
32
+ function cmdDryRun() {
33
+ console.log(chalk.cyan('\n Uninstall — Dry Run\n'));
34
+ console.log(chalk.gray(' Would remove:\n'));
35
+
36
+ if (fs.existsSync(BASE_DIR)) {
37
+ console.log(chalk.gray(' • ') + chalk.white('~/.natureco/') + chalk.gray(' — all config and data'));
38
+ } else {
39
+ console.log(chalk.gray(' • ') + chalk.white('~/.natureco/') + chalk.gray(' — not found'));
40
+ }
41
+
42
+ console.log(chalk.gray('') + chalk.white('npm uninstall -g natureco-cli'));
43
+ console.log(chalk.gray(' • ') + chalk.white('Remove global symlink\n'));
44
+ }
45
+
46
+ async function cmdRun() {
47
+ console.log(chalk.cyan('\n Uninstall NatureCo\n'));
48
+
49
+ const answer = await rlQuestion(chalk.red(' This will remove all NatureCo data. Continue? [y/N]: '));
50
+ if (answer !== 'y' && answer !== 'yes') {
51
+ console.log(chalk.gray('\n Cancelled.\n'));
52
+ return;
53
+ }
54
+
55
+ if (fs.existsSync(BASE_DIR)) {
56
+ console.log(chalk.gray(' Removing ~/.natureco/...'));
57
+ fs.rmSync(BASE_DIR, { recursive: true, force: true });
58
+ console.log(chalk.green(' ✓ Removed ~/.natureco/'));
59
+ }
60
+
61
+ console.log(chalk.gray(' Uninstalling global package...'));
62
+ try {
63
+ execSync('npm uninstall -g natureco-cli', { stdio: 'inherit' });
64
+ console.log(chalk.green(' ✓ Global package uninstalled'));
65
+ } catch (e) {
66
+ console.log(chalk.yellow(' Could not uninstall package: ' + e.message));
67
+ console.log(chalk.gray(' Try manually: npm uninstall -g natureco-cli'));
68
+ }
69
+
70
+ console.log(chalk.green('\n Uninstall complete.\n'));
71
+ }
72
+
73
+ module.exports = uninstall;