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
@@ -6,59 +6,163 @@ async function sms(action) {
6
6
  if (!action || action === 'connect') return connectSms();
7
7
  if (action === 'disconnect') return disconnectSms();
8
8
  if (action === 'status') return statusSms();
9
+ if (action === 'probe') return probeSms();
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 connectSms() {
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⏳ SMS (Twilio) bağlantısı hazırlanıyor...\n'));
18
- console.log(chalk.gray('Twilio hesabı gereklidir: https://twilio.com'));
19
- console.log(chalk.gray('Account SID ve Auth Token\'ı Twilio Console\'dan alın.\n'));
22
+ console.log(chalk.gray('Twilio hesabı gereklidir: https://twilio.com\n'));
23
+
24
+ const defaults = {
25
+ accountSid: config.smsAccountSid || '',
26
+ authToken: config.smsAuthToken || '',
27
+ fromNumber: config.smsFromNumber || '',
28
+ webhookUrl: config.smsPublicWebhookUrl || '',
29
+ dmPolicy: config.smsDmPolicy || 'allowlist',
30
+ messagingServiceSid: config.smsMessagingServiceSid || '',
31
+ };
32
+
20
33
  const answers = await inquirer.prompt([
21
- { type: 'input', name: 'accountSid', message: 'Twilio Account SID:', validate: v => v.trim() ? true : 'Gerekli' },
22
- { type: 'password', name: 'authToken', message: 'Twilio Auth Token:', validate: v => v.trim() ? true : 'Gerekli' },
23
- { type: 'input', name: 'fromNumber', message: 'Twilio telefon numarası (E.164, örn: +15551234567):', validate: v => v.trim() ? true : 'Gerekli' },
24
- { type: 'input', name: 'publicWebhookUrl', message: 'Webhook URL\'si (opsiyonel, ngrok vb.):' },
25
- { type: 'list', name: 'dmPolicy', message: 'DM politikası:', choices: [{ name: 'Allowlist (önerilen)', value: 'allowlist' }, { name: 'Pairing', value: 'pairing' }, { name: 'Open', value: 'open' }, { name: 'Disabled', value: 'disabled' }], default: 'allowlist' },
34
+ { type: 'input', name: 'accountSid', message: 'Twilio Account SID:', default: defaults.accountSid ? defaults.accountSid.slice(0, 10) + '...' : '', validate: v => v.trim() ? true : 'Gerekli' },
35
+ { type: 'password', name: 'authToken', message: 'Twilio Auth Token:' },
36
+ { type: 'input', name: 'fromNumber', message: 'Gönderen numara (E.164, +15551234567):', default: defaults.fromNumber, validate: v => v.trim() || defaults.messagingServiceSid ? true : 'Numara veya Messaging Service SID gerekli' },
37
+ { type: 'input', name: 'messagingServiceSid', message: 'Messaging Service SID (opsiyonel):', default: defaults.messagingServiceSid },
38
+ { type: 'input', name: 'webhookUrl', message: 'Genel webhook URL (ngrok vb., opsiyonel):', default: defaults.webhookUrl },
39
+ { type: 'list', name: 'dmPolicy', message: 'DM politikası:', default: defaults.dmPolicy, choices: [
40
+ { name: 'Allowlist (önerilen) — spam koruması', value: 'allowlist' },
41
+ { name: 'Pairing — eşleşme kodu ile', value: 'pairing' },
42
+ { name: 'Open — herkese açık', value: 'open' },
43
+ { name: 'Disabled — devre dışı', value: 'disabled' },
44
+ ]},
45
+ { type: 'confirm', name: 'enableWebhook', message: 'Gelen SMS webhook\'u etkinleştirilsin mi?', default: config.smsEnableWebhook !== false },
26
46
  ]);
47
+
27
48
  const botId = `sms_${Date.now()}`;
28
49
  config.smsAccountSid = answers.accountSid.trim();
29
50
  config.smsAuthToken = answers.authToken.trim();
30
51
  config.smsFromNumber = answers.fromNumber.trim();
31
- config.smsPublicWebhookUrl = answers.publicWebhookUrl.trim() || '';
52
+ config.smsMessagingServiceSid = answers.messagingServiceSid.trim() || '';
53
+ config.smsPublicWebhookUrl = answers.webhookUrl.trim() || '';
32
54
  config.smsDmPolicy = answers.dmPolicy;
55
+ config.smsEnableWebhook = answers.enableWebhook;
33
56
  config.smsBotId = botId;
34
57
  saveConfig(config);
58
+
35
59
  console.log(chalk.green('\n✅ SMS (Twilio) bağlantısı kaydedildi!\n'));
36
60
  console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
37
61
  console.log(chalk.cyan('Account SID:'), chalk.white(answers.accountSid.slice(0, 20) + '...'));
38
- console.log(chalk.cyan('Numara:'), chalk.white(answers.fromNumber.trim()));
39
- console.log(chalk.gray('\nNot: SMS webhook\'u için Twilio Console\'da Webhook URL\'si ayarlayın.'));
40
- console.log(chalk.gray('Gateway ile başlatmak için: natureco gateway start\n'));
62
+ console.log(chalk.cyan('Numara:'), chalk.white(answers.fromNumber || '(Messaging Service)'));
63
+ console.log(chalk.cyan('DM Politikası:'), chalk.white(answers.dmPolicy));
64
+
65
+ if (answers.enableWebhook) {
66
+ console.log(chalk.gray('\nTwilio Console\'da webhook URL\'si ayarlayın:'));
67
+ if (answers.webhookUrl) {
68
+ console.log(chalk.cyan(` ${answers.webhookUrl}/webhooks/sms`));
69
+ } else {
70
+ console.log(chalk.gray(' (önce bir genel URL ayarlayın)'));
71
+ }
72
+ }
73
+ console.log(chalk.gray('\nGateway ile başlatmak için: natureco gateway start\n'));
41
74
  }
42
75
 
43
76
  async function disconnectSms() {
44
77
  const config = getConfig();
45
- if (!config.smsBotId) { console.log(chalk.gray('\n⚠️ No SMS connection found\n')); return; }
46
- const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'SMS bağlantısını kaldırmak istediğinize emin misiniz?', default: false }]);
47
- if (!confirm) { console.log(chalk.gray('\nCancelled\n')); return; }
78
+ if (!config.smsBotId) {
79
+ console.log(chalk.gray('\n⚠️ No SMS connection found\n'));
80
+ return;
81
+ }
82
+ const { confirm } = await inquirer.prompt([
83
+ { type: 'confirm', name: 'confirm', message: 'SMS bağlantısını kaldırmak istediğinize emin misiniz?', default: false }
84
+ ]);
85
+ if (!confirm) {
86
+ console.log(chalk.gray('\nCancelled\n'));
87
+ return;
88
+ }
48
89
  delete config.smsAccountSid; delete config.smsAuthToken; delete config.smsFromNumber;
