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
@@ -1,649 +1,102 @@
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 { saveConfig, CONFIG_DIR, CONFIG_FILE } = require('../utils/config');
7
- const { saveMemory } = require('../utils/memory');
8
-
9
- // ─── Dil metinleri ────────────────────────────────────────────────────────────
10
- const LANG = {
11
- tr: {
12
- welcome: '🌿 NatureCo CLI — Kurulum',
13
- welcomeSub: 'Birkaç adımda hazır olacaksın.',
14
- step: (n, t) => chalk.gray(`[${n}/6]`) + ' ' + chalk.cyan.bold(t),
15
- done: '',
16
- // Adım 1
17
- providerTitle: 'AI Provider seç',
18
- providerQ: 'Hangi AI provider kullanmak istiyorsunuz?',
19
- customUrl: 'Provider URL girin (örn: https://api.example.com/v1):',
20
- apiKeyQ: 'API Key girin:',
21
- apiKeyNatureCo: 'natureco.me Geliştirici Paneli → API Keys bölümünden aldığın key\'i gir:',
22
- modelQ: 'Model seç:',
23
- customModel: 'Model adı girin (örn: llama-3.3-70b-versatile):',
24
- customEntry: 'Özel URL gir',
25
- customModelEntry: 'Özel model adı gir',
26
- // Adım 2
27
- botNameTitle: 'Bot adı',
28
- botNameQ: 'Botunun adı ne olsun?',
29
- botNameDefault: 'NatureBot',
30
- // Adım 3
31
- userNameTitle: 'Kullanıcı adı',
32
- userNameQ: 'Senin adın ne? (hafıza için)',
33
- userNameDefault:'Kullanıcı',
34
- // Adım 4
35
- integTitle: 'Entegrasyonlar',
36
- integQ: 'Hangi entegrasyonları kurmak istiyorsunuz?',
37
- integSkip: 'Şimdilik atla',
38
- integNote: (list) => `Seçilen: ${list.join(', ')} — kurulum için ilgili komutu çalıştır.`,
39
- integCmds: {
40
- Telegram: 'natureco telegram connect',
41
- WhatsApp: 'natureco whatsapp connect',
42
- Discord: 'natureco discord connect',
43
- Slack: 'natureco slack connect',
44
- Signal: 'natureco signal connect',
45
- IRC: 'natureco irc connect',
46
- Mattermost:'natureco mattermost connect',
47
- iMessage: 'natureco imessage connect',
48
- SMS: 'natureco sms connect',
49
- Webhooks: 'natureco webhooks connect',
50
- },
51
- // Adım 5
52
- gatewayTitle: 'Gateway',
53
- gatewayQ: 'Gateway şimdi başlatılsın mı? (arka planda çalışır)',
54
- gatewayYes: 'Gateway başlatılıyor...',
55
- gatewaySkip: 'Sonra başlatmak için: natureco gateway start',
56
- // Adım 6
57
- chatTitle: 'Hazır!',
58
- chatQ: 'Hemen chat başlatmak ister misin?',
59
- chatStart: 'Chat başlatılıyor...',
60
- chatSkip: 'Başlamak için: natureco chat',
61
- // Özet
62
- summaryTitle: '✅ Kurulum tamamlandı!',
63
- summaryProvider:'Provider',
64
- summaryModel: 'Model',
65
- summaryBot: 'Bot adı',
66
- summaryUser: 'Kullanıcı',
67
- summaryConfig: 'Config',
68
- // Hata
69
- urlRequired: 'URL gerekli',
70
- urlInvalid: 'URL http:// veya https:// ile başlamalı',
71
- apiKeyRequired: 'API key gerekli',
72
- modelRequired: 'Model adı gerekli',
73
- nameRequired: 'İsim gerekli',
74
- },
75
- en: {
76
- welcome: '🌿 NatureCo CLI — Setup',
77
- welcomeSub: 'You\'ll be ready in a few steps.',
78
- step: (n, t) => chalk.gray(`[${n}/6]`) + ' ' + chalk.cyan.bold(t),
79
- done: '✓',
80
- // Step 1
81
- providerTitle: 'AI Provider',
82
- providerQ: 'Which AI provider do you want to use?',
83
- customUrl: 'Enter provider URL (e.g. https://api.example.com/v1):',
84
- apiKeyQ: 'Enter API Key:',
85
- apiKeyNatureCo: 'natureco.me → Developer Panel → API Keys section — paste your key:',
86
- modelQ: 'Select model:',
87
- customModel: 'Enter model name (e.g. llama-3.3-70b-versatile):',
88
- customEntry: 'Enter custom URL',
89
- customModelEntry: 'Enter custom model name',
90
- // Step 2
91
- botNameTitle: 'Bot name',
92
- botNameQ: 'What should your bot be called?',
93
- botNameDefault: 'NatureBot',
94
- // Step 3
95
- userNameTitle: 'Your name',
96
- userNameQ: 'What is your name? (for memory)',
97
- userNameDefault:'User',
98
- // Step 4
99
- integTitle: 'Integrations',
100
- integQ: 'Which integrations do you want to set up?',
101
- integSkip: 'Skip for now',
102
- integNote: (list) => `Selected: ${list.join(', ')} — run the relevant command to connect.`,
103
- integCmds: {
104
- Telegram: 'natureco telegram connect',
105
- WhatsApp: 'natureco whatsapp connect',
106
- Discord: 'natureco discord connect',
107
- Slack: 'natureco slack connect',
108
- Signal: 'natureco signal connect',
109
- IRC: 'natureco irc connect',
110
- Mattermost:'natureco mattermost connect',
111
- iMessage: 'natureco imessage connect',
112
- SMS: 'natureco sms connect',
113
- Webhooks: 'natureco webhooks connect',
114
- },
115
- // Step 5
116
- gatewayTitle: 'Gateway',
117
- gatewayQ: 'Start the gateway now? (runs in background)',
118
- gatewayYes: 'Starting gateway...',
119
- gatewaySkip: 'To start later: natureco gateway start',
120
- // Step 6
121
- chatTitle: 'All set!',
122
- chatQ: 'Start chatting now?',
123
- chatStart: 'Starting chat...',
124
- chatSkip: 'To start: natureco chat',
125
- // Summary
126
- summaryTitle: '✅ Setup complete!',
127
- summaryProvider:'Provider',
128
- summaryModel: 'Model',
129
- summaryBot: 'Bot name',
130
- summaryUser: 'User',
131
- summaryConfig: 'Config',
132
- // Errors
133
- urlRequired: 'URL is required',
134
- urlInvalid: 'URL must start with http:// or https://',
135
- apiKeyRequired: 'API key is required',
136
- modelRequired: 'Model name is required',
137
- nameRequired: 'Name is required',
138
- },
139
- };
140
-
141
- // ─── Provider presets ─────────────────────────────────────────────────────────
142
- const NATURECO_PROVIDER = {
143
- name: 'NatureCo (natureco.me — kendi platformun)',
144
- value: 'natureco',
145
- url: 'https://api.natureco.me',
146
- };
147
-
148
- const PROVIDER_PRESETS = (customLabel) => [
149
- NATURECO_PROVIDER,
150
- { name: 'Groq (recommended — fast & free)', value: 'https://api.groq.com/openai/v1' },
151
- { name: 'OpenAI', value: 'https://api.openai.com/v1' },
152
- { name: 'Anthropic', value: 'https://api.anthropic.com' },
153
- { name: 'Together AI', value: 'https://api.together.xyz/v1' },
154
- { name: 'Fireworks AI', value: 'https://api.fireworks.ai/inference/v1' },
155
- { name: 'DeepSeek', value: 'https://api.deepseek.com/v1' },
156
- { name: 'OpenRouter', value: 'https://openrouter.ai/api/v1' },
157
- { name: 'Ollama (local)', value: 'http://localhost:11434/v1' },
158
- { name: 'LM Studio (local)', value: 'http://localhost:1234/v1' },
159
- { name: customLabel, value: 'custom' },
160
- ];
161
-
162
- const COMMON_MODELS = {
163
- 'api.groq.com': ['llama-3.3-70b-versatile','llama-3.1-8b-instant','llama-3.1-70b-versatile','mixtral-8x7b-32768','gemma2-9b-it'],
164
- 'api.openai.com': ['gpt-4o','gpt-4o-mini','gpt-4-turbo','gpt-3.5-turbo'],
165
- 'api.anthropic.com': ['claude-opus-4-7','claude-sonnet-4-6','claude-haiku-4-5-20251001'],
166
- 'api.together.xyz': ['meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo','meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo','mistralai/Mixtral-8x7B-Instruct-v0.1'],
167
- };
168
-
169
- // ─── Yardımcı: adım başlığı ───────────────────────────────────────────────────
170
- function printStep(L, n, title) {
171
- console.log('');
172
- console.log(chalk.gray('─'.repeat(50)));
173
- console.log(L.step(n, title));
174
- console.log('');
175
- }
176
-
177
- function printDone(L, msg) {
178
- console.log(chalk.green(` ${L.done} ${msg}`));
179
- }
180
-
181
- // ─── Ana fonksiyon ────────────────────────────────────────────────────────────
182
- async function setup() {
183
- console.clear();
184
-
185
- // ── Karşılama ──────────────────────────────────────────────────────────────
186
- console.log('');
187
- console.log(chalk.green.bold(' (\\_/)'));
188
- console.log(chalk.green.bold(' (•ᴥ•)'));
189
- console.log(chalk.green(' />🌿'));
190
- console.log('');
191
-
192
- // ── ADIM 0: Dil seçimi ─────────────────────────────────────────────────────
193
- const { lang } = await inquirer.prompt([{
194
- type: 'list',
195
- name: 'lang',
196
- message: 'Language / Dil:',
197
- choices: [
198
- { name: '🇹🇷 Türkçe', value: 'tr' },
199
- { name: '🇬🇧 English', value: 'en' },
200
- ],
201
- }]);
202
-
203
- const L = LANG[lang];
204
-
205
- console.log('');
206
- console.log(chalk.green.bold(` ${L.welcome}`));
207
- console.log(chalk.gray(` ${L.welcomeSub}`));
208
-
209
- // Klasör oluştur
210
- if (!fs.existsSync(CONFIG_DIR)) {
211
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
212
- }
213
-
214
- // Mevcut config
215
- let existingConfig = {};
216
- if (fs.existsSync(CONFIG_FILE)) {
217
- try { existingConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8')); } catch {}
218
- }
219
-
220
- // ── ADIM 1: Provider + API key + Model ────────────────────────────────────
221
- printStep(L, 1, L.providerTitle);
222
-
223
- const { providerChoice } = await inquirer.prompt([{
224
- type: 'list',
225
- name: 'providerChoice',
226
- message: L.providerQ,
227
- choices: PROVIDER_PRESETS(L.customEntry),
228
- default: 'https://api.groq.com/openai/v1',
229
- }]);
230
-
231
- // NatureCo provider seçildiyse URL'yi ayarla
232
- let providerUrl = providerChoice; // varsayılan: seçilen değer direkt URL
233
- let isNatureCo = false;
234
- if (providerChoice === 'natureco') {
235
- providerUrl = NATURECO_PROVIDER.url;
236
- isNatureCo = true;
237
- } else if (providerChoice === 'custom') {
238
- const { customUrl } = await inquirer.prompt([{
239
- type: 'input',
240
- name: 'customUrl',
241
- message: L.customUrl,
242
- validate: (v) => {
243
- if (!v.trim()) return L.urlRequired;
244
- if (!v.startsWith('http://') && !v.startsWith('https://')) return L.urlInvalid;
245
- return true;
246
- },
247
- }]);
248
- providerUrl = customUrl.trim();
249
- }
250
-
251
- const { providerApiKey } = await inquirer.prompt([{
252
- type: 'password',
253
- name: 'providerApiKey',
254
- message: isNatureCo ? L.apiKeyNatureCo : L.apiKeyQ,
255
- mask: '*',
256
- validate: (v) => v.trim() ? true : L.apiKeyRequired,
257
- }]);
258
-
259
- // Model listesi — NatureCo seçildiyse atla
260
- let providerModel;
261
- if (isNatureCo) {
262
- providerModel = 'natureco-default';
263
- } else {
264
- let modelChoices = [L.customModelEntry];
265
- for (const [domain, models] of Object.entries(COMMON_MODELS)) {
266
- if (providerUrl.includes(domain)) {
267
- modelChoices = [...models, L.customModelEntry];
268
- break;
269
- }
270
- }
271
-
272
- const { modelChoice } = await inquirer.prompt([{
273
- type: 'list',
274
- name: 'modelChoice',
275
- message: L.modelQ,
276
- choices: modelChoices,
277
- }]);
278
-
279
- providerModel = modelChoice;
280
- if (modelChoice === L.customModelEntry) {
281
- const { customModel } = await inquirer.prompt([{
282
- type: 'input',
283
- name: 'customModel',
284
- message: L.customModel,
285
- validate: (v) => v.trim() ? true : L.modelRequired,
286
- }]);
287
- providerModel = customModel.trim();
288
- }
289
- }
290
-
291
- printDone(L, `${providerUrl.replace('https://', '').split('/')[0]} · ${providerModel}`);
292
-
293
- // ── ADIM 2: Bot adı — NatureCo provider'da API'den çek ───────────────────
294
- printStep(L, 2, L.botNameTitle);
295
-
296
- let safeBotName = existingConfig.botName || 'NatureBot';
297
-
298
- if (isNatureCo) {
299
- // API'den bot listesini çek
300
- console.log(chalk.gray(lang === 'tr' ? ' Botlar yükleniyor...' : ' Loading bots...'));
301
- try {
302
- const res = await fetch('https://api.natureco.me/api/v1/bots', {
303
- headers: { 'Authorization': `Bearer ${providerApiKey.trim()}` },
304
- });
305
- if (res.ok) {
306
- const data = await res.json();
307
- const bots = Array.isArray(data) ? data : (data.bots || data.data || []);
308
- if (bots.length > 0) {
309
- if (bots.length === 1) {
310
- // Tek bot varsa otomatik seç
311
- safeBotName = bots[0].name;
312
- printDone(L, safeBotName);
313
- } else {
314
- // Birden fazla bot varsa seçtir
315
- const { selectedBotName } = await inquirer.prompt([{
316
- type: 'list',
317
- name: 'selectedBotName',
318
- message: lang === 'tr' ? ' Hangi botu kullanmak istiyorsunuz?' : ' Which bot do you want to use?',
319
- choices: bots.map(b => ({ name: b.name, value: b.name })),
320
- }]);
321
- safeBotName = selectedBotName;
322
- printDone(L, safeBotName);
323
- }
324
- } else {
325
- console.log(chalk.yellow(lang === 'tr'
326
- ? ' Bot bulunamadı. developers.natureco.me\'den bot oluşturun.'
327
- : ' No bots found. Create one at developers.natureco.me'));
328
- printDone(L, safeBotName);
329
- }
330
- } else {
331
- console.log(chalk.yellow(lang === 'tr' ? ' Bot listesi alınamadı.' : ' Could not fetch bot list.'));
332
- printDone(L, safeBotName);
333
- }
334
- } catch (e) {
335
- console.log(chalk.yellow(lang === 'tr' ? ' Bağlantı hatası, varsayılan kullanılıyor.' : ' Connection error, using default.'));
336
- printDone(L, safeBotName);
337
- }
338
- } else {
339
- const { botName } = await inquirer.prompt([{
340
- type: 'input',
341
- name: 'botName',
342
- message: L.botNameQ,
343
- default: existingConfig.botName || L.botNameDefault,
344
- validate: (v) => v.trim() ? true : L.nameRequired,
345
- }]);
346
- safeBotName = String(botName || 'NatureBot').trim();
347
- printDone(L, safeBotName);
348
- }
349
-
350
- // ── ADIM 3: Kullanıcı adı ──────────────────────────────────────────────────
351
- printStep(L, 3, L.userNameTitle);
352
-
353
- const { userName } = await inquirer.prompt([{
354
- type: 'input',
355
- name: 'userName',
356
- message: L.userNameQ,
357
- default: existingConfig.userName || L.userNameDefault,
358
- validate: (v) => v.trim() ? true : L.nameRequired,
359
- }]);
360
-
361
- printDone(L, userName.trim());
362
-
363
- // ── ADIM 4: Entegrasyonlar ─────────────────────────────────────────────────
364
- printStep(L, 4, L.integTitle);
365
-
366
- const { integrations } = await inquirer.prompt([{
367
- type: 'checkbox',
368
- name: 'integrations',
369
- message: L.integQ,
370
- choices: [
371
- { name: 'Telegram', value: 'Telegram' },
372
- { name: 'WhatsApp', value: 'WhatsApp' },
373
- { name: 'Discord', value: 'Discord' },
374
- { name: 'Slack', value: 'Slack' },
375
- { name: 'Signal', value: 'Signal' },
376
- { name: 'IRC', value: 'IRC' },
377
- { name: 'Mattermost', value: 'Mattermost' },
378
- { name: 'iMessage', value: 'iMessage' },
379
- { name: 'SMS (Twilio)', value: 'SMS' },
380
- { name: 'Webhooks', value: 'Webhooks' },
381
- ],
382
- }]);
383
-
384
- // ── Entegrasyon sub-flow'ları ──────────────────────────────────────────────
385
- const integConfig = {};
386
-
387
- if (integrations.includes('Telegram')) {
388
- console.log('');
389
- console.log(chalk.cyan(' Telegram kurulumu:'));
390
- const { tgToken } = await inquirer.prompt([{
391
- type: 'input',
392
- name: 'tgToken',
393
- message: lang === 'tr' ? ' Bot Token girin (BotFather\'dan):' : ' Enter Bot Token (from BotFather):',
394
- validate: (v) => v.trim() ? true : (lang === 'tr' ? 'Token gerekli' : 'Token required'),
395
- }]);
396
- const { tgChatId } = await inquirer.prompt([{
397
- type: 'input',
398
- name: 'tgChatId',
399
- message: lang === 'tr' ? ' Chat ID girin (sadece bu ID\'den gelen mesajlara cevap verilir):' : ' Enter Chat ID (only messages from this ID will be answered):',
400
- validate: (v) => v.trim() ? true : (lang === 'tr' ? 'Chat ID gerekli' : 'Chat ID required'),
401
- }]);
402
- console.log(chalk.gray(lang === 'tr'
403
- ? ' 💡 Chat ID\'nizi öğrenmek için @userinfobot\'a /start yazın'
404
- : ' 💡 To find your Chat ID, send /start to @userinfobot'));
405
- integConfig.telegramToken = tgToken.trim();
406
- integConfig.telegramChatId = tgChatId.trim();
407
- // Bağlantı testi
408
- try {
409
- const res = await fetch(`https://api.telegram.org/bot${tgToken.trim()}/getMe`);
410
- const data = await res.json();
411
- if (data.ok) {
412
- printDone(L, `Telegram @${data.result.username}`);
413
- } else {
414
- console.log(chalk.yellow(' ⚠ Token geçersiz görünüyor, ilerleyebilirsin'));
415
- }
416
- } catch {
417
- console.log(chalk.gray(' (bağlantı testi atlandı)'));
418
- }
419
- }
420
-
421
- if (integrations.includes('WhatsApp')) {
422
- console.log('');
423
- console.log(chalk.cyan(lang === 'tr'
424
- ? ' WhatsApp için gateway başlatılması gerekiyor.'
425
- : ' WhatsApp requires the gateway to be running.'));
426
- console.log(chalk.gray(lang === 'tr'
427
- ? ' Kurulum sonunda gateway başlatılacak, ardından QR kodu taratman gerekecek.'
428
- : ' The gateway will start after setup — you\'ll need to scan the QR code.'));
429
- printDone(L, 'WhatsApp');
430
- }
431
-
432
- if (integrations.includes('Discord')) {
433
- console.log('');
434
- console.log(chalk.cyan(' Discord kurulumu:'));
435
- const { discordToken } = await inquirer.prompt([{
436
- type: 'password',
437
- name: 'discordToken',
438
- message: lang === 'tr' ? ' Discord Bot Token girin:' : ' Enter Discord Bot Token:',
439
- mask: '*',
440
- validate: (v) => v.trim() ? true : (lang === 'tr' ? 'Token gerekli' : 'Token required'),
441
- }]);
442
- integConfig.discordToken = discordToken.trim();
443
- printDone(L, 'Discord');
444
- }
445
-
446
- if (integrations.includes('Signal')) {
447
- console.log('');
448
- console.log(chalk.cyan(' Signal kurulumu (signal-cli REST API):'));
449
- const { sigUrl, sigAccount } = await inquirer.prompt([
450
- { type: 'input', name: 'sigUrl', message: lang === 'tr' ? ' signal-cli REST API URL (örn: http://localhost:8080):' : ' signal-cli REST API URL (e.g. http://localhost:8080):', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
451
- { type: 'input', name: 'sigAccount', message: lang === 'tr' ? ' Signal hesap numarası:' : ' Signal account number:', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
452
- ]);
453
- const sigBotId = `signal_${Date.now()}`;
454
- integConfig.signalHttpUrl = sigUrl.trim();
455
- integConfig.signalAccount = sigAccount.trim();
456
- integConfig.signalBotId = sigBotId;
457
- printDone(L, 'Signal');
458
- }
459
-
460
- if (integrations.includes('IRC')) {
461
- console.log('');
462
- console.log(chalk.cyan(' IRC kurulumu:'));
463
- const { ircHost, ircPort, ircNick } = await inquirer.prompt([
464
- { type: 'input', name: 'ircHost', message: lang === 'tr' ? ' IRC sunucusu (örn: irc.libera.chat):' : ' IRC server (e.g. irc.libera.chat):', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
465
- { type: 'input', name: 'ircPort', message: lang === 'tr' ? ' Port:' : ' Port:', default: '6697' },
466
- { type: 'input', name: 'ircNick', message: lang === 'tr' ? ' Nick:' : ' Nick:', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
467
- ]);
468
- integConfig.ircHost = ircHost.trim();
469
- integConfig.ircPort = parseInt(ircPort) || 6697;
470
- integConfig.ircNick = ircNick.trim();
471
- integConfig.ircBotId = `irc_${Date.now()}`;
472
- printDone(L, 'IRC');
473
- }
474
-
475
- if (integrations.includes('Mattermost')) {
476
- console.log('');
477
- console.log(chalk.cyan(' Mattermost kurulumu:'));
478
- const { mmUrl, mmToken } = await inquirer.prompt([
479
- { type: 'input', name: 'mmUrl', message: lang === 'tr' ? ' Mattermost sunucu URL:' : ' Mattermost server URL:', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
480
- { type: 'password', name: 'mmToken', message: lang === 'tr' ? ' Bot token:' : ' Bot token:', mask: '*', validate: v => v.trim() ? true : (lang === 'tr' ? 'Gerekli' : 'Required') },
481
- ]);
482
- integConfig.mattermostBaseUrl = mmUrl.trim().replace(/\/$/, '');
483
- integConfig.mattermostToken = mmToken.trim();
484
- integConfig.mattermostBotId = `mattermost_${Date.now()}`;
485
- printDone(L, 'Mattermost');
486
- }
487
-
488
- if (integrations.includes('iMessage')) {
489
- console.log('');
490
- console.log(chalk.cyan(lang === 'tr' ? ' iMessage (sadece macOS):' : ' iMessage (macOS only):'));
491
- const { imCliPath } = await inquirer.prompt([{ type: 'input', name: 'imCliPath', message: lang === 'tr' ? ' imsg CLI yolu (opsiyonel):' : ' imsg CLI path (optional):' }]);
492
- integConfig.imessageCliPath = imCliPath.trim() || '';
493
- integConfig.imessageBotId = `imessage_${Date.now()}`;
494
- printDone(L, 'iMessage');
495
- }
496
-
497
- if (integrations.includes('SMS')) {
498
- console.log('');
499
- console.log(chalk.cyan(' SMS (Twilio) kurulumu:'));
500
- const { smsSid, smsToken, smsFrom } = await inquirer.prompt([
501
- { type: 'input', name: 'smsSid', message: ' Twilio Account SID:', validate: v => v.trim() ? true : 'Required' },
502
- { type: 'password', name: 'smsToken', message: ' Twilio Auth Token:', mask: '*', validate: v => v.trim() ? true : 'Required' },
503
- { type: 'input', name: 'smsFrom', message: ' Twilio telefon numarası (E.164):', validate: v => v.trim() ? true : 'Required' },
504
- ]);
505
- integConfig.smsAccountSid = smsSid.trim();
506
- integConfig.smsAuthToken = smsToken.trim();
507
- integConfig.smsFromNumber = smsFrom.trim();
508
- integConfig.smsBotId = `sms_${Date.now()}`;
509
- printDone(L, 'SMS');
510
- }
511
-
512
- if (integrations.includes('Webhooks')) {
513
- printDone(L, 'Webhooks');
514
- console.log(chalk.gray(lang === 'tr'
515
- ? ' → Webhook eklemek için: natureco webhooks connect'
516
- : ' → To add a webhook: natureco webhooks connect'));
517
- }
518
-
519
- if (integrations.length > 0) {
520
- const subflowChannels = ['Telegram', 'WhatsApp', 'Discord', 'Signal', 'IRC', 'Mattermost', 'iMessage', 'SMS', 'Webhooks'];
521
- const hasSubflow = subflowChannels.some(ch => integrations.includes(ch));
522
- if (!hasSubflow) {
523
- printDone(L, integrations.join(', '));
524
- }
525
- console.log('');
526
- } else {
527
- printDone(L, L.integSkip);
528
- }
529
-
530
- // ── ADIM 5: Gateway ────────────────────────────────────────────────────────
531
- printStep(L, 5, L.gatewayTitle);
532
- const { startGateway } = await inquirer.prompt([{
533
- type: 'confirm',
534
- name: 'startGateway',
535
- message: L.gatewayQ,
536
- default: integrations.includes('WhatsApp'),
537
- }]);
538
-
539
- // ── Config kaydet ──────────────────────────────────────────────────────────
540
- const config = {
541
- ...existingConfig,
542
- setupCompleted: true,
543
- setupDate: new Date().toISOString(),
544
- language: lang,
545
- providerUrl,
546
- providerApiKey: providerApiKey.trim(),
547
- botName: safeBotName,
548
- userName: userName.trim(),
549
- debug: existingConfig.debug || false,
550
- skills: existingConfig.skills || { enabled: true, list: [] },
551
- mcpServers: existingConfig.mcpServers || {},
552
- // Entegrasyon config'leri
553
- ...(integConfig.telegramToken && { telegramToken: integConfig.telegramToken }),
554
- ...(integConfig.telegramChatId && { telegramChatId: integConfig.telegramChatId }),
555
- ...(integConfig.discordToken && { discordToken: integConfig.discordToken }),
556
- ...(integConfig.signalHttpUrl && { signalHttpUrl: integConfig.signalHttpUrl }),
557
- ...(integConfig.signalAccount && { signalAccount: integConfig.signalAccount }),
558
- ...(integConfig.signalBotId && { signalBotId: integConfig.signalBotId }),
559
- ...(integConfig.ircHost && { ircHost: integConfig.ircHost }),
560
- ...(integConfig.ircPort && { ircPort: integConfig.ircPort }),
561
- ...(integConfig.ircNick && { ircNick: integConfig.ircNick }),
562
- ...(integConfig.ircBotId && { ircBotId: integConfig.ircBotId }),
563
- ...(integConfig.mattermostBaseUrl && { mattermostBaseUrl: integConfig.mattermostBaseUrl }),
564
- ...(integConfig.mattermostToken && { mattermostToken: integConfig.mattermostToken }),
565
- ...(integConfig.mattermostBotId && { mattermostBotId: integConfig.mattermostBotId }),
566
- ...(integConfig.imessageCliPath && { imessageCliPath: integConfig.imessageCliPath }),
567
- ...(integConfig.imessageBotId && { imessageBotId: integConfig.imessageBotId }),
568
- ...(integConfig.smsAccountSid && { smsAccountSid: integConfig.smsAccountSid }),
569
- ...(integConfig.smsAuthToken && { smsAuthToken: integConfig.smsAuthToken }),
570
- ...(integConfig.smsFromNumber && { smsFromNumber: integConfig.smsFromNumber }),
571
- ...(integConfig.smsBotId && { smsBotId: integConfig.smsBotId }),
572
- };
573
-
574
- saveConfig(config);
575
-
576
- // Hafızaya kullanıcı adı ve bot adı kaydet
577
- const botId = 'universal-provider';
578
- try {
579
- saveMemory(botId, {
580
- name: userName.trim(),
581
- botName: safeBotName,
582
- nickname: '',
583
- preferences: [],
584
- facts: [],
585
- lastSeen: new Date().toISOString(),
586
- });
587
- } catch {}
588
-
589
- // ── Özet ───────────────────────────────────────────────────────────────────
590
- console.log('');
591
- console.log(chalk.gray('─'.repeat(50)));
592
- console.log(chalk.green.bold(` ${L.summaryTitle}`));
593
- console.log('');
594
- console.log(chalk.gray(` ${L.summaryProvider}:`), chalk.white(providerUrl.replace('https://', '').split('/')[0]));
595
- console.log(chalk.gray(` ${L.summaryModel}:`), chalk.white(providerModel));
596
- console.log(chalk.gray(` ${L.summaryBot}:`), chalk.cyan(safeBotName));
597
- console.log(chalk.gray(` ${L.summaryUser}:`), chalk.white(userName.trim()));
598
- console.log(chalk.gray(` ${L.summaryConfig}:`), chalk.gray(CONFIG_FILE));
599
- console.log('');
600
-
601
- // Gateway başlat
602
- if (startGateway) {
603
- console.log(chalk.cyan(` ${L.gatewayYes}`));
604
- try {
605
- const { spawn } = require('child_process');
606
- const gatewayBin = path.join(__dirname, '..', '..', 'bin', 'natureco.js');
607
- spawn(process.execPath, [gatewayBin, 'gateway', 'start'], {
608
- detached: true,
609
- stdio: 'ignore',
610
- }).unref();
611
- printDone(L, 'Gateway');
612
- if (integrations.includes('WhatsApp')) {
613
- console.log('');
614
- console.log(chalk.yellow(lang === 'tr'
615
- ? ' 📱 WhatsApp QR kodunu taratmak için: natureco whatsapp connect'
616
- : ' 📱 To scan WhatsApp QR code: natureco whatsapp connect'));
617
- }
618
- } catch (e) {
619
- console.log(chalk.yellow(` ⚠ ${e.message}`));
620
- }
621
- } else {
622
- console.log(chalk.gray(` ${L.gatewaySkip}`));
623
- }
624
-
625
- // ── ADIM 6: Chat ───────────────────────────────────────────────────────────
626
- printStep(L, 6, L.chatTitle);
627
-
628
- const { startChat } = await inquirer.prompt([{
629
- type: 'confirm',
630
- name: 'startChat',
631
- message: L.chatQ,
632
- default: true,
633
- }]);
634
-
635
- console.log('');
636
-
637
- if (startChat) {
638
- console.log(chalk.cyan(` ${L.chatStart}`));
639
- console.log('');
640
- const chat = require('./chat');
641
- // NatureCo provider'da seçilen bot adıyla başlat
642
- await chat(safeBotName, {});
643
- } else {
644
- console.log(chalk.gray(` ${L.chatSkip}`));
645
- console.log('');
646
- }
647
- }
648
-
649
- module.exports = setup;
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const BASE_DIR = path.join(os.homedir(), '.natureco');
7
+ const CONFIG_FILE = path.join(BASE_DIR, 'config.json');
8
+
9
+ const DIRS = ['sources', 'concepts', 'cache', 'skills', 'memory', 'sessions', 'backups'];
10
+
11
+ function setup(params) {
12
+ try {
13
+ const [action] = params || [];
14
+
15
+ if (!action || action === 'status') return cmdStatus();
16
+ if (action === 'config') return cmdConfig();
17
+ if (action === 'workspace') return cmdWorkspace();
18
+ if (action === 'dirs') return cmdDirs();
19
+
20
+ console.log(chalk.red(`\n Unknown setup action: ${action}\n`));
21
+ console.log(chalk.gray(' Usage: natureco setup [config|workspace|dirs|status]\n'));
22
+ } catch (err) {
23
+ console.log(chalk.red(`\n Setup error: ${err.message}\n`));
24
+ }
25
+ }
26
+
27
+ function cmdStatus() {
28
+ console.log(chalk.cyan('\n Setup Status\n'));
29
+
30
+ const configExists = fs.existsSync(CONFIG_FILE);
31
+ const dirExists = fs.existsSync(BASE_DIR);
32
+
33
+ console.log(chalk.white(' Config: ') + (configExists ? chalk.green('exists') : chalk.yellow('missing')));
34
+ console.log(chalk.white(' Directory: ') + (dirExists ? chalk.green('exists') : chalk.yellow('missing')));
35
+
36
+ if (dirExists) {
37
+ const existing = fs.readdirSync(BASE_DIR).filter(f => fs.statSync(path.join(BASE_DIR, f)).isDirectory());
38
+ const present = DIRS.filter(d => existing.includes(d));
39
+ const absent = DIRS.filter(d => !existing.includes(d));
40
+ if (present.length) console.log(chalk.white(' Dirs: ') + chalk.green(present.join(', ')));
41
+ if (absent.length) console.log(chalk.white(' Missing: ') + chalk.yellow(absent.join(', ')));
42
+ }
43
+
44
+ console.log('');
45
+ }
46
+
47
+ function cmdConfig() {
48
+ if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
49
+
50
+ const defaults = {
51
+ version: 1,
52
+ created: new Date().toISOString(),
53
+ updated: new Date().toISOString(),
54
+ setupCompleted: false,
55
+ skills: { enabled: true, list: [] },
56
+ mcpServers: {},
57
+ };
58
+
59
+ if (fs.existsSync(CONFIG_FILE)) {
60
+ console.log(chalk.yellow('\n Config already exists at: ' + CONFIG_FILE + '\n'));
61
+ return;
62
+ }
63
+
64
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(defaults, null, 2), 'utf8');
65
+ console.log(chalk.green('\n Config created at: ' + CONFIG_FILE + '\n'));
66
+ }
67
+
68
+ function cmdWorkspace() {
69
+ if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
70
+
71
+ const workspaceDir = path.join(BASE_DIR, 'workspace');
72
+ const logsDir = path.join(BASE_DIR, 'logs');
73
+
74
+ if (!fs.existsSync(workspaceDir)) fs.mkdirSync(workspaceDir, { recursive: true });
75
+ if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
76
+
77
+ console.log(chalk.green('\n Workspace directories created:\n'));
78
+ console.log(chalk.gray(' ' + workspaceDir));
79
+ console.log(chalk.gray(' ' + logsDir));
80
+ console.log('');
81
+ }
82
+
83
+ function cmdDirs() {
84
+ if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
85
+
86
+ let created = 0;
87
+ for (const dir of DIRS) {
88
+ const p = path.join(BASE_DIR, dir);
89
+ if (!fs.existsSync(p)) {
90
+ fs.mkdirSync(p, { recursive: true });
91
+ created++;
92
+ }
93
+ }
94
+
95
+ console.log(chalk.green(`\n Created ${created} data director${created === 1 ? 'y' : 'ies'}`));
96
+ if (created > 0) {
97
+ console.log(chalk.gray(' Location: ' + BASE_DIR));
98
+ }
99
+ console.log('');
100
+ }
101
+
102
+ module.exports = setup;