natureco-cli 2.23.29 → 2.23.30

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 (71) hide show
  1. package/README.md +94 -11
  2. package/bin/natureco.js +402 -4
  3. package/package.json +1 -1
  4. package/src/commands/admin-rpc.js +219 -0
  5. package/src/commands/agent.js +89 -0
  6. package/src/commands/approvals.js +53 -0
  7. package/src/commands/backup.js +124 -0
  8. package/src/commands/bonjour.js +167 -0
  9. package/src/commands/capability.js +64 -0
  10. package/src/commands/clickclack.js +130 -0
  11. package/src/commands/commitments.js +32 -0
  12. package/src/commands/completion.js +76 -0
  13. package/src/commands/configure.js +93 -0
  14. package/src/commands/crestodian.js +92 -0
  15. package/src/commands/daemon.js +60 -0
  16. package/src/commands/device-pair.js +248 -0
  17. package/src/commands/devices.js +110 -0
  18. package/src/commands/directory.js +47 -0
  19. package/src/commands/dns.js +58 -0
  20. package/src/commands/docs.js +43 -0
  21. package/src/commands/exec-policy.js +71 -0
  22. package/src/commands/gateway-server.js +1155 -24
  23. package/src/commands/health.js +18 -0
  24. package/src/commands/imessage.js +128 -14
  25. package/src/commands/infer.js +73 -0
  26. package/src/commands/irc.js +64 -15
  27. package/src/commands/mattermost.js +114 -12
  28. package/src/commands/memory-cmd.js +134 -1
  29. package/src/commands/message.js +9 -3
  30. package/src/commands/migrate.js +213 -2
  31. package/src/commands/node.js +98 -0
  32. package/src/commands/nodes.js +106 -0
  33. package/src/commands/oc-path.js +200 -0
  34. package/src/commands/onboard.js +70 -0
  35. package/src/commands/open-prose.js +67 -0
  36. package/src/commands/policy.js +176 -0
  37. package/src/commands/proxy.js +155 -0
  38. package/src/commands/qr.js +28 -0
  39. package/src/commands/sandbox.js +125 -0
  40. package/src/commands/secrets.js +118 -0
  41. package/src/commands/setup.js +113 -7
  42. package/src/commands/signal.js +447 -18
  43. package/src/commands/sms.js +123 -19
  44. package/src/commands/system.js +53 -0
  45. package/src/commands/terminal.js +21 -0
  46. package/src/commands/thread-ownership.js +157 -0
  47. package/src/commands/transcripts.js +72 -0
  48. package/src/commands/voice.js +82 -0
  49. package/src/commands/vydra.js +98 -0
  50. package/src/commands/workboard.js +207 -0
  51. package/src/tools/audio_understanding.js +154 -0
  52. package/src/tools/browser.js +112 -0
  53. package/src/tools/canvas.js +104 -0
  54. package/src/tools/document_extract.js +84 -0
  55. package/src/tools/duckduckgo.js +54 -0
  56. package/src/tools/exa_search.js +66 -0
  57. package/src/tools/firecrawl.js +104 -0
  58. package/src/tools/image_generation.js +99 -0
  59. package/src/tools/llm_task.js +118 -0
  60. package/src/tools/media_understanding.js +128 -0
  61. package/src/tools/music_generation.js +113 -0
  62. package/src/tools/parallel_search.js +77 -0
  63. package/src/tools/phone_control.js +80 -0
  64. package/src/tools/phone_control_enhanced.js +184 -0
  65. package/src/tools/searxng.js +61 -0
  66. package/src/tools/speech_to_text.js +135 -0
  67. package/src/tools/text_to_speech.js +105 -0
  68. package/src/tools/thread_ownership.js +88 -0
  69. package/src/tools/video_generation.js +72 -0
  70. package/src/tools/web_readability.js +104 -0
  71. package/src/utils/memory.js +200 -0
@@ -0,0 +1,18 @@
1
+ const chalk = require('chalk');
2
+ const os = require('os');
3
+
4
+ function health(args) {
5
+ console.log(chalk.cyan('\n 🏥 System Health\n'));
6
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
7
+ console.log(` ${chalk.white('Status:')} ${chalk.green('Healthy')}`);
8
+ console.log(` ${chalk.white('Node:')} ${process.version}`);
9
+ console.log(` ${chalk.white('Platform:')} ${process.platform} ${os.release()}`);
10
+ console.log(` ${chalk.white('Uptime:')} ${Math.floor(process.uptime())}s`);
11
+ console.log(` ${chalk.white('Memory:')} ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB / ${Math.round(process.memoryUsage().heapTotal / 1024 / 1024)}MB`);
12
+ console.log(` ${chalk.white('CPU:')} ${os.cpus()[0]?.model || 'unknown'}`);
13
+ console.log(` ${chalk.white('Load:')} ${os.loadavg()[0].toFixed(2)}`);
14
+ console.log(` ${chalk.white('Host:')} ${os.hostname()}`);
15
+ console.log();
16
+ }
17
+
18
+ module.exports = health;
@@ -1,55 +1,169 @@
1
1
  const chalk = require('chalk');