49
- delete config.smsPublicWebhookUrl; delete config.smsDmPolicy; delete config.smsBotId;
90
+ delete config.smsMessagingServiceSid; delete config.smsPublicWebhookUrl;
91
+ delete config.smsDmPolicy; delete config.smsEnableWebhook; delete config.smsBotId;
50
92
  saveConfig(config);
51
93
  console.log(chalk.green('\n✅ SMS disconnected\n'));
52
94
  }
53
95
 
54
96
  function statusSms() {
55
97
  const config = getConfig();
56
- if (!config.smsBotId) { console.log(chalk.gray('\n⚠️ SMS not connected\n')); console.log(chalk.gray('Connect with: natureco sms connect\n')); return; }
98
+ if (!config.smsBotId) {
99
+ console.log(chalk.gray('\n⚠️ SMS not connected\n'));
100
+ console.log(chalk.gray('Connect with: natureco sms connect\n'));
101
+ return;
102
+ }
57
103
  console.log(chalk.green('\n✅ SMS (Twilio) connected\n'));
58
104
  console.log(chalk.cyan('Bot ID:'), chalk.white(config.smsBotId));
59
105
  console.log(chalk.cyan('Account SID:'), chalk.white((config.smsAccountSid || '').slice(0, 20) + '...'));
60
- console.log(chalk.cyan('Numara:'), chalk.white(config.smsFromNumber));
106
+ console.log(chalk.cyan('Numara:'), chalk.white(config.smsFromNumber || '(Messaging Service)'));
107
+ console.log(chalk.cyan('DM Politikası:'), chalk.white(config.smsDmPolicy || 'allowlist'));
108
+ console.log(chalk.cyan('Webhook:'), chalk.white(config.smsEnableWebhook !== false ? 'Aktif' : 'Devre Dışı'));
61
109
  console.log(chalk.gray('\nDisconnect with: natureco sms disconnect\n'));
62
110
  }
