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
@@ -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
 
@@ -1,99 +1,122 @@
1
- const chalk = require('chalk');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const os = require('os');
5
-
6
- const LOG_FILE = path.join(os.homedir(), '.natureco', 'gateway.log');
7
-
8
- async function logs(args) {
9
- const follow = args.includes('--follow') || args.includes('-f');
10
- const json = args.includes('--json');
11
- const plain = args.includes('--plain');
12
- const limitIdx = args.indexOf('--limit');
13
- const limit = limitIdx !== -1 && args[limitIdx + 1]
14
- ? parseInt(args[limitIdx + 1]) || 50
15
- : (args.find(a => a.startsWith('--limit='))
16
- ? parseInt(args.find(a => a.startsWith('--limit=')).split('=')[1]) || 50
17
- : 50);
18
-
19
- if (!fs.existsSync(LOG_FILE)) {
20
- if (!json) console.log(chalk.gray('\n Log dosyası bulunamadı: ' + LOG_FILE + '\n'));
21
- else console.log(JSON.stringify({ error: 'Log file not found' }));
22
- return;
23
- }
24
-
25
- const printLines = (lines) => {
26
- const last = lines.slice(-limit);
27
- if (json) {
28
- console.log(JSON.stringify({ lines: last }));
29
- return;
30
- }
31
- if (!plain) {
32
- console.log('');
33
- console.log(chalk.gray(' ' + '─'.repeat(48)));
34
- console.log(chalk.cyan.bold(`\n Gateway Logları (son ${limit})\n`));
35
- }
36
- last.forEach(line => {
37
- if (!line.trim()) return;
38
- if (plain) {
39
- console.log(line);
40
- return;
41
- }
42
- // Renklendirme
43
- if (line.includes('[error]') || line.includes('ERROR') || line.includes('❌')) {
44
- console.log(chalk.red(' ' + line));
45
- } else if (line.includes('[warn]') || line.includes('WARN') || line.includes('⚠')) {
46
- console.log(chalk.yellow(' ' + line));
47
- } else if (line.includes('[whatsapp]') || line.includes('[telegram]') || line.includes('[discord]')) {
48
- console.log(chalk.cyan(' ' + line));
49
- } else {
50
- console.log(chalk.gray(' ' + line));
51
- }
52
- });
53
- if (!plain) console.log('');
54
- };
55
-
56
- const content = fs.readFileSync(LOG_FILE, 'utf-8');
57
- const lines = content.split('\n').filter(l => l.trim());
58
- printLines(lines);
59
-
60
- if (follow) {
61
- if (!plain) console.log(chalk.gray(' Canlı takip modunda... (Ctrl+C ile çık)\n'));
62
- let lastSize = fs.statSync(LOG_FILE).size;
63
-
64
- const watcher = setInterval(() => {
65
- try {
66
- const stat = fs.statSync(LOG_FILE);
67
- if (stat.size > lastSize) {
68
- const fd = fs.openSync(LOG_FILE, 'r');
69
- const buf = Buffer.alloc(stat.size - lastSize);
70
- fs.readSync(fd, buf, 0, buf.length, lastSize);
71
- fs.closeSync(fd);
72
- const newLines = buf.toString('utf-8').split('\n').filter(l => l.trim());
73
- newLines.forEach(line => {
74
- if (!line.trim()) return;
75
- if (plain) { console.log(line); return; }
76
- if (line.includes('[error]') || line.includes('ERROR')) {
77
- console.log(chalk.red(' ' + line));
78
- } else if (line.includes('[warn]') || line.includes('WARN')) {
79
- console.log(chalk.yellow(' ' + line));
80
- } else if (line.includes('[whatsapp]') || line.includes('[telegram]')) {
81
- console.log(chalk.cyan(' ' + line));
82
- } else {
83
- console.log(chalk.gray(' ' + line));
84
- }
85
- });
86
- lastSize = stat.size;
87
- }
88
- } catch {}
89
- }, 500);
90
-
91
- process.on('SIGINT', () => {
92
- clearInterval(watcher);
93
- console.log(chalk.gray('\n Takip durduruldu.\n'));
94
- process.exit(0);
95
- });
96
- }
97
- }
98
-
99
- module.exports = logs;
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const LOG_FILE = path.join(os.homedir(), '.natureco', 'natureco.log');
7
+
8
+ function ensureLog() {
9
+ const dir = path.dirname(LOG_FILE);
10
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
11
+ if (!fs.existsSync(LOG_FILE)) fs.writeFileSync(LOG_FILE, '', 'utf8');
12
+ }
13
+
14
+ function logs(args) {
15
+ const [action, ...params] = args || [];
16
+
17
+ if (!action || action === 'show') return cmdShow(params[0] ? parseInt(params[0], 10) : 50);
18
+ if (action === 'tail') return cmdTail();
19
+ if (action === 'search') return cmdSearch(params.join(' '));
20
+ if (action === 'clear') return cmdClear();
21
+ if (action === 'path') return cmdPath();
22
+
23
+ console.log(chalk.red(`\n Unknown logs action: ${action}\n`));
24
+ console.log(chalk.gray(' Usage: natureco logs <action> [params]'));
25
+ console.log(chalk.gray(' Actions: tail, show <lines>, search <term>, clear, path\n'));
26
+ process.exit(1);
27
+ }
28
+
29
+ function cmdShow(lines) {
30
+ ensureLog();
31
+ const content = fs.readFileSync(LOG_FILE, 'utf8');
32
+ const allLines = content.split('\n').filter(l => l.trim());
33
+
34
+ if (lines < 1) lines = 50;
35
+ const last = allLines.slice(-lines);
36
+
37
+ console.log(chalk.cyan(`\n Logs (last ${last.length} of ${allLines.length} lines)\n`));
38
+ for (const line of last) {
39
+ printColoredLine(line);
40
+ }
41
+ console.log('');
42
+ }
43
+
44
+ function cmdTail() {
45
+ ensureLog();
46
+ console.log(chalk.cyan('\n Tailing log file... (Ctrl+C to stop)\n'));
47
+ let lastSize = fs.statSync(LOG_FILE).size;
48
+
49
+ const watcher = setInterval(() => {
50
+ try {
51
+ const stat = fs.statSync(LOG_FILE);
52
+ if (stat.size > lastSize) {
53
+ const fd = fs.openSync(LOG_FILE, 'r');
54
+ const buf = Buffer.alloc(stat.size - lastSize);
55
+ fs.readSync(fd, buf, 0, buf.length, lastSize);
56
+ fs.closeSync(fd);
57
+ const newLines = buf.toString('utf8').split('\n').filter(l => l.trim());
58
+ for (const line of newLines) printColoredLine(line);
59
+ lastSize = stat.size;
60
+ }
61
+ } catch {}
62
+ }, 500);
63
+
64
+ process.on('SIGINT', () => {
65
+ clearInterval(watcher);
66
+ console.log(chalk.gray('\n Tail stopped.\n'));
67
+ process.exit(0);
68
+ });
69
+ }
70
+
71
+ function cmdSearch(term) {
72
+ if (!term) {
73
+ console.log(chalk.red('\n Usage: natureco logs search <term>\n'));
74
+ process.exit(1);
75
+ }
76
+
77
+ ensureLog();
78
+ const content = fs.readFileSync(LOG_FILE, 'utf8');
79
+ const lines = content.split('\n').filter(l => l.trim());
80
+ const lower = term.toLowerCase();
81
+ const results = lines.filter(l => l.toLowerCase().includes(lower));
82
+
83
+ if (results.length === 0) {
84
+ console.log(chalk.yellow(`\n No matches for "${term}"\n`));
85
+ return;
86
+ }
87
+
88
+ console.log(chalk.cyan(`\n Found ${results.length} match(es) for "${term}"\n`));
89
+ for (const line of results.slice(-50)) {
90
+ const idx = line.toLowerCase().indexOf(lower);
91
+ if (idx === -1) { printColoredLine(line); continue; }
92
+ const before = line.slice(0, idx);
93
+ const match = line.slice(idx, idx + term.length);
94
+ const after = line.slice(idx + term.length);
95
+ console.log(chalk.gray(' ') + chalk.gray(before) + chalk.yellow(match) + chalk.gray(after));
96
+ }
97
+ console.log('');
98
+ }
99
+
100
+ function cmdClear() {
101
+ ensureLog();
102
+ fs.writeFileSync(LOG_FILE, '', 'utf8');
103
+ console.log(chalk.gray('\n Log file cleared.\n'));
104
+ }
105
+
106
+ function cmdPath() {
107
+ console.log(chalk.cyan(`\n Log file: ${LOG_FILE}\n`));
108
+ }
109
+
110
+ function printColoredLine(line) {
111
+ if (line.includes('[error]') || line.includes('ERROR') || line.includes('❌')) {
112
+ console.log(chalk.red(' ' + line));
113
+ } else if (line.includes('[warn]') || line.includes('WARN') || line.includes('⚠')) {
114
+ console.log(chalk.yellow(' ' + line));
115
+ } else if (line.includes('[info]') || line.includes('INFO')) {
116
+ console.log(chalk.cyan(' ' + line));
117
+ } else {
118
+ console.log(chalk.gray(' ' + line));
119
+ }
120
+ }
121
+
122
+ module.exports = logs;
@@ -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;