2
2
  const inquirer = require('../utils/inquirer-wrapper');
3
3
  const { getConfig, saveConfig } = require('../utils/config');
4
+ const fs = require('fs');
5
+ const { execSync } = require('child_process');
4
6
 
5
7
  async function imessage(action) {
6
8
  if (!action || action === 'connect') return connectImessage();
7
9
  if (action === 'disconnect') return disconnectImessage();
8
10
  if (action === 'status') return statusImessage();
11
+ if (action === 'probe') return probeImessage();
9
12
  console.log(chalk.red('\n❌ Unknown action\n'));
10
- console.log(chalk.gray('Available actions: connect, disconnect, status\n'));
13
+ console.log(chalk.gray('Available actions: connect, disconnect, status, probe\n'));
11
14
  process.exit(1);
12
15
  }
13
16
 
14
17
  async function connectImessage() {
15
18
  const config = getConfig();
16
- if (!config.providerUrl) { console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n')); process.exit(1); }
19
+ if (!config.providerUrl) {
20
+ console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n'));
21
+ process.exit(1);
22
+ }
23
+
24
+ if (process.platform !== 'darwin') {
25
+ console.log(chalk.red('\n❌ iMessage sadece macOS\'te çalışır.\n'));
26
+ console.log(chalk.gray('Mevcut platform:'), chalk.white(process.platform));
27
+ console.log(chalk.gray('Diğer platformlar için SMS (Twilio) kullanılabilir.\n'));
28
+ process.exit(1);
29
+ }
30
+
17
31
  console.log(chalk.yellow('\n⏳ iMessage bağlantısı hazırlanıyor...\n'));
18
- console.log(chalk.gray('iMessage sadece macOS\'te çalışır. Windows/Linux\'ta kullanılamaz.'));
19
- console.log(chalk.gray('Gereken: imsg bridge: https://github.com/mbilker/imsg\n'));
32
+ console.log(chalk.gray('Gereken: imsg bridge — https://github.com/mbilker/imsg\n'));
33
+
34
+ const defaults = {
35
+ cliPath: config.imessageCliPath || '',
36
+ service: config.imessageService || 'auto',
37
+ dbPath: config.imessageDbPath || '~/Library/Messages/chat.db',
38
+ dmPolicy: config.imessageDmPolicy || 'pairing',
39
+ };
40
+
20
41
  const answers = await inquirer.prompt([
21
- { type: 'input', name: 'cliPath', message: 'imsg CLI yolu (opsiyonel, boş bırakın PATH\'ten bulsun):' },
22
- { type: 'list', name: 'dmPolicy', message: 'DM politikası:', choices: [{ name: 'Pairing (önerilen)', value: 'pairing' }, { name: 'Allowlist', value: 'allowlist' }, { name: 'Open', value: 'open' }, { name: 'Disabled', value: 'disabled' }], default: 'pairing' },
42
+ { type: 'input', name: 'cliPath', message: 'imsg CLI yolu (boş = PATH):', default: defaults.cliPath },
43
+ { type: 'input', name: 'dbPath', message: 'iMessage veritabanı yolu:', default: defaults.dbPath },
44
+ { type: 'list', name: 'service', message: 'Servis:', default: defaults.service, choices: [
45
+ { name: 'Auto-detect (önerilen)', value: 'auto' },
46
+ { name: 'iMessage', value: 'imessage' },
47
+ { name: 'SMS', value: 'sms' },
48
+ ]},
49
+ { type: 'list', name: 'dmPolicy', message: 'DM politikası:', default: defaults.dmPolicy, choices: [
50
+ { name: 'Pairing (önerilen)', value: 'pairing' },
51
+ { name: 'Allowlist', value: 'allowlist' },
52
+ { name: 'Open', value: 'open' },
53
+ { name: 'Disabled', value: 'disabled' },
54
+ ]},
23
55
  ]);
56
+
24
57
  const botId = `imessage_${Date.now()}`;
25
58
  config.imessageCliPath = answers.cliPath.trim() || '';
59
+ config.imessageDbPath = answers.dbPath.trim() || '~/Library/Messages/chat.db';
60
+ config.imessageService = answers.service;
26
61
  config.imessageDmPolicy = answers.dmPolicy;
27
62
  config.imessageBotId = botId;
28
63
  saveConfig(config);
64
+
29
65
  console.log(chalk.green('\n✅ iMessage bağlantısı kaydedildi!\n'));
30
66
  console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
31
67
  if (config.imessageCliPath) console.log(chalk.cyan('CLI Yolu:'), chalk.white(config.imessageCliPath));
32
- console.log(chalk.gray('\nNot: iMessage sadece macOS\'te çalışır.'));
33
- console.log(chalk.gray('Gateway ile başlatmak için: natureco gateway start\n'));
68
+ console.log(chalk.cyan('Servis:'), chalk.white(answers.service));
69
+ console.log(chalk.gray('\nGateway ile başlatmak için: natureco gateway start\n'));
34
70
  }
35
71
 
36
72
  async function disconnectImessage() {
37
73
  const config = getConfig();
38
- if (!config.imessageBotId) { console.log(chalk.gray('\n⚠️ No iMessage connection found\n')); return; }
39
- const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'iMessage bağlantısını kaldırmak istediğinize emin misiniz?', default: false }]);
40
- if (!confirm) { console.log(chalk.gray('\nCancelled\n')); return; }
41
- delete config.imessageCliPath; delete config.imessageDmPolicy; delete config.imessageBotId;
74
+ if (!config.imessageBotId) {
75
+ console.log(chalk.gray('\n⚠️ No iMessage connection found\n'));
76
+ return;
77
+ }
78
+ const { confirm } = await inquirer.prompt([
79
+ { type: 'confirm', name: 'confirm', message: 'iMessage bağlantısını kaldırmak istediğinize emin misiniz?', default: false }
80
+ ]);
81
+ if (!confirm) {
82
+ console.log(chalk.gray('\nCancelled\n'));
83
+ return;
84
+ }
85
+ delete config.imessageCliPath; delete config.imessageDbPath; delete config.imessageService;
86
+ delete config.imessageDmPolicy; delete config.imessageBotId;
42
87
  saveConfig(config);