63
111
 
112
+ async function probeSms() {
113
+ const config = getConfig();
114
+ if (!config.smsAccountSid || !config.smsAuthToken) {
115
+ console.log(chalk.red('\n❌ SMS bağlantısı yapılmamış\n'));
116
+ console.log(chalk.gray('Önce: natureco sms connect\n'));
117
+ process.exit(1);
118
+ }
119
+
120
+ const base64Auth = Buffer.from(`${config.smsAccountSid}:${config.smsAuthToken}`).toString('base64');
121
+ console.log(chalk.yellow('\n⏳ Twilio problanıyor...\n'));
122
+
123
+ try {
124
+ const res = await fetch('https://api.twilio.com/2010-04-01/Accounts/' + config.smsAccountSid + '.json', {
125
+ headers: { 'Authorization': `Basic ${base64Auth}` },
126
+ signal: AbortSignal.timeout(10000),
127
+ });
128
+
129
+ if (!res.ok) {
130
+ console.log(chalk.red(`✗ Twilio API Hatası: HTTP ${res.status}\n`));
131
+ if (res.status === 401) console.log(chalk.gray(' Account SID veya Auth Token hatalı.\n'));
132
+ process.exit(1);
133
+ }
134
+
135
+ const account = await res.json();
136
+ console.log(chalk.green('✓ Twilio API Bağlantısı Başarılı\n'));
137
+ console.log(chalk.cyan('Hesap Adı:'), chalk.white(account.friendly_name));
138
+ console.log(chalk.cyan('Status:'), chalk.white(account.status));
139
+ console.log(chalk.cyan('Type:'), chalk.white(account.type));
140
+
141
+ // Check balance
142
+ if (account.subresource_uris?.balance) {
143
+ try {
144
+ const balRes = await fetch('https://api.twilio.com' + account.subresource_uris.balance, {
145
+ headers: { 'Authorization': `Basic ${base64Auth}` },
146
+ signal: AbortSignal.timeout(5000),
147
+ });
148
+ if (balRes.ok) {
149
+ const balance = await balRes.json();
150
+ console.log(chalk.cyan('Bakiye:'), chalk.white(`${balance.balance} ${balance.currency}`));
151
+ }
152
+ } catch {}
153
+ }
154
+
155
+ // Check phone number
156
+ if (config.smsFromNumber) {
157
+ console.log(chalk.gray(`\nGönderen numara: ${config.smsFromNumber}`));
158
+ }
159
+
160
+ console.log('');
161
+
162
+ } catch (err) {
163
+ console.log(chalk.red(`\n✗ Probe hatası: ${err.message}\n`));
164
+ process.exit(1);
165
+ }
166
+ }
167
+
64
168
  module.exports = sms;
