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,26 +1,41 @@
1
1
  const chalk = require('chalk');
2
+ const F = require('../utils/format');
2
3
  const path = require('path');
3
- const { getConfig, setConfigValue, getAllConfig, listBackups, restoreConfig, CONFIG_BACKUP_DIR } = require('../utils/config');
4
+ const fs = require('fs');
5
+ const { getConfig, setConfigValue, getAllConfig, listBackups, restoreConfig, saveConfig, CONFIG_FILE, CONFIG_BACKUP_DIR } = require('../utils/config');
6
+ const TB = require('../utils/token-budget');
4
7
 
5
8
  function config(args) {
6
9
  const [action, key, ...valueParts] = args;
7
10
 
8
11
  if (!action) {
9
- console.log(chalk.red('\n❌ Kullanım: natureco config <get|set|list|backups|restore> [key] [value]\n'));
12
+ F.error('Kullanım: natureco config <get|set|unset|list|file|schema|validate|backups|restore> [key] [value]');
10
13
  process.exit(1);
11
14
  }
12
15
 
16
+ const SENSITIVE_KEYS = ['apiKey', 'providerApiKey', 'providerApiKey1', 'providerApiKey2', 'secret', 'token', 'password', 'webhookSecret'];
17
+
18
+ function maskSensitive(key, value) {
19
+ if (typeof value !== 'string' || value.length < 8) return value;
20
+ const lower = key.toLowerCase();
21
+ if (!SENSITIVE_KEYS.some(sk => lower.includes(sk.toLowerCase()))) return value;
22
+ return value.slice(0, 4) + '*'.repeat(Math.min(value.length - 8, 16)) + value.slice(-4);
23
+ }
24
+
13
25
  if (action === 'list') {
14
26
  const cfg = getAllConfig();
15
- console.log(chalk.green.bold('\n╭─ Config ─╮\n'));
16
- console.log(JSON.stringify(cfg, null, 2));
17
- console.log('');
27
+ F.header('Configuration');
28
+ const rows = Object.entries(cfg).map(([k, v]) => [
29
+ k,
30
+ maskSensitive(k, typeof v === 'string' ? v : JSON.stringify(v)),
31
+ ]);
32
+ F.table(['Key', 'Value'], rows);
18
33
  return;
19
34
  }
20
35
 
21
36
  if (action === 'get') {
22
37
  if (!key) {
23
- console.log(chalk.red('\n❌ Key belirtilmedi.\n'));
38
+ F.error('Key belirtilmedi.');
24
39
  process.exit(1);
25
40
  }
26
41
  const cfg = getConfig();
@@ -30,21 +45,20 @@ function config(args) {
30
45
  value = value?.[k];
31
46
  }
32
47
  if (value === undefined) {
33
- console.log(chalk.gray(`\n${key}: (tanımlı değil)\n`));
48
+ F.info(`${key}: (tanımlı değil)`);
34
49
  } else {
35
- console.log(chalk.cyan(`\n${key}:`), chalk.white(JSON.stringify(value, null, 2)));
36
- console.log('');
50
+ F.kv(key, maskSensitive(key, JSON.stringify(value, null, 2)));
37
51
  }
38
52
  return;
39
53
  }
40
54
 
41
55
  if (action === 'set') {
42
56
  if (!key) {
43
- console.log(chalk.red('\n❌ Key belirtilmedi.\n'));
57
+ F.error('Key belirtilmedi.');
44
58
  process.exit(1);
45
59
  }
46
60
  if (valueParts.length === 0) {
47
- console.log(chalk.red('\n❌ Value belirtilmedi.\n'));
61
+ F.error('Value belirtilmedi.');
48
62
  process.exit(1);
49
63
  }
50
64
  const value = valueParts.join(' ');
@@ -55,24 +69,121 @@ function config(args) {
55
69
  } catch {}
56
70
 
57
71
  setConfigValue(key, parsedValue);
58
- console.log(chalk.green(`\n✅ ${key} = ${JSON.stringify(parsedValue)}\n`));
72
+ F.success(`${key} = ${JSON.stringify(parsedValue)}`);
73
+ return;
74
+ }
75
+
76
+ if (action === 'unset') {
77
+ if (!key) {
78
+ F.error('Key belirtilmedi.');
79
+ process.exit(1);
80
+ }
81
+ const cfg = getConfig();
82
+ const keys = key.split('.');
83
+ let obj = cfg;
84
+ for (let i = 0; i < keys.length - 1; i++) {
85
+ obj = obj?.[keys[i]];
86
+ }
87
+ if (obj && keys[keys.length - 1] in obj) {
88
+ delete obj[keys[keys.length - 1]];
89
+ }
90
+ saveConfig(cfg);
91
+ F.success(`Unset: ${key}`);
92
+ return;
93
+ }
94
+
95
+ if (action === 'file') {
96
+ const configPath = CONFIG_FILE;
97
+ const exists = fs.existsSync(configPath);
98
+ F.header('Config File');
99
+ F.kv('Path', configPath);
100
+ if (exists) {
101
+ const stats = fs.statSync(configPath);
102
+ const sizeKB = (stats.size / 1024).toFixed(2);
103
+ F.kv('Size', `${sizeKB} KB`);
104
+ F.kv('Last Modified', String(stats.mtime));
105
+ const content = fs.readFileSync(configPath, 'utf8');
106
+ try {
107
+ const parsed = JSON.parse(content);
108
+ const keys = Object.keys(parsed);
109
+ F.kv('Keys', keys.length ? keys.join(', ') : '(empty)');
110
+ } catch {
111
+ F.error('(invalid JSON)');
112
+ }
113
+ } else {
114
+ F.warning('(file does not exist)');
115
+ }
116
+ return;
117
+ }
118
+
119
+ if (action === 'schema') {
120
+ F.section('Config Schema');
121
+ const schema = {
122
+ apiKey: { type: 'string', description: 'API key for the provider', required: true },
123
+ providerUrl: { type: 'string', description: 'Base URL of the provider API', required: true },
124
+ providerModel: { type: 'string', description: 'Default model identifier', required: false, default: 'gpt-4' },
125
+ temperature: { type: 'number', description: 'Sampling temperature (0-2)', required: false, default: 0.7 },
126
+ maxTokens: { type: 'number', description: 'Maximum tokens per response', required: false, default: 2048 },
127
+ systemPrompt: { type: 'string', description: 'Custom system prompt', required: false },
128
+ proxy: { type: 'object', description: 'Proxy configuration', required: false, properties: { host: { type: 'string' }, port: { type: 'number' } } },
129
+ timeout: { type: 'number', description: 'Request timeout in milliseconds', required: false, default: 30000 },
130
+ organization: { type: 'string', description: 'Organization ID for multi-tenant setups', required: false },
131
+ };
132
+ const rows = Object.entries(schema).map(([k, v]) => [
133
+ v.required ? `${k}*` : k,
134
+ v.type,
135
+ v.description,
136
+ v.default !== undefined ? JSON.stringify(v.default) : '—',
137
+ ]);
138
+ F.table(['Field', 'Type', 'Description', 'Default'], rows);
139
+ F.meta('* = required');
140
+ return;
141
+ }
142
+
143
+ if (action === 'validate') {
144
+ const cfg = getConfig();
145
+ F.section('Config Validation');
146
+ const checks = [
147
+ { field: 'apiKey', label: 'API Key', required: true },
148
+ { field: 'providerUrl', label: 'Provider URL', required: true },
149
+ { field: 'providerModel', label: 'Provider Model', required: false },
150
+ ];
151
+ let allPass = true;
152
+ for (const check of checks) {
153
+ const value = cfg[check.field];
154
+ if (check.required && (!value || typeof value !== 'string')) {
155
+ F.error(`${check.label}: FAIL (required)`);
156
+ allPass = false;
157
+ } else if (value && typeof value !== 'string') {
158
+ F.warning(`${check.label}: WARN (expected string, got ${typeof value})`);
159
+ } else if (value) {
160
+ F.success(`${check.label}: PASS`);
161
+ } else {
162
+ F.info(`${check.label}: not set`);
163
+ }
164
+ }
165
+ if (allPass) {
166
+ F.success('All required fields are set.');
167
+ } else {
168
+ F.error('Some required fields are missing.');
169
+ }
59
170
  return;
60
171
  }
61
172
 
62
173
  if (action === 'backups' || action === 'backup') {
63
174
  const backups = listBackups();
64
- console.log(chalk.cyan.bold('\n Config Yedekleri\n'));
175
+ F.section('Config Yedekleri');
65
176
  if (backups.length === 0) {
66
- console.log(chalk.gray(' Henüz yedek alınmamış.\n'));
177
+ F.info('Hen\u00fcz yedek al\u0131nmam\u0131\u015f.');
67
178
  return;
68
179
  }
69
- backups.forEach((f, i) => {
180
+ const rows = backups.map((f, i) => {
70
181
  const ts = f.replace(/^config-|\.json$/g, '').replace(/T/, ' ').replace(/-/g, ':').replace(/:[^:]*$/, '');
71
- console.log(chalk.white(` ${i + 1}. ${ts}`));
72
- console.log(chalk.gray(` ${path.join(CONFIG_BACKUP_DIR, f)}`));
182
+ return [String(i + 1), ts, path.join(CONFIG_BACKUP_DIR, f)];
73
183
  });
74
- console.log(chalk.gray(`\n Geri yüklemek için: natureco config restore <dosya-adı>`));
75
- console.log(chalk.gray(` Örnek: natureco config restore ${backups[0] || 'config-....json'}\n`));
184
+ F.table(['#', 'Tarih', 'Dosya'], rows);
185
+ F.meta('Geri y\u00fcklemek i\u00e7in: natureco config restore <dosya-ad\u0131>');
186
+ F.meta(`\u00d6rnek: natureco config restore ${backups[0] || 'config-....json'}`);
76
187
  return;
77
188
  }
78
189
 
@@ -81,31 +192,118 @@ function config(args) {
81
192
  if (!backupId) {
82
193
  const backups = listBackups();
83
194
  if (backups.length === 0) {
84
- console.log(chalk.red('\n❌ Geri yüklenecek yedek bulunamadı.\n'));
195
+ F.error('Geri y\u00fcklenecek yedek bulunamad\u0131.');
85
196
  process.exit(1);
86
197
  }
87
- console.log(chalk.cyan.bold('\n Geri Yükleme\n'));
88
- console.log(chalk.gray(' En son yedek: ') + chalk.white(backups[0]));
89
- console.log('');
90
- console.log(chalk.gray(' Kullanım: ') + chalk.cyan(`natureco config restore ${backups[0]}`));
91
- console.log(chalk.gray(' Yedekleri listelemek için: ') + chalk.cyan('natureco config backups\n'));
198
+ F.section('Geri Y\u00fckleme');
199
+ F.kv('En son yedek', backups[0]);
200
+ F.meta(`Kullan\u0131m: natureco config restore ${backups[0]}`);
201
+ F.meta('Yedekleri listelemek i\u00e7in: natureco config backups');
92
202
  return;
93
203
  }
94
204
 
95
205
  try {
96
206
  const result = restoreConfig(backupId);
97
- console.log(chalk.green(`\n✅ Config geri yüklendi: ${result.timestamp}\n`));
98
- console.log(chalk.gray(` Kaynak: ${result.path}\n`));
207
+ F.success(`Config geri y\u00fcklendi: ${result.timestamp}`);
208
+ F.meta(`Kaynak: ${result.path}`);
99
209
  } catch (err) {
100
- console.log(chalk.red(`\n❌ Geri yükleme başarısız: ${err.message}\n`));
210
+ F.error(`Geri y\u00fckleme ba\u015far\u0131s\u0131z: ${err.message}`);
101
211
  process.exit(1);
102
212
  }
103
213
  return;
104
214
  }
105
215
 
106
- console.log(chalk.red(`\n❌ Geçersiz action: ${action}\n`));
107
- console.log(chalk.gray(' Kullanım: natureco config <get|set|list|backups|restore> [key] [value]\n'));
216
+ if (action === 'budget') {
217
+ return configBudget(key, valueParts);
218
+ }
219
+
220
+ F.error(`Ge\u00e7ersiz action: ${action}`);
221
+ F.meta('Kullan\u0131m: natureco config <get|set|unset|list|file|schema|validate|backups|restore|budget> [key] [value]');
108
222
  process.exit(1);
109
223
  }
110
224
 
225
+ function configBudget(sub, args) {
226
+ if (!sub || sub === 'show') {
227
+ const b = TB.load();
228
+ F.header('Token Budget');
229
+ F.kv('Preset', b.preset || 'balanced');
230
+ F.kv('Max Context Tokens', String(b.maxContextTokens));
231
+ F.kv('Preserve Recent Tokens', String(b.preserveRecentTokens));
232
+ F.kv('Tail Turns', String(b.tailTurns));
233
+ F.divider();
234
+ F.section('Output Limits');
235
+ F.kv('Tool Max Lines', String(b.toolMaxLines));
236
+ F.kv('Tool Max Chars', String(b.toolMaxChars));
237
+ F.kv('MCP Desc Max Chars', String(b.mcpDescMaxChars));
238
+ F.divider();
239
+ F.section('Content Truncation');
240
+ F.kv('System Prompt Max', String(b.systemPromptMaxChars));
241
+ F.kv('Memory Max Facts', String(b.memoryMaxFacts));
242
+ F.kv('Project Memory Max', String(b.projectMemoryMaxChars));
243
+ F.kv('File Content Max', String(b.fileContentMaxChars));
244
+ F.divider();
245
+ F.section('Conversation');
246
+ F.kv('Messages on Disk', String(b.conversationOnDisk));
247
+ F.kv('Messages in Context', String(b.conversationInContext));
248
+ F.kv('Auto Compact', String(b.autoCompact));
249
+ F.kv('Reserved Tokens', String(b.reservedTokens));
250
+ F.meta('');
251
+ F.meta('Switch preset: natureco config budget preset <efficient|balanced|quality>');
252
+ F.meta('Set a value: natureco config budget set <key> <value>');
253
+ return;
254
+ }
255
+
256
+ if (sub === 'preset') {
257
+ const name = args[0];
258
+ if (!name || !['efficient', 'balanced', 'quality'].includes(name)) {
259
+ F.error('Preset: efficient, balanced, quality');
260
+ F.table(['Preset', 'Description', 'Context'], TB.getPresets().map(p => [p.key, p.label, String(p.maxContextTokens)]));
261
+ return;
262
+ }
263
+ TB.setPreset(name);
264
+ F.success('Token budget preset: ' + name);
265
+ return;
266
+ }
267
+
268
+ if (sub === 'set') {
269
+ const key = args[0];
270
+ const val = args[1];
271
+ if (!key || val === undefined) {
272
+ F.error('Kullan\u0131m: natureco config budget set <key> <value>');
273
+ return;
274
+ }
275
+ const budget = TB.load();
276
+ if (!(key in budget)) {
277
+ F.error('Bilinmeyen budget key: ' + key);
278
+ return;
279
+ }
280
+ const num = Number(val);
281
+ budget[key] = isNaN(num) ? val : num;
282
+ TB.save(budget);
283
+ F.success(key + ' = ' + budget[key]);
284
+ return;
285
+ }
286
+
287
+ if (sub === 'usage') {
288
+ const usage = TB.getAllUsage();
289
+ if (!usage || Object.keys(usage).length === 0) {
290
+ F.info('Hen\u00fcz token kullan\u0131m\u0131 kaydedilmedi.');
291
+ return;
292
+ }
293
+ F.header('Token Usage');
294
+ const rows = Object.entries(usage).map(([sid, u]) => [
295
+ sid.slice(0, 20),
296
+ String(u.total || 0),
297
+ String(u.input || 0),
298
+ String(u.output || 0),
299
+ String(u.count || 0)
300
+ ]);
301
+ F.table(['Session', 'Total', 'Input', 'Output', 'Calls'], rows);
302
+ return;
303
+ }
304
+
305
+ F.error('Budget alt komutu: ' + sub);
306
+ F.meta('Kullan\u0131m: natureco config budget <show|preset|set|usage>');
307
+ }
308
+
111
309
  module.exports = config;
@@ -1,6 +1,23 @@
1
1
  const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
2
5
  const readline = require('readline');
3
6
 
7
+ const BASE_DIR = path.join(os.homedir(), '.natureco');
8
+ const CONFIG_FILE = path.join(BASE_DIR, 'config.json');
9
+
10
+ function getConfig() {
11
+ if (!fs.existsSync(CONFIG_FILE)) return {};
12
+ try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); }
13
+ catch { return {}; }
14
+ }
15
+
16
+ function saveConfig(data) {
17
+ if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
18
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
19
+ }
20
+
4
21
  function rlQuestion(query) {
5
22
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6
23
  return new Promise(resolve => {
@@ -8,86 +25,86 @@ function rlQuestion(query) {
8
25
  });
9
26
  }
10
27
 
11
- async function configure(args) {
12
- console.log(chalk.cyan('\n ⚙️ Interactive Configuration\n'));
13
- console.log(chalk.gray(' Press Ctrl+C anytime to cancel.\n'));
28
+ async function configure(params) {
29
+ try {
30
+ const [action] = params || [];
14
31
 
15
- const { getConfig, saveConfig } = require('../utils/config');
16
- const config = getConfig();
32
+ if (!action) return cmdMenu();
33
+ if (action === 'gateway') return await cmdGateway();
34
+ if (action === 'auth') return await cmdAuth();
35
+ if (action === 'channels') return cmdChannels();
36
+ if (action === 'plugins') return cmdPlugins();
37
+ if (action === 'skills') return cmdSkills();
17
38
 
18
- console.log(' 1) AI Provider & Model');
19
- console.log(' 2) Gateway Settings');
20
- console.log(' 3) Channels');
21
- console.log(' 4) Voice / TTS');
22
- console.log(' 5) API Keys');
23
- console.log(' 6) View Current Config');
24
- console.log(' 7) Cancel');
25
- console.log();
39
+ console.log(chalk.red(`\n Unknown configure action: ${action}\n`));
40
+ console.log(chalk.gray(' Usage: natureco configure [gateway|auth|channels|plugins|skills]\n'));
41
+ } catch (err) {
42
+ console.log(chalk.red(`\n Configure error: ${err.message}\n`));
43
+ }
44
+ }
26
45
 
27
- const choice = await rlQuestion(' Select [1-7]: ');
46
+ function cmdMenu() {
47
+ console.log(chalk.cyan('\n Configure\n'));
48
+ console.log(chalk.gray(' Run with an action:'));
49
+ console.log(chalk.gray(' natureco configure gateway Update gateway config'));
50
+ console.log(chalk.gray(' natureco configure auth Update provider keys'));
51
+ console.log(chalk.gray(' natureco configure channels Re-run channels setup'));
52
+ console.log(chalk.gray(' natureco configure plugins Re-run plugin setup'));
53
+ console.log(chalk.gray(' natureco configure skills Re-run skills setup\n'));
54
+ }
28
55
 
29
- if (choice === '7' || choice === '') {
30
- console.log(chalk.gray('\n Cancelled.\n'));
31
- return;
32
- }
56
+ async function cmdGateway() {
57
+ const cfg = getConfig();
58
+ console.log(chalk.cyan('\n Gateway Configuration\n'));
59
+ console.log(chalk.gray(' Current: ') + chalk.white(cfg.gatewayUrl || 'not set'));
33
60
 
34
- if (choice === '6') {
35
- console.log(chalk.cyan('\n' + JSON.stringify(config, null, 2) + '\n'));
36
- return;
37
- }
61
+ const url = await rlQuestion(` Gateway URL (${cfg.gatewayUrl || 'ws://localhost:3848'}): `);
62
+ const port = await rlQuestion(` Port (${cfg.gatewayPort || 3848}): `);
38
63
 
39
- if (choice === '1') {
40
- const provider = await rlQuestion(` Provider (${config.provider || 'openai'}): `);
41
- const model = await rlQuestion(` Model (${config.model || 'gpt-4o'}): `);
42
- config.provider = provider || config.provider || 'openai';
43
- config.model = model || config.model || 'gpt-4o';
44
- saveConfig(config);
45
- console.log(chalk.green(`\n ✅ Provider: ${config.provider}, Model: ${config.model}\n`));
46
- return;
47
- }
64
+ cfg.gatewayUrl = url || cfg.gatewayUrl || 'ws://localhost:3848';
65
+ cfg.gatewayPort = parseInt(port) || cfg.gatewayPort || 3848;
66
+ saveConfig(cfg);
48
67
 
49
- if (choice === '2') {
50
- const url = await rlQuestion(` Gateway URL (${config.gatewayUrl || 'ws://localhost:3848'}): `);
51
- const port = await rlQuestion(` Gateway port (${config.gatewayPort || 3848}): `);
52
- config.gatewayUrl = url || config.gatewayUrl || 'ws://localhost:3848';
53
- config.gatewayPort = parseInt(port) || config.gatewayPort || 3848;
54
- saveConfig(config);
55
- console.log(chalk.green(`\n ✅ Gateway: ${config.gatewayUrl}\n`));
56
- return;
57
- }
68
+ console.log(chalk.green(`\n Gateway updated: ${cfg.gatewayUrl}:${cfg.gatewayPort}\n`));
69
+ }
58
70
 
59
- if (choice === '3') {
60
- console.log(chalk.gray('\n Configure channels using:'));
61
- console.log(chalk.cyan(' natureco channels add'));
62
- console.log(chalk.cyan(' natureco telegram connect'));
63
- console.log(chalk.cyan(' natureco whatsapp connect\n'));
64
- return;
65
- }
71
+ async function cmdAuth() {
72
+ const cfg = getConfig();
73
+ console.log(chalk.cyan('\n Auth Configuration\n'));
74
+ console.log(chalk.gray(' Current provider key: ') + chalk.white(cfg.providerApiKey ? '(set)' : '(not set)'));
66
75
 
67
- if (choice === '4') {
68
- const tts = await rlQuestion(` TTS Provider (${config.tts?.provider || 'openai'}): `);
69
- const voiceId = await rlQuestion(` Voice ID (${config.tts?.voiceId || '(none)'}): `);
70
- if (!config.tts) config.tts = {};
71
- config.tts.provider = tts || config.tts.provider || 'openai';
72
- if (voiceId) config.tts.voiceId = voiceId;
73
- saveConfig(config);
74
- console.log(chalk.green(`\n ✅ Voice: ${config.tts.provider}\n`));
75
- return;
76
+ const key = await rlQuestion(' Provider API Key (leave blank to keep current): ');
77
+ if (key) {
78
+ cfg.providerApiKey = key;
79
+ saveConfig(cfg);
80
+ console.log(chalk.green('\n API key updated.\n'));
81
+ } else {
82
+ console.log(chalk.gray('\n No changes made.\n'));
76
83
  }
84
+ }
77
85
 
78
- if (choice === '5') {
79
- const openai = await rlQuestion(` OpenAI API Key (${config.openaiApiKey ? '(set)' : '(none)'}): `);
80
- const anthropic = await rlQuestion(` Anthropic API Key (${config.anthropicApiKey ? '(set)' : '(none)'}): `);
81
- const tavily = await rlQuestion(` Tavily Search Key (${config.tavilyApiKey ? '(set)' : '(none)'}): `);
82
- if (openai) config.openaiApiKey = openai;
83
- if (anthropic) config.anthropicApiKey = anthropic;
84
- if (tavily) config.tavilyApiKey = tavily;
85
- saveConfig(config);
86
- console.log(chalk.green('\n ✅ API Keys saved\n'));
87
- return;
86
+ function cmdChannels() {
87
+ console.log(chalk.cyan('\n Channels Setup\n'));
88
+ console.log(chalk.gray(' To connect a channel:'));
89
+ const channels = ['telegram', 'whatsapp', 'discord', 'slack', 'signal', 'irc', 'mattermost', 'imessage'];
90
+ for (const ch of channels) {
91
+ console.log(chalk.gray(' natureco ' + ch + ' connect'));
88
92
  }
93
+ console.log('');
94
+ }
95
+
96
+ function cmdPlugins() {
97
+ console.log(chalk.cyan('\n Plugin Setup\n'));
98
+ console.log(chalk.gray(' To manage plugins:'));
99
+ console.log(chalk.cyan(' natureco plugins list'));
100
+ console.log(chalk.cyan(' natureco plugins add <url>\n'));
101
+ }
89
102
 
90
- console.log(chalk.red('\n ❌ Invalid choice\n'));
103
+ function cmdSkills() {
104
+ console.log(chalk.cyan('\n Skills Setup\n'));
105
+ console.log(chalk.gray(' To manage skills:'));
106
+ console.log(chalk.cyan(' natureco skills list'));
107
+ console.log(chalk.cyan(' natureco skills add <name>\n'));
91
108
  }
92
109
 
93
110
  module.exports = configure;