43
88
  console.log(chalk.green('\n✅ iMessage disconnected\n'));
44
89
  }
45
90
 
46
- function statusImessage() {
91
+ async function statusImessage() {
47
92
  const config = getConfig();
48
- if (!config.imessageBotId) { console.log(chalk.gray('\n⚠️ iMessage not connected\n')); console.log(chalk.gray('Connect with: natureco imessage connect\n')); return; }
93
+ if (!config.imessageBotId) {
94
+ console.log(chalk.gray('\n⚠️ iMessage not connected\n'));
95
+ console.log(chalk.gray('Connect with: natureco imessage connect\n'));
96
+ return;
97
+ }
49
98
  console.log(chalk.green('\n✅ iMessage connected\n'));
50
99
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.imessageBotId));
51
100
  if (config.imessageCliPath) console.log(chalk.cyan('CLI Yolu:'), chalk.white(config.imessageCliPath));
101
+ console.log(chalk.cyan('Servis:'), chalk.white(config.imessageService || 'auto'));
102
+
103
+ if (process.platform === 'darwin') {
104
+ const imsgPath = findImsgBinary(config);
105
+ console.log(chalk.cyan('imsg binary:'), chalk.white(imsgPath || 'Bulunamadı'));
106
+ if (config.imessageDbPath) console.log(chalk.cyan('DB Yolu:'), chalk.white(config.imessageDbPath));
107
+ } else {
108
+ console.log(chalk.yellow('\n⚠️ iMessage sadece macOS\'te çalışır'));
109
+ }
110
+
52
111
  console.log(chalk.gray('\nDisconnect with: natureco imessage disconnect\n'));
53
112
  }
54
113
 
114
+ async function probeImessage() {
115
+ const config = getConfig();
116
+ if (!config.imessageBotId) {
117
+ console.log(chalk.red('\n❌ iMessage bağlantısı yapılmamış\n'));
118
+ console.log(chalk.gray('Önce: natureco imessage connect\n'));
119
+ process.exit(1);
120
+ }
121
+
122
+ if (process.platform !== 'darwin') {
123
+ console.log(chalk.red('\n❌ iMessage sadece macOS\'te kullanılabilir.\n'));
124
+ process.exit(1);
125
+ }
126
+
127
+ console.log(chalk.yellow('\n⏳ iMessage problanıyor...\n'));
128
+
129
+ const imsgPath = findImsgBinary(config);
130
+ if (!imsgPath) {
131
+ console.log(chalk.red('✗ imsg binary bulunamadı\n'));
132
+ console.log(chalk.gray('Kurulum: brew install mbilker/imsg/imsg'));
133
+ console.log(chalk.gray('Veya: https://github.com/mbilker/imsg\n'));
134
+ process.exit(1);
135
+ }
136
+ console.log(chalk.green(`✓ imsg found: ${imsgPath}`));
137
+
138
+ // Check DB
139
+ const dbPath = (config.imessageDbPath || '~/Library/Messages/chat.db').replace(/^~/, require('os').homedir());
140
+ if (fs.existsSync(dbPath)) {
141
+ console.log(chalk.green(`✓ iMessage DB: ${dbPath}`));
142
+ } else {
143
+ console.log(chalk.yellow(`⚠️ iMessage DB bulunamadı: ${dbPath}`));
144
+ }
145
+
146
+ // Try to send a test message (dry run)
147
+ try {
148
+ const result = execSync(`"${imsgPath}" --help 2>&1`, { encoding: 'utf-8', timeout: 5000 });
149
+ console.log(chalk.gray(`\nimsg version: ${result.split('\n')[0]}`));
150
+ } catch {
151
+ console.log(chalk.yellow('⚠️ imsg çalıştırılamadı'));
152
+ }
153
+
154
+ console.log('');
155
+ }
156
+
157
+ function findImsgBinary(config) {
158
+ if (config.imessageCliPath && fs.existsSync(config.imessageCliPath)) {
159
+ return config.imessageCliPath;
160
+ }
161
+ try {
162
+ const which = execSync('which imsg 2>/dev/null || echo ""', { encoding: 'utf-8', timeout: 5000 });
163
+ const p = which.trim();
164
+ if (p && fs.existsSync(p)) return p;
165
+ } catch {}
166
+ return null;
167
+ }
168
+
55
169
  module.exports = imessage;