@@ -0,0 +1,53 @@
1
+ const chalk = require('chalk');
2
+ const os = require('os');
3
+
4
+ function system(args) {
5
+ const [action, ...params] = args || [];
6
+
7
+ if (!action || action === 'status') return systemStatus();
8
+ if (action === 'events' || action === 'heartbeat') return systemHeartbeat();
9
+ if (action === 'presence') return systemPresence();
10
+
11
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
12
+ console.log(chalk.gray(' Kullanım: natureco system [status|events|presence]\n'));
13
+ process.exit(1);
14
+ }
15
+
16
+ function systemStatus() {
17
+ const mem = process.memoryUsage();
18
+ const uptime = process.uptime();
19
+ const days = Math.floor(uptime / 86400);
20
+ const hours = Math.floor((uptime % 86400) / 3600);
21
+ const mins = Math.floor((uptime % 3600) / 60);
22
+
23
+ console.log(chalk.cyan('\n 💻 System\n'));
24
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
25
+ console.log(` ${chalk.white('Host:')} ${os.hostname()}`);
26
+ console.log(` ${chalk.white('Platform:')} ${process.platform} ${os.release()}`);
27
+ console.log(` ${chalk.white('Uptime:')} ${days}d ${hours}h ${mins}m`);
28
+ console.log(` ${chalk.white('Node:')} ${process.version}`);
29
+ console.log(` ${chalk.white('Memory:')} ${Math.round(mem.heapUsed / 1024 / 1024)}MB / ${Math.round(mem.heapTotal / 1024 / 1024)}MB`);
30
+ console.log(` ${chalk.white('CPU:')} ${os.cpus()[0]?.model || 'unknown'}`);
31
+ console.log(` ${chalk.white('Load:')} ${os.loadavg().map(l => l.toFixed(2)).join(', ')}`);
32
+ console.log(` ${chalk.white('PID:')} ${process.pid}`);
33
+ console.log();
34
+ }
35
+
36
+ function systemHeartbeat() {
37
+ console.log(chalk.cyan(`\n 💓 Heartbeat: ${new Date().toISOString()}\n`));
38
+ console.log(chalk.gray(` PID: ${process.pid}`));
39
+ console.log(chalk.gray(` Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB`));
40
+ console.log(chalk.gray(` Status: ${chalk.green('alive')}\n`));
41
+ }
42
+
43
+ function systemPresence() {
44
+ console.log(chalk.cyan('\n 🟢 Presence\n'));
45
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
46
+ console.log(` ${chalk.white('Status:')} ${chalk.green('online')}`);
47
+ console.log(` ${chalk.white('Since:')} ${new Date(Date.now() - process.uptime() * 1000).toISOString()}`);
48
+ console.log(` ${chalk.white('Host:')} ${os.hostname()}`);
49
+ console.log(` ${chalk.white('Version:')} NatureCo CLI`);
50
+ console.log();
51
+ }
52
+
53
+ module.exports = system;
@@ -0,0 +1,21 @@
1
+ const chalk = require('chalk');
2
+ const { execSync } = require('child_process');
3
+
4
+ function terminal(args) {
5
+ console.log(chalk.cyan('\n 🖥️ Terminal UI\n'));
6
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
7
+ console.log(chalk.gray(' Open a terminal UI connected to the Gateway.\n'));
8
+ console.log(chalk.gray(' Starting chat interface...\n'));
9
+
10
+ try {
11
+ execSync('node "' + __dirname + '\\chat.js"', {
12
+ stdio: 'inherit',
13
+ cwd: require('path').join(__dirname, '..', '..'),
14
+ timeout: 5000
15
+ });
16
+ } catch {
17
+ console.log(chalk.cyan(' Use:') + chalk.white(' natureco chat\n'));
18
+ }
19
+ }
20
+
21
+ module.exports = terminal;
@@ -0,0 +1,157 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, saveConfig } = require('../utils/config');
3
+
4
+ const MENTION_TTL_MS = 300 * 1000;
5
+
6
+ function threadOwnership(args) {
7
+ const [action, ...params] = args || [];
8
+
9
+ if (!action || action === 'status') return statusOwnership();
10
+ if (action === 'list') return listOwnership();
11
+ if (action === 'assign') return assignOwnership(params[0], params[1], params[2]);
12
+ if (action === 'release') return releaseOwnership(params[0], params[1]);
13
+ if (action === 'check') return checkOwnership(params[0], params[1], params[2]);
14
+ if (action === 'agent') return setDefaultAgent(params[0]);
15
+
16
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
17
+ console.log(chalk.gray(' Kullanım: natureco thread-ownership [status|list|assign|release|check|agent]\n'));
18
+ process.exit(1);
19
+ }
20
+
21
+ function statusOwnership() {
22
+ const config = getConfig();
23
+ const to = config.threadOwnership || {};
24
+ const agents = to.agents || { default: config.agentName || 'default' };
25
+
26
+ const totalAssigned = Object.keys(to).filter(k => k !== 'agents').length;
27
+
28
+ console.log(chalk.cyan('\n 🧵 Thread Ownership\n'));
29
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
30
+ console.log(` ${chalk.white('Default Agent:')} ${chalk.cyan(agents.default || 'default')}`);
31
+ console.log(` ${chalk.white('Assigned:')} ${chalk.cyan(totalAssigned)} threads`);
32
+ console.log(` ${chalk.white('Slack Forwarder:')} ${chalk.gray(to.forwarderUrl || process.env.SLACK_FORWARDER_URL || 'not configured')}`);
33
+ console.log(` ${chalk.white('Config Path:')} ${chalk.gray('~/.natureco/config.json → threadOwnership')}`);
34
+ console.log(chalk.gray('\n Commands:'));
35
+ console.log(chalk.cyan(' list') + chalk.gray(' List assignments'));
36
+ console.log(chalk.cyan(' assign <thread> <agent> [channel]') + chalk.gray(' Assign thread'));
37
+ console.log(chalk.cyan(' release <thread> [channel]') + chalk.gray(' Release thread'));
38
+ console.log(chalk.cyan(' check <thread> <channel> <agent>') + chalk.gray(' Check if agent can claim'));
39
+ console.log(chalk.cyan(' agent <name>') + chalk.gray(' Set default agent'));
40
+ console.log();
41
+ }
42
+
43
+ function listOwnership() {
44
+ const config = getConfig();
45
+ const to = config.threadOwnership || {};
46
+ const entries = Object.entries(to).filter(([k]) => k !== 'agents' && k !== 'forwarderUrl');
47
+
48
+ console.log(chalk.cyan(`\n 🧵 Thread Assignments (${entries.length})\n`));
49
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
50
+
51
+ if (entries.length === 0) {
52
+ console.log(chalk.gray(' Atanmış thread yok.\n'));
53
+ return;
54
+ }
55
+
56
+ for (const [threadId, data] of entries) {
57
+ const agent = typeof data === 'string' ? data : data.agent || 'unknown';
58
+ const channel = typeof data === 'string' ? '-' : data.channel || '-';
59
+ const ts = typeof data === 'string' ? '-' : data.since ? new Date(data.since).toLocaleString() : '-';
60
+ console.log(` ${chalk.cyan(threadId.substring(0, 30))}`);
61
+ console.log(` ${chalk.gray('Agent:')} ${chalk.white(agent)}`);
62
+ console.log(` ${chalk.gray('Channel:')} ${chalk.white(channel)}`);
63
+ if (ts !== '-') console.log(` ${chalk.gray('Since:')} ${chalk.gray(ts)}`);
64
+ }
65
+ console.log();
66
+ }
67
+
68
+ function assignOwnership(threadId, agentName, channel) {
69
+ if (!threadId || !agentName) {
70
+ console.log(chalk.red('\n ❌ threadId ve agentName gerekli\n'));
71
+ console.log(chalk.cyan(' natureco thread-ownership assign C012345 "agent-bob" slack\n'));
72
+ process.exit(1);
73
+ }
74
+
75
+ const config = getConfig();
76
+ if (!config.threadOwnership) config.threadOwnership = {};
77
+ config.threadOwnership[threadId] = { agent: agentName, channel: channel || 'slack', since: new Date().toISOString() };
78
+ saveConfig(config);
79
+
80
+ console.log(chalk.green(`\n ✅ Thread ${threadId} → ${agentName}${channel ? ` (${channel})` : ''}\n`));
81
+ }
82
+
83
+ function releaseOwnership(threadId, channel) {
84
+ if (!threadId) {
85
+ console.log(chalk.red('\n ❌ threadId gerekli\n'));
86
+ process.exit(1);
87
+ }
88
+
89
+ const config = getConfig();
90
+ if (!config.threadOwnership) config.threadOwnership = {};
91
+
92
+ if (channel) {
93
+ const found = Object.entries(config.threadOwnership).find(([k, v]) =>
94
+ k === threadId && (typeof v === 'string' ? true : v.channel === channel)
95
+ );
96
+ if (found) delete config.threadOwnership[found[0]];
97
+ } else {
98
+ delete config.threadOwnership[threadId];
99
+ }
100
+
101
+ saveConfig(config);
102
+ console.log(chalk.gray(`\n 🔓 Thread ${threadId} serbest bırakıldı\n`));
103
+ }
104
+
105
+ function checkOwnership(threadId, channel, agentName) {
106
+ if (!threadId || !channel || !agentName) {
107
+ console.log(chalk.red('\n ❌ threadId, channel ve agentName gerekli\n'));
108
+ console.log(chalk.cyan(' natureco thread-ownership check C012345 slack agent-bob\n'));
109
+ process.exit(1);
110
+ }
111
+
112
+ const config = getConfig();
113
+ const to = config.threadOwnership || {};
114
+ const entry = Object.entries(to).find(([k, v]) => {
115
+ if (k !== threadId) return false;
116
+ if (typeof v === 'string') return true;
117
+ return v.channel === channel || !v.channel;
118
+ });
119
+
120
+ if (!entry) {
121
+ console.log(chalk.green(`\n ✅ Thread ${threadId} sahipsiz — ${agentName} alabilir\n`));
122
+ return;
123
+ }
124
+
125
+ const [, data] = entry;
126
+ const owner = typeof data === 'string' ? data : data.agent;
127
+ const since = typeof data === 'string' ? '-' : data.since ? new Date(data.since).toLocaleString() : '-';
128
+
129
+ if (owner === agentName) {
130
+ console.log(chalk.green(`\n ✅ Thread ${threadId} zaten ${agentName}'e ait\n`));
131
+ return;
132
+ }
133
+
134
+ const expired = data.since ? (Date.now() - new Date(data.since).getTime() > MENTION_TTL_MS) : false;
135
+ if (expired) {
136
+ console.log(chalk.yellow(`\n ⚠️ Thread ${threadId} süresi dolmuş (${owner}), ${agentName} alabilir\n`));
137
+ return;
138
+ }
139
+
140
+ console.log(chalk.red(`\n ❌ Thread ${threadId} ${owner}'e ait (since: ${since}) — ${agentName} alamaz\n`));
141
+ }
142
+
143
+ function setDefaultAgent(name) {
144
+ if (!name) {
145
+ console.log(chalk.red('\n ❌ Agent adı gerekli\n'));
146
+ process.exit(1);
147
+ }
148
+
149
+ const config = getConfig();
150
+ if (!config.threadOwnership) config.threadOwnership = {};
151
+ if (!config.threadOwnership.agents) config.threadOwnership.agents = {};
152
+ config.threadOwnership.agents.default = name;
153
+ saveConfig(config);
154
+ console.log(chalk.green(`\n ✅ Default agent set to: ${name}\n`));
155
+ }
156
+
157
+ module.exports = threadOwnership;
@@ -0,0 +1,72 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ function transcripts(args) {
7
+ const [action, ...params] = args || [];
8
+
9
+ if (!action || action === 'list') return listTranscripts();
10
+ if (action === 'show') return showTranscript(params[0]);
11
+
12
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
13
+ console.log(chalk.gray(' Kullanım: natureco transcripts [list|show]\n'));
14
+ process.exit(1);
15
+ }
16
+
17
+ function listTranscripts() {
18
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
19
+ console.log(chalk.cyan('\n 📜 Transcripts\n'));
20
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
21
+
22
+ if (!fs.existsSync(sessionsDir)) {
23
+ console.log(chalk.gray(' No transcripts found.\n'));
24
+ return;
25
+ }
26
+
27
+ const files = fs.readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
28
+ if (files.length === 0) {
29
+ console.log(chalk.gray(' No transcripts found.\n'));
30
+ return;
31
+ }
32
+
33
+ for (const f of files.sort().reverse().slice(0, 20)) {
34
+ const stat = fs.statSync(path.join(sessionsDir, f));
35
+ const size = (stat.size / 1024).toFixed(1);
36
+ const date = stat.birthtime.toLocaleString();
37
+ const preview = f.replace('.json', '').substring(0, 40);
38
+ console.log(` ${chalk.cyan('●')} ${chalk.white(preview)} ${chalk.gray(`(${size} KB, ${date})`)}`);
39
+ }
40
+ console.log();
41
+ }
42
+
43
+ function showTranscript(id) {
44
+ if (!id) {
45
+ console.log(chalk.red('\n ❌ Transcript ID gerekli\n'));
46
+ process.exit(1);
47
+ }
48
+
49
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
50
+ const file = path.join(sessionsDir, `${id}.json`);
51
+
52
+ if (!fs.existsSync(file)) {
53
+ const alt = path.join(sessionsDir, id);
54
+ if (!fs.existsSync(alt)) {
55
+ console.log(chalk.red(`\n ❌ Transcript bulunamadı: ${id}\n`));
56
+ process.exit(1);
57
+ }
58
+ const content = fs.readFileSync(alt, 'utf8');
59
+ console.log(chalk.gray(`\n ${alt}\n`));
60
+ console.log(content.substring(0, 5000));
61
+ if (content.length > 5000) console.log(chalk.gray('\n ... (truncated)\n'));
62
+ return;
63
+ }
64
+
65
+ const content = fs.readFileSync(file, 'utf8');
66
+ console.log(chalk.gray(`\n ${file}\n`));
67
+ const parsed = JSON.parse(content);
68
+ console.log(JSON.stringify(parsed, null, 2).substring(0, 5000));
69
+ console.log();
70
+ }
71
+
72
+ module.exports = transcripts;
@@ -0,0 +1,82 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, saveConfig } = require('../utils/config');
3
+
4
+ const PROVIDER_LABELS = {
5
+ openai: 'OpenAI',
6
+ elevenlabs: 'ElevenLabs',
7
+ microsoft: 'Microsoft (Azure)',
8
+ deepgram: 'Deepgram',
9
+ google: 'Google Cloud'
10
+ };
11
+
12
+ function mask(str, keep = 6) {
13
+ if (!str) return '(unset)';
14
+ return str.length <= keep ? '***' : `${str.slice(0, keep)}…`;
15
+ }
16
+
17
+ async function voice(args) {
18
+ const [action, ...params] = args || [];
19
+
20
+ if (!action || action === 'status') return statusVoice();
21
+ if (action === 'providers') return listProviders();
22
+ if (action === 'set') return setVoiceProvider(params);
23
+
24
+ console.log(chalk.red(`\n ❌ Unknown command: ${action}\n`));
25
+ console.log(chalk.gray(' Usage: natureco voice [status|providers|set]\n'));
26
+ process.exit(1);
27
+ }
28
+
29
+ function statusVoice() {
30
+ const config = getConfig();
31
+ const ttsConfig = config.tts || {};
32
+ const provider = ttsConfig.provider || 'openai';
33
+ const voiceId = ttsConfig.voiceId;
34
+ const apiKey = ttsConfig.apiKey || config[`${provider}ApiKey`] || process.env[`${provider.toUpperCase()}_API_KEY`];
35
+
36
+ console.log(chalk.cyan('\n 🎤 Voice Status\n'));
37
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
38
+ console.log(` ${chalk.white('Provider:')} ${chalk.cyan(provider)}`);
39
+ console.log(` ${chalk.white('Voice ID:')} ${chalk.cyan(voiceId || '(default)')}`);
40
+ console.log(` ${chalk.white('API Key:')} ${chalk.gray(mask(apiKey))}`);
41
+ console.log(chalk.gray('\n Commands:'));
42
+ console.log(chalk.cyan(' natureco voice providers') + chalk.gray(' List available providers'));
43
+ console.log(chalk.cyan(' natureco voice set <provider> [voiceId]') + chalk.gray(' Set voice provider'));
44
+ console.log();
45
+ }
46
+
47
+ function listProviders() {
48
+ console.log(chalk.cyan('\n 🎤 Voice Providers\n'));
49
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
50
+
51
+ for (const [id, label] of Object.entries(PROVIDER_LABELS)) {
52
+ console.log(` ${chalk.white(label)} ${chalk.gray(`(${id})`)}`);
53
+ }
54
+
55
+ console.log(chalk.gray('\n Set provider:'));
56
+ console.log(chalk.cyan(' natureco voice set openai'));
57
+ console.log(chalk.cyan(' natureco voice set elevenlabs [voiceId]'));
58
+ console.log();
59
+ }
60
+
61
+ function setVoiceProvider(args) {
62
+ const provider = args[0];
63
+ const voiceId = args.slice(1).join(' ') || '';
64
+
65
+ if (!provider || !PROVIDER_LABELS[provider]) {
66
+ console.log(chalk.red(`\n ❌ Unknown provider: ${provider}\n`));
67
+ console.log(chalk.gray(' Available: ' + Object.keys(PROVIDER_LABELS).join(', ')));
68
+ console.log();
69
+ process.exit(1);
70
+ }
71
+
72
+ const config = getConfig();
73
+ if (!config.tts) config.tts = {};
74
+ config.tts.provider = provider;
75
+ if (voiceId) config.tts.voiceId = voiceId;
76
+ else delete config.tts.voiceId;
77
+ saveConfig(config);
78
+
79
+ console.log(chalk.green(`\n ✅ Voice provider set to ${PROVIDER_LABELS[provider]}${voiceId ? ` (voice: ${voiceId})` : ''}\n`));
80
+ }
81
+
82
+ module.exports = voice;
@@ -0,0 +1,98 @@
1
+ const chalk = require('chalk');
2
+ const { getConfig, saveConfig } = require('../utils/config');
3
+
4
+ const VYDRA_ENDPOINTS = {
5
+ 'vydra-image': {
6
+ name: 'Vydra Image Generation',
7
+ endpoint: 'https://api.vydra.ai/v1/images/generations',
8
+ docs: 'https://docs.vydra.ai/image-generation'
9
+ },
10
+ 'vydra-video': {
11
+ name: 'Vydra Video Generation',
12
+ endpoint: 'https://api.vydra.ai/v1/video/generations',
13
+ docs: 'https://docs.vydra.ai/video-generation'
14
+ },
15
+ 'vydra-music': {
16
+ name: 'Vydra Music Generation',
17
+ endpoint: 'https://api.vydra.ai/v1/music/generations',
18
+ docs: 'https://docs.vydra.ai/music-generation'
19
+ }
20
+ };
21
+
22
+ function vydra(args) {
23
+ const [action, ...params] = args || [];
24
+
25
+ if (!action || action === 'status') return statusVydra();
26
+ if (action === 'configure') return configureVydra(params[0], params[1]);
27
+ if (action === 'test') return testVydra();
28
+
29
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
30
+ console.log(chalk.gray(' Kullanım: natureco vydra [status|configure|test]\n'));
31
+ process.exit(1);
32
+ }
33
+
34
+ function statusVydra() {
35
+ const config = getConfig();
36
+ const apiKey = config.vydraApiKey || process.env.VYDRA_API_KEY;
37
+
38
+ console.log(chalk.cyan('\n 🎬 Vydra Media Provider\n'));
39
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
40
+ console.log(` ${chalk.white('API Key:')} ${apiKey ? chalk.green('Configured') : chalk.red('Not set')}`);
41
+ console.log(chalk.gray('\n Available endpoints:\n'));
42
+
43
+ for (const [id, ep] of Object.entries(VYDRA_ENDPOINTS)) {
44
+ const configured = apiKey ? chalk.green('✅') : chalk.gray('⏸️');
45
+ console.log(` ${configured} ${chalk.white(ep.name)}`);
46
+ console.log(` ${chalk.gray(ep.endpoint)}`);
47
+ }
48
+
49
+ console.log(chalk.gray('\n Commands:'));
50
+ console.log(chalk.cyan(' configure <key>') + chalk.gray(' Set Vydra API key'));
51
+ console.log(chalk.cyan(' test') + chalk.gray(' Test API connection'));
52
+ console.log();
53
+ }
54
+
55
+ function configureVydra(key) {
56
+ if (!key) {
57
+ console.log(chalk.red('\n ❌ API key gerekli\n'));
58
+ process.exit(1);
59
+ }
60
+
61
+ const config = getConfig();
62
+ config.vydraApiKey = key;
63
+ saveConfig(config);
64
+ console.log(chalk.green('\n ✅ Vydra API key saved\n'));
65
+ }
66
+
67
+ async function testVydra() {
68
+ const config = getConfig();
69
+ const apiKey = config.vydraApiKey || process.env.VYDRA_API_KEY;
70
+
71
+ if (!apiKey) {
72
+ console.log(chalk.red('\n ❌ Vydra API key gerekli\n'));
73
+ console.log(chalk.cyan(' natureco vydra configure <your-api-key>\n'));
74
+ process.exit(1);
75
+ }
76
+
77
+ console.log(chalk.cyan('\n Testing Vydra API connection...\n'));
78
+
79
+ for (const [id, ep] of Object.entries(VYDRA_ENDPOINTS)) {
80
+ try {
81
+ const response = await fetch(ep.endpoint, {
82
+ method: 'HEAD',
83
+ headers: { 'Authorization': `Bearer ${apiKey}` }
84
+ });
85
+ console.log(` ${response.ok ? chalk.green('✅') : chalk.red('❌')} ${chalk.white(ep.name)} ${chalk.gray(`(${response.status})`)}`);
86
+ } catch (err) {
87
+ console.log(` ${chalk.red('❌')} ${chalk.white(ep.name)} ${chalk.gray(`(${err.message})`)}`);
88
+ }
89
+ }
90
+
91
+ console.log(chalk.gray('\n Vydra API endpoints are available as providers for:'));
92
+ console.log(chalk.cyan(' image_generation') + chalk.gray(' tool (provider: vydra)'));
93
+ console.log(chalk.cyan(' video_generation') + chalk.gray(' tool (provider: vydra)'));
94
+ console.log(chalk.cyan(' music_generation') + chalk.gray(' tool (provider: vydra)'));
95
+ console.log();
96
+ }
97
+
98
+ module.exports = vydra;