@@ -0,0 +1,73 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig } = require('../utils/config');
3
+
4
+ function infer(args) {
5
+ const [action, ...params] = args || [];
6
+
7
+ if (!action || action === 'models') return inferModels();
8
+ if (action === 'media') return inferMedia();
9
+ if (action === 'capabilities') return inferCapabilities();
10
+
11
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
12
+ console.log(chalk.gray(' Kullanım: natureco infer [models|media|capabilities]\n'));
13
+ process.exit(1);
14
+ }
15
+
16
+ function inferModels() {
17
+ const config = getConfig();
18
+ console.log(chalk.cyan('\n 🔍 Inferring models...\n'));
19
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
20
+
21
+ const providers = ['openai', 'anthropic', 'groq', 'deepseek', 'xai'];
22
+ for (const p of providers) {
23
+ const key = config[`${p}ApiKey`] || process.env[`${p.toUpperCase()}_API_KEY`];
24
+ const status = key ? chalk.green('API key found') : chalk.gray('not configured');
25
+ console.log(` ${chalk.white(p)}: ${status}`);
26
+ }
27
+
28
+ console.log(chalk.gray('\n For full model listing: ') + chalk.cyan('natureco models list\n'));
29
+ }
30
+
31
+ function inferMedia() {
32
+ const config = getConfig();
33
+ console.log(chalk.cyan('\n 🔍 Inferring media capabilities...\n'));
34
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
35
+
36
+ const checks = [
37
+ { name: 'Image Generation', key: 'openaiApiKey', provider: 'OpenAI / FAL / Together' },
38
+ { name: 'Video Generation', key: 'runwayApiKey', provider: 'Runway / DeepInfra' },
39
+ { name: 'Music Generation', key: 'sunoApiKey', provider: 'Suno / Udio / ElevenLabs' },
40
+ { name: 'Speech-to-Text', key: 'openaiApiKey', provider: 'OpenAI Whisper / Deepgram' },
41
+ { name: 'Text-to-Speech', key: 'elevenlabsApiKey', provider: 'ElevenLabs / OpenAI' },
42
+ { name: 'Audio Understanding', key: 'openaiApiKey', provider: 'OpenAI / Deepgram' }
43
+ ];
44
+
45
+ for (const c of checks) {
46
+ const key = config[c.key] || process.env[c.key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase()];
47
+ const status = key ? chalk.green('available') : chalk.gray('not configured');
48
+ console.log(` ${chalk.white(c.name)}: ${status} ${chalk.gray(`(${c.provider})`)}`);
49
+ }
50
+ console.log();
51
+ }
52
+
53
+ function inferCapabilities() {
54
+ const config = getConfig();
55
+ console.log(chalk.cyan('\n 🔍 Provider capabilities...\n'));
56
+
57
+ const cap = [
58
+ { name: 'Chat', needs: ['openaiApiKey', 'anthropicApiKey'] },
59
+ { name: 'Vision', needs: ['openaiApiKey', 'anthropicApiKey'] },
60
+ { name: 'Embeddings', needs: ['openaiApiKey'] },
61
+ { name: 'Web Search', needs: ['tavilyApiKey'] },
62
+ { name: 'Image Gen', needs: ['openaiApiKey', 'falApiKey'] },
63
+ { name: 'TTS', needs: ['elevenlabsApiKey', 'openaiApiKey'] }
64
+ ];
65
+
66
+ for (const c of cap) {
67
+ const ok = c.needs.some(k => config[k] || process.env[k.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase()]);
68
+ console.log(` ${ok ? chalk.green('●') : chalk.gray('○')} ${chalk.white(c.name)}`);
69
+ }
70
+ console.log();
71
+ }
72
+
73
+ module.exports = infer;
@@ -13,29 +13,60 @@ async function irc(action) {
13
13
 
14
14
  async function connectIrc() {
15
15
  const config = getConfig();
16
- if (!config.providerUrl) { console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n')); process.exit(1); }
16
+ if (!config.providerUrl) {
17
+ console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n'));
18
+ process.exit(1);
19
+ }
17
20
  console.log(chalk.yellow('\n⏳ IRC bağlantısı hazırlanıyor...\n'));
21
+
22
+ const defaults = {
23
+ host: config.ircHost || '',
24
+ port: config.ircPort || 6697,
25
+ tls: config.ircTls !== undefined ? config.ircTls : true,
26
+ nick: config.ircNick || '',
27
+ username: config.ircUsername || '',
28
+ realname: config.ircRealname || '',
29
+ password: config.ircPassword || '',
30
+ channels: config.ircChannels || [],
31
+ dmPolicy: config.ircDmPolicy || 'pairing',
32
+ nickservEnabled: config.ircNickservEnabled !== undefined ? config.ircNickservEnabled : true,
33
+ nickservPassword: config.ircNickservPassword || '',
34
+ };
35
+
18
36
  const answers = await inquirer.prompt([
19
- { type: 'input', name: 'host', message: 'IRC sunucusu (örn: irc.libera.chat):', validate: v => v.trim() ? true : 'Gerekli' },
20
- { type: 'input', name: 'port', message: 'Port:', default: '6697' },
21
- { type: 'confirm', name: 'tls', message: 'TLS kullanılsın mı?', default: true },
22
- { type: 'input', name: 'nick', message: 'Nick:', validate: v => v.trim() ? true : 'Gerekli' },
23
- { type: 'input', name: 'username', message: 'Kullanıcı adı (opsiyonel):' },
24
- { type: 'password', name: 'password', message: 'Parola (opsiyonel):' },
25
- { type: 'input', name: 'channels', message: 'Kanallar (virgülle ayırın, örn: #natureco,#bots):' },
26
- { type: 'list', name: 'dmPolicy', message: 'DM politikası:', choices: [{ name: 'Pairing (önerilen)', value: 'pairing' }, { name: 'Allowlist', value: 'allowlist' }, { name: 'Open', value: 'open' }, { name: 'Disabled', value: 'disabled' }], default: 'pairing' },
37
+ { type: 'input', name: 'host', message: 'IRC sunucusu:', default: defaults.host, validate: v => v.trim() ? true : 'Gerekli' },
38
+ { type: 'input', name: 'port', message: 'Port:', default: String(defaults.port), validate: v => { const n = parseInt(v); return n > 0 && n < 65536 ? true : '1-65535 arası' } },
39
+ { type: 'confirm', name: 'tls', message: 'TLS kullanılsın mı?', default: defaults.tls },
40
+ { type: 'input', name: 'nick', message: 'Nick:', default: defaults.nick, validate: v => v.trim() ? true : 'Gerekli' },
41
+ { type: 'input', name: 'username', message: 'Kullanıcı adı (opsiyonel):', default: defaults.username || defaults.nick },
42
+ { type: 'input', name: 'realname', message: 'Gerçek ad (opsiyonel):', default: defaults.realname || 'NatureCo' },
43
+ { type: 'password', name: 'password', message: 'Sunucu parolası (opsiyonel):' },
44
+ { type: 'input', name: 'channels', message: 'Kanallar (virgülle ayırın):', default: defaults.channels.join(',') },
45
+ { type: 'confirm', name: 'nickservEnabled', message: 'NickServ kullanılsın mı?', default: defaults.nickservEnabled },
46
+ { type: 'password', name: 'nickservPassword', message: 'NickServ parolası (opsiyonel):' },
47
+ { type: 'list', name: 'dmPolicy', message: 'DM politikası:', default: defaults.dmPolicy, choices: [
48
+ { name: 'Pairing (önerilen)', value: 'pairing' },
49
+ { name: 'Allowlist', value: 'allowlist' },
50
+ { name: 'Open', value: 'open' },
51
+ { name: 'Disabled', value: 'disabled' },
52
+ ]},
27
53
  ]);
54
+
28
55
  const botId = `irc_${Date.now()}`;
29
56
  config.ircHost = answers.host.trim();
30
- config.ircPort = parseInt(answers.port) || 6697;
57
+ config.ircPort = parseInt(answers.port);
31
58
  config.ircTls = answers.tls;
32
59
  config.ircNick = answers.nick.trim();
33
60
  config.ircUsername = answers.username.trim() || answers.nick.trim();
61
+ config.ircRealname = answers.realname.trim() || 'NatureCo';
34
62
  config.ircPassword = answers.password || '';
35
63
  config.ircChannels = answers.channels ? answers.channels.split(',').map(c => c.trim()).filter(Boolean) : [];
64
+ config.ircNickservEnabled = answers.nickservEnabled;
65
+ config.ircNickservPassword = answers.nickservPassword || '';
36
66
  config.ircDmPolicy = answers.dmPolicy;
37
67
  config.ircBotId = botId;
38
68
  saveConfig(config);
69
+
39
70
  console.log(chalk.green('\n✅ IRC bağlantısı kaydedildi!\n'));
40
71
  console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
41
72
  console.log(chalk.cyan('Sunucu:'), chalk.white(`${answers.host.trim()}:${answers.port}`));
@@ -46,11 +77,20 @@ async function connectIrc() {
46
77
 
47
78
  async function disconnectIrc() {
48
79
  const config = getConfig();
49
- if (!config.ircBotId) { console.log(chalk.gray('\n⚠️ No IRC connection found\n')); return; }
50
- const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'IRC bağlantısını kaldırmak istediğinize emin misiniz?', default: false }]);
51
- if (!confirm) { console.log(chalk.gray('\nCancelled\n')); return; }
80
+ if (!config.ircBotId) {
81
+ console.log(chalk.gray('\n⚠️ No IRC connection found\n'));
82
+ return;
83
+ }
84
+ const { confirm } = await inquirer.prompt([
85
+ { type: 'confirm', name: 'confirm', message: 'IRC bağlantısını kaldırmak istediğinize emin misiniz?', default: false }
86
+ ]);
87
+ if (!confirm) {
88
+ console.log(chalk.gray('\nCancelled\n'));
89
+ return;
90
+ }
52
91
  delete config.ircHost; delete config.ircPort; delete config.ircTls; delete config.ircNick;
53
- delete config.ircUsername; delete config.ircPassword; delete config.ircChannels;
92
+ delete config.ircUsername; delete config.ircRealname; delete config.ircPassword;
93
+ delete config.ircChannels; delete config.ircNickservEnabled; delete config.ircNickservPassword;
54
94
  delete config.ircDmPolicy; delete config.ircBotId;
55
95
  saveConfig(config);
56
96
  console.log(chalk.green('\n✅ IRC disconnected\n'));
@@ -58,12 +98,21 @@ async function disconnectIrc() {
58
98
 
59
99
  function statusIrc() {
60
100
  const config = getConfig();
61
- if (!config.ircBotId) { console.log(chalk.gray('\n⚠️ IRC not connected\n')); console.log(chalk.gray('Connect with: natureco irc connect\n')); return; }
101
+ if (!config.ircBotId) {
102
+ console.log(chalk.gray('\n⚠️ IRC not connected\n'));
103
+ console.log(chalk.gray('Connect with: natureco irc connect\n'));
104
+ return;
105
+ }
62
106
  console.log(chalk.green('\n✅ IRC connected\n'));
63
107
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.ircBotId));
64
108
  console.log(chalk.cyan('Sunucu:'), chalk.white(`${config.ircHost}:${config.ircPort}`));
109
+ console.log(chalk.cyan('TLS:'), chalk.white(config.ircTls ? 'Evet' : 'Hayır'));
65
110
  console.log(chalk.cyan('Nick:'), chalk.white(config.ircNick));
111
+ console.log(chalk.cyan('Kullanıcı:'), chalk.white(config.ircUsername));
112
+ if (config.ircRealname) console.log(chalk.cyan('Realname:'), chalk.white(config.ircRealname));
66
113
  if (config.ircChannels?.length) console.log(chalk.cyan('Kanallar:'), chalk.white(config.ircChannels.join(', ')));
114
+ console.log(chalk.cyan('NickServ:'), chalk.white(config.ircNickservEnabled ? 'Evet' : 'Hayır'));
115
+ console.log(chalk.cyan('DM Politikası:'), chalk.white(config.ircDmPolicy || 'pairing'));
67
116
  console.log(chalk.gray('\nDisconnect with: natureco irc disconnect\n'));
68
117
  }
69
118
 
@@ -6,57 +6,159 @@ async function mattermost(action) {
6
6
  if (!action || action === 'connect') return connectMattermost();
7
7
  if (action === 'disconnect') return disconnectMattermost();
8
8
  if (action === 'status') return statusMattermost();
9
+ if (action === 'probe') return probeMattermost();
9
10
  console.log(chalk.red('\n❌ Unknown action\n'));
10
- console.log(chalk.gray('Available actions: connect, disconnect, status\n'));
11
+ console.log(chalk.gray('Available actions: connect, disconnect, status, probe\n'));
11
12
  process.exit(1);
12
13
  }
13
14
 
14
15
  async function connectMattermost() {
15
16
  const config = getConfig();
16
- if (!config.providerUrl) { console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n')); process.exit(1); }
17
+ if (!config.providerUrl) {
18
+ console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n'));
19
+ process.exit(1);
20
+ }
17
21
  console.log(chalk.yellow('\n⏳ Mattermost bağlantısı hazırlanıyor...\n'));
18
22
  console.log(chalk.gray('Mattermost bot token almak için:'));
19
23
  console.log(chalk.gray('1. Mattermost > System Console > Bot Accounts'));
20
24
  console.log(chalk.gray('2. Bot oluşturun veya mevcut botu kullanın'));
21
25
  console.log(chalk.gray('3. Access Token oluşturun\n'));
26
+
27
+ const defaults = {
28
+ baseUrl: config.mattermostBaseUrl || '',
29
+ token: config.mattermostToken || '',
30
+ dmPolicy: config.mattermostDmPolicy || 'pairing',
31
+ };
32
+
22
33
  const answers = await inquirer.prompt([
23
- { type: 'input', name: 'baseUrl', message: 'Mattermost sunucu URL (örn: https://mattermost.example.com):', validate: v => v.trim() ? true : 'Gerekli' },
24
- { type: 'input', name: 'token', message: 'Bot token:', validate: v => v.trim() ? true : 'Gerekli' },
25
- { type: 'list', name: 'dmPolicy', message: 'DM politikası:', choices: [{ name: 'Pairing (önerilen)', value: 'pairing' }, { name: 'Allowlist', value: 'allowlist' }, { name: 'Open', value: 'open' }, { name: 'Disabled', value: 'disabled' }], default: 'pairing' },
34
+ { type: 'input', name: 'baseUrl', message: 'Mattermost sunucu URL:', default: defaults.baseUrl, validate: v => v.trim() ? true : 'Gerekli' },
35
+ { type: 'input', name: 'token', message: 'Bot token:', default: defaults.token ? defaults.token.slice(0, 10) + '...' : '', validate: v => v.trim() ? true : 'Gerekli' },
36
+ { type: 'confirm', name: 'enableSlash', message: 'Slash komutları kaydedilsin mi?', default: config.mattermostSlashEnabled !== false },
37
+ { type: 'list', name: 'dmPolicy', message: 'DM politikası:', default: defaults.dmPolicy, choices: [
38
+ { name: 'Pairing (önerilen)', value: 'pairing' },
39
+ { name: 'Allowlist', value: 'allowlist' },
40
+ { name: 'Open', value: 'open' },
41
+ { name: 'Disabled', value: 'disabled' },
42
+ ]},
26
43
  ]);
44
+
27
45
  const botId = `mattermost_${Date.now()}`;
28
- config.mattermostBaseUrl = answers.baseUrl.trim().replace(/\/$/, '');
46
+ config.mattermostBaseUrl = answers.baseUrl.trim().replace(/\/+$/, '');
29
47
  config.mattermostToken = answers.token.trim();
48
+ config.mattermostSlashEnabled = answers.enableSlash;
30
49
  config.mattermostDmPolicy = answers.dmPolicy;
31
50
  config.mattermostBotId = botId;
32
51
  saveConfig(config);
52
+
33
53
  console.log(chalk.green('\n✅ Mattermost bağlantısı kaydedildi!\n'));
34
54
  console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
35
55
  console.log(chalk.cyan('Sunucu:'), chalk.white(config.mattermostBaseUrl));
36
- console.log(chalk.cyan('Token:'), chalk.white(answers.token.slice(0, 20) + '...'));
56
+ console.log(chalk.cyan('Token:'), chalk.white((answers.token || '').slice(0, 20) + '...'));
37
57
  console.log(chalk.gray('\nGateway ile başlatmak için: natureco gateway start\n'));
38
58
  }
39
59
 
40
60
  async function disconnectMattermost() {
41
61
  const config = getConfig();
42
- if (!config.mattermostBotId) { console.log(chalk.gray('\n⚠️ No Mattermost connection found\n')); return; }
43
- const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'Mattermost bağlantısını kaldırmak istediğinize emin misiniz?', default: false }]);
44
- if (!confirm) { console.log(chalk.gray('\nCancelled\n')); return; }
62
+ if (!config.mattermostBotId) {
63
+ console.log(chalk.gray('\n⚠️ No Mattermost connection found\n'));
64
+ return;
65
+ }
66
+ const { confirm } = await inquirer.prompt([
67
+ { type: 'confirm', name: 'confirm', message: 'Mattermost bağlantısını kaldırmak istediğinize emin misiniz?', default: false }
68
+ ]);
69
+ if (!confirm) {
70
+ console.log(chalk.gray('\nCancelled\n'));
71
+ return;
72
+ }
45
73
  delete config.mattermostBaseUrl; delete config.mattermostToken;
46
- delete config.mattermostDmPolicy; delete config.mattermostBotId;
74
+ delete config.mattermostSlashEnabled; delete config.mattermostDmPolicy;
75
+ delete config.mattermostBotId;
47
76
  saveConfig(config);
48
77
  console.log(chalk.green('\n✅ Mattermost disconnected\n'));
49
78
  }
50
79
 
51
80
  function statusMattermost() {
52
81
  const config = getConfig();
53
- if (!config.mattermostBotId) { console.log(chalk.gray('\n⚠️ Mattermost not connected\n')); console.log(chalk.gray('Connect with: natureco mattermost connect\n')); return; }
82
+ if (!config.mattermostBotId) {
83
+ console.log(chalk.gray('\n⚠️ Mattermost not connected\n'));
84
+ console.log(chalk.gray('Connect with: natureco mattermost connect\n'));
85
+ return;
86
+ }
54
87
  console.log(chalk.green('\n✅ Mattermost connected\n'));
55
88
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.mattermostBotId));
56
89
  console.log(chalk.cyan('Sunucu:'), chalk.white(config.mattermostBaseUrl));
57
90
  console.log(chalk.cyan('Token:'), chalk.white((config.mattermostToken || '').slice(0, 20) + '...'));
91
+ console.log(chalk.cyan('Slash Komutları:'), chalk.white(config.mattermostSlashEnabled !== false ? 'Aktif' : 'Devre Dışı'));
58
92
  console.log(chalk.cyan('DM Politikası:'), chalk.white(config.mattermostDmPolicy || 'pairing'));
93
+
94
+ // Optionally probe
95
+ if (config.mattermostBaseUrl && config.mattermostToken) {
96
+ console.log(chalk.gray('\nProbe için: natureco mattermost probe\n'));
97
+ }
59
98
  console.log(chalk.gray('\nDisconnect with: natureco mattermost disconnect\n'));
60
99
  }
61
100
 
101
+ async function probeMattermost() {
102
+ const config = getConfig();
103
+ if (!config.mattermostBaseUrl || !config.mattermostToken) {
104
+ console.log(chalk.red('\n❌ Mattermost bağlantısı yapılmamış\n'));
105
+ console.log(chalk.gray('Önce: natureco mattermost connect\n'));
106
+ process.exit(1);
107
+ }
108
+
109
+ const baseUrl = config.mattermostBaseUrl.replace(/\/+$/, '');
110
+ const token = config.mattermostToken;
111
+
112
+ console.log(chalk.yellow(`\n⏳ Problanıyor: ${baseUrl}\n`));
113
+
114
+ try {
115
+ const res = await fetch(`${baseUrl}/api/v4/users/me`, {
116
+ headers: { 'Authorization': `Bearer ${token}` },
117
+ signal: AbortSignal.timeout(10000),
118
+ });
119
+
120
+ if (!res.ok) {
121
+ console.log(chalk.red(`✗ API Hatası: HTTP ${res.status}`));
122
+ if (res.status === 401) console.log(chalk.gray(' Token geçersiz. Yeni bir bot token alın.'));
123
+ if (res.status === 403) console.log(chalk.gray(' Botun yetkisi yetersiz.'));
124
+ process.exit(1);
125
+ }
126
+
127
+ const me = await res.json();
128
+ console.log(chalk.green('✓ API Bağlantısı Başarılı\n'));
129
+ console.log(chalk.cyan('Bot Kullanıcı ID:'), chalk.white(me.id));
130
+ console.log(chalk.cyan('Kullanıcı Adı:'), chalk.white(me.username));
131
+ console.log(chalk.cyan('E-posta:'), chalk.white(me.email));
132
+ console.log(chalk.cyan('Rol:'), chalk.white(me.roles));
133
+
134
+ // Check WebSocket
135
+ const wsUrl = baseUrl.replace(/^http/, 'ws') + '/api/v4/websocket';
136
+ console.log(chalk.gray(`\nWebSocket: ${wsUrl}`));
137
+
138
+ // Check slash commands
139
+ try {
140
+ const teamsRes = await fetch(`${baseUrl}/api/v4/users/me/teams`, {
141
+ headers: { 'Authorization': `Bearer ${token}` },
142
+ signal: AbortSignal.timeout(5000),
143
+ });
144
+ if (teamsRes.ok) {
145
+ const teams = await teamsRes.json();
146
+ console.log(chalk.gray(`\nTakımlar (${teams.length}):`));
147
+ for (const team of teams.slice(0, 5)) {
148
+ console.log(chalk.gray(` - ${team.display_name} (${team.name})`));
149
+ }
150
+ }
151
+ } catch {}
152
+
153
+ console.log('');
154
+
155
+ } catch (err) {
156
+ console.log(chalk.red(`\n✗ Probe hatası: ${err.message}\n`));
157
+ if (err.message.includes('ENOTFOUND') || err.message.includes('ECONNREFUSED')) {
158
+ console.log(chalk.gray('Sunucuya erişilemiyor. URL\'yi kontrol edin.\n'));
159
+ }
160
+ process.exit(1);
161
+ }
162
+ }
163
+
62
164
  module.exports = mattermost;