natureco-cli 2.23.28 → 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.
- package/README.md +94 -11
- package/bin/natureco.js +470 -10
- package/package.json +10 -6
- package/src/commands/admin-rpc.js +219 -0
- package/src/commands/agent.js +89 -0
- package/src/commands/approvals.js +53 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/capability.js +64 -0
- package/src/commands/channels.js +94 -4
- package/src/commands/chat.js +11 -25
- package/src/commands/clickclack.js +130 -0
- package/src/commands/commitments.js +32 -0
- package/src/commands/completion.js +76 -0
- package/src/commands/config.js +111 -68
- package/src/commands/configure.js +93 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/daemon.js +60 -0
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +110 -0
- package/src/commands/directory.js +47 -0
- package/src/commands/dns.js +58 -0
- package/src/commands/docs.js +43 -0
- package/src/commands/doctor.js +121 -16
- package/src/commands/exec-policy.js +71 -0
- package/src/commands/gateway-server.js +1175 -30
- package/src/commands/gateway.js +11 -20
- package/src/commands/health.js +18 -0
- package/src/commands/help.js +6 -0
- package/src/commands/imessage.js +169 -0
- package/src/commands/infer.js +73 -0
- package/src/commands/irc.js +119 -0
- package/src/commands/mattermost.js +164 -0
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/message.js +30 -4
- package/src/commands/migrate.js +213 -2
- package/src/commands/models.js +584 -216
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +106 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +70 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/plugins.js +415 -172
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +155 -0
- package/src/commands/qr.js +28 -0
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +118 -0
- package/src/commands/security.js +149 -1
- package/src/commands/setup.js +114 -10
- package/src/commands/signal.js +495 -0
- package/src/commands/skills.js +20 -29
- package/src/commands/sms.js +168 -0
- package/src/commands/system.js +53 -0
- package/src/commands/tasks.js +328 -79
- package/src/commands/terminal.js +21 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +72 -0
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/webhooks.js +79 -0
- package/src/commands/whatsapp.js +7 -21
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- package/src/tools/bash.js +63 -29
- package/src/tools/browser.js +112 -0
- package/src/tools/canvas.js +104 -0
- package/src/tools/document_extract.js +84 -0
- package/src/tools/duckduckgo.js +54 -0
- package/src/tools/exa_search.js +66 -0
- package/src/tools/firecrawl.js +104 -0
- package/src/tools/image_generation.js +99 -0
- package/src/tools/llm_task.js +118 -0
- package/src/tools/media_understanding.js +128 -0
- package/src/tools/music_generation.js +113 -0
- package/src/tools/parallel_search.js +77 -0
- package/src/tools/phone_control.js +80 -0
- package/src/tools/phone_control_enhanced.js +184 -0
- package/src/tools/searxng.js +61 -0
- package/src/tools/speech_to_text.js +135 -0
- package/src/tools/text_to_speech.js +105 -0
- package/src/tools/thread_ownership.js +88 -0
- package/src/tools/video_generation.js +72 -0
- package/src/tools/web_readability.js +104 -0
- package/src/utils/api.js +3 -20
- package/src/utils/approvals.js +297 -0
- package/src/utils/background.js +223 -66
- package/src/utils/baileys.js +21 -0
- package/src/utils/config.js +141 -10
- package/src/utils/errors.js +148 -0
- package/src/utils/inquirer-wrapper.js +1 -2
- package/src/utils/memory.js +200 -0
- package/src/utils/path-utils.js +13 -13
- package/src/utils/plugin-registry.js +238 -0
- package/src/utils/secrets.js +177 -0
- package/src/utils/skills.js +10 -23
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('../utils/inquirer-wrapper');
|
|
3
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { spawn, execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const SIGNAL_DIR = path.join(os.homedir(), '.natureco', 'signal');
|
|
10
|
+
const SIGNAL_PID_FILE = path.join(SIGNAL_DIR, 'daemon.pid');
|
|
11
|
+
const SIGNAL_LOG_FILE = path.join(SIGNAL_DIR, 'daemon.log');
|
|
12
|
+
const SIGNAL_CLI_VERSION = '0.13.6';
|
|
13
|
+
|
|
14
|
+
async function signal(action, subAction) {
|
|
15
|
+
if (!action || action === 'connect') return connectSignal();
|
|
16
|
+
if (action === 'disconnect') return disconnectSignal();
|
|
17
|
+
if (action === 'status') return statusSignal();
|
|
18
|
+
if (action === 'install') return installSignalCli();
|
|
19
|
+
if (action === 'daemon') return manageDaemon(subAction);
|
|
20
|
+
if (action === 'probe') return probeSignalCli();
|
|
21
|
+
console.log(chalk.red('\n❌ Unknown action\n'));
|
|
22
|
+
console.log(chalk.gray('Available actions: connect, disconnect, status, install, daemon, probe\n'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function connectSignal() {
|
|
27
|
+
const config = getConfig();
|
|
28
|
+
if (!config.providerUrl) {
|
|
29
|
+
console.log(chalk.red('\n❌ Setup yapılmamış. Önce "natureco setup" çalıştırın.\n'));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
console.log(chalk.yellow('\n⏳ Signal bağlantısı hazırlanıyor...\n'));
|
|
33
|
+
console.log(chalk.gray('Signal, signal-cli REST API üzerinden bağlanır.\n'));
|
|
34
|
+
|
|
35
|
+
const existing = config.signalHttpUrl || '';
|
|
36
|
+
const existingAccount = config.signalAccount || '';
|
|
37
|
+
const existingDm = config.signalDmPolicy || 'pairing';
|
|
38
|
+
const existingMode = config.signalApiMode || 'auto';
|
|
39
|
+
|
|
40
|
+
const answers = await inquirer.prompt([
|
|
41
|
+
{ type: 'input', name: 'httpUrl', message: 'signal-cli REST API URL:', default: existing || 'http://localhost:8080', validate: v => v.trim() ? true : 'URL boş olamaz' },
|
|
42
|
+
{ type: 'input', name: 'account', message: 'Signal hesap numarası (+905551234567):', default: existingAccount, validate: v => v.trim() ? true : 'Numara boş olamaz' },
|
|
43
|
+
{
|
|
44
|
+
type: 'list', name: 'apiMode', message: 'API modu:', default: existingMode,
|
|
45
|
+
choices: [
|
|
46
|
+
{ name: 'Auto-detect (önerilen)', value: 'auto' },
|
|
47
|
+
{ name: 'Native (signal-cli JSON-RPC)', value: 'native' },
|
|
48
|
+
{ name: 'Container (bbernhard/signal-cli-rest-api)', value: 'container' },
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{ type: 'confirm', name: 'autoStart', message: 'Gateway ile signal-cli daemon\'ı otomatik başlatılsın mı?', default: config.signalAutoStart !== undefined ? config.signalAutoStart : true },
|
|
52
|
+
{
|
|
53
|
+
type: 'list', name: 'receiveMode', message: 'Mesaj alma modu:', default: config.signalReceiveMode || 'on-start',
|
|
54
|
+
choices: [
|
|
55
|
+
{ name: 'Gateway başlangıcında dinlemeye başla (önerilen)', value: 'on-start' },
|
|
56
|
+
{ name: 'Manuel (sadece status kontrol)', value: 'manual' },
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{ type: 'list', name: 'dmPolicy', message: 'DM politikası:', default: existingDm, choices: [
|
|
60
|
+
{ name: 'Pairing (önerilen) — eşleşme onayı ile', value: 'pairing' },
|
|
61
|
+
{ name: 'Allowlist — sadece izin listesi', value: 'allowlist' },
|
|
62
|
+
{ name: 'Open — herkese açık', value: 'open' },
|
|
63
|
+
{ name: 'Disabled — devre dışı', value: 'disabled' },
|
|
64
|
+
]},
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const botId = `signal_${Date.now()}`;
|
|
68
|
+
config.signalHttpUrl = answers.httpUrl.trim().replace(/\/+$/, '');
|
|
69
|
+
config.signalAccount = answers.account.trim();
|
|
70
|
+
config.signalApiMode = answers.apiMode;
|
|
71
|
+
config.signalAutoStart = answers.autoStart;
|
|
72
|
+
config.signalReceiveMode = answers.receiveMode;
|
|
73
|
+
config.signalDmPolicy = answers.dmPolicy;
|
|
74
|
+
config.signalBotId = botId;
|
|
75
|
+
saveConfig(config);
|
|
76
|
+
|
|
77
|
+
console.log(chalk.green('\n✅ Signal bağlantısı kaydedildi!\n'));
|
|
78
|
+
console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
|
|
79
|
+
console.log(chalk.cyan('REST API URL:'), chalk.white(config.signalHttpUrl));
|
|
80
|
+
console.log(chalk.cyan('Hesap:'), chalk.white(config.signalAccount));
|
|
81
|
+
console.log(chalk.cyan('API Modu:'), chalk.white(answers.apiMode));
|
|
82
|
+
console.log(chalk.cyan('DM Politikası:'), chalk.white(answers.dmPolicy));
|
|
83
|
+
|
|
84
|
+
if (answers.autoStart) {
|
|
85
|
+
const signalCliPath = findSignalCli();
|
|
86
|
+
if (signalCliPath) {
|
|
87
|
+
console.log(chalk.gray(`\nsignal-cli bulundu: ${signalCliPath}`));
|
|
88
|
+
} else {
|
|
89
|
+
console.log(chalk.yellow('\n⚠️ signal-cli bulunamadı. İndirmek için:'));
|
|
90
|
+
console.log(chalk.cyan(' natureco signal install'));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.gray('\nGateway ile başlatmak için: natureco gateway start\n'));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function disconnectSignal() {
|
|
97
|
+
const config = getConfig();
|
|
98
|
+
if (!config.signalBotId) {
|
|
99
|
+
console.log(chalk.gray('\n⚠️ No Signal connection found\n'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const { confirm } = await inquirer.prompt([
|
|
103
|
+
{ type: 'confirm', name: 'confirm', message: 'Signal bağlantısını kaldırmak istediğinize emin misiniz?', default: false }
|
|
104
|
+
]);
|
|
105
|
+
if (!confirm) {
|
|
106
|
+
console.log(chalk.gray('\nCancelled\n'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Stop daemon if running
|
|
110
|
+
stopDaemonProcess();
|
|
111
|
+
|
|
112
|
+
delete config.signalHttpUrl;
|
|
113
|
+
delete config.signalAccount;
|
|
114
|
+
delete config.signalApiMode;
|
|
115
|
+
delete config.signalAutoStart;
|
|
116
|
+
delete config.signalReceiveMode;
|
|
117
|
+
delete config.signalDmPolicy;
|
|
118
|
+
delete config.signalBotId;
|
|
119
|
+
saveConfig(config);
|
|
120
|
+
console.log(chalk.green('\n✅ Signal disconnected\n'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function statusSignal() {
|
|
124
|
+
const config = getConfig();
|
|
125
|
+
if (!config.signalBotId) {
|
|
126
|
+
console.log(chalk.gray('\n⚠️ Signal not connected\n'));
|
|
127
|
+
console.log(chalk.gray('Connect with: natureco signal connect\n'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const daemonRunning = isDaemonRunning();
|
|
132
|
+
const apiReachable = probeSync(config);
|
|
133
|
+
|
|
134
|
+
console.log(chalk.green('\n✅ Signal connected\n'));
|
|
135
|
+
console.log(chalk.cyan('Bot ID:'), chalk.white(config.signalBotId));
|
|
136
|
+
console.log(chalk.cyan('REST API URL:'), chalk.white(config.signalHttpUrl));
|
|
137
|
+
console.log(chalk.cyan('Hesap:'), chalk.white(config.signalAccount));
|
|
138
|
+
console.log(chalk.cyan('API Modu:'), chalk.white(config.signalApiMode || 'auto'));
|
|
139
|
+
console.log(chalk.cyan('DM Politikası:'), chalk.white(config.signalDmPolicy || 'pairing'));
|
|
140
|
+
|
|
141
|
+
console.log('');
|
|
142
|
+
console.log(chalk.cyan('Daemon Durumu:'), daemonRunning ? chalk.green('✓ Çalışıyor') : chalk.gray('✗ Durduruldu'));
|
|
143
|
+
console.log(chalk.cyan('API Erişilebilirlik:'), apiReachable ? chalk.green('✓ Ulaşılabilir') : chalk.red('✗ Ulaşılamıyor'));
|
|
144
|
+
|
|
145
|
+
if (config.signalCliPath) {
|
|
146
|
+
console.log(chalk.gray(`\nsignal-cli: ${config.signalCliPath}`));
|
|
147
|
+
}
|
|
148
|
+
const cliPath = findSignalCli();
|
|
149
|
+
if (cliPath) {
|
|
150
|
+
console.log(chalk.gray(`signal-cli binary: ${cliPath}`));
|
|
151
|
+
}
|
|
152
|
+
console.log(chalk.gray('\nActions: connect, disconnect, install, daemon start/stop/status, probe\n'));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function installSignalCli() {
|
|
156
|
+
console.log(chalk.yellow('\n⏳ signal-cli indiriliyor...\n'));
|
|
157
|
+
|
|
158
|
+
if (!fs.existsSync(SIGNAL_DIR)) {
|
|
159
|
+
fs.mkdirSync(SIGNAL_DIR, { recursive: true });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const platform = process.platform;
|
|
163
|
+
let downloadUrl;
|
|
164
|
+
let archiveName;
|
|
165
|
+
|
|
166
|
+
if (platform === 'win32') {
|
|
167
|
+
archiveName = `signal-cli-${SIGNAL_CLI_VERSION}-Windows.tar.gz`;
|
|
168
|
+
downloadUrl = `https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/${archiveName}`;
|
|
169
|
+
} else if (platform === 'linux') {
|
|
170
|
+
archiveName = `signal-cli-${SIGNAL_CLI_VERSION}-Linux.tar.gz`;
|
|
171
|
+
downloadUrl = `https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/${archiveName}`;
|
|
172
|
+
} else if (platform === 'darwin') {
|
|
173
|
+
archiveName = `signal-cli-${SIGNAL_CLI_VERSION}-macOS.tar.gz`;
|
|
174
|
+
downloadUrl = `https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/${archiveName}`;
|
|
175
|
+
} else {
|
|
176
|
+
console.log(chalk.red(`\n❌ Platform desteklenmiyor: ${platform}\n`));
|
|
177
|
+
console.log(chalk.gray('Manual kurulum: https://github.com/AsamK/signal-cli#installation\n'));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const archivePath = path.join(SIGNAL_DIR, archiveName);
|
|
182
|
+
const extractDir = path.join(SIGNAL_DIR, `signal-cli-${SIGNAL_CLI_VERSION}`);
|
|
183
|
+
|
|
184
|
+
if (fs.existsSync(extractDir)) {
|
|
185
|
+
console.log(chalk.gray(`signal-cli ${SIGNAL_CLI_VERSION} zaten indirilmiş: ${extractDir}`));
|
|
186
|
+
const config = getConfig();
|
|
187
|
+
config.signalCliPath = path.join(extractDir, 'bin', 'signal-cli' + (platform === 'win32' ? '.bat' : ''));
|
|
188
|
+
saveConfig(config);
|
|
189
|
+
console.log(chalk.green('✅ Hazır\n'));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
console.log(chalk.cyan(`İndiriliyor: ${downloadUrl}`));
|
|
195
|
+
const response = await fetch(downloadUrl);
|
|
196
|
+
if (!response.ok) {
|
|
197
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
198
|
+
}
|
|
199
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
200
|
+
fs.writeFileSync(archivePath, buffer);
|
|
201
|
+
console.log(chalk.green(`✓ İndirildi (${(buffer.length / 1024 / 1024).toFixed(1)} MB)`));
|
|
202
|
+
|
|
203
|
+
// Extract
|
|
204
|
+
console.log(chalk.cyan('Ayıklanıyor...'));
|
|
205
|
+
const tar = require('tar');
|
|
206
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
207
|
+
await tar.x({ file: archivePath, cwd: SIGNAL_DIR });
|
|
208
|
+
console.log(chalk.green('✓ Ayıklandı'));
|
|
209
|
+
|
|
210
|
+
// Clean up archive
|
|
211
|
+
fs.unlinkSync(archivePath);
|
|
212
|
+
|
|
213
|
+
// Make executable on Unix
|
|
214
|
+
if (platform !== 'win32') {
|
|
215
|
+
const binaryPath = path.join(extractDir, 'bin', 'signal-cli');
|
|
216
|
+
if (fs.existsSync(binaryPath)) {
|
|
217
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Save path to config
|
|
222
|
+
const config = getConfig();
|
|
223
|
+
config.signalCliPath = path.join(extractDir, 'bin', 'signal-cli' + (platform === 'win32' ? '.bat' : ''));
|
|
224
|
+
saveConfig(config);
|
|
225
|
+
|
|
226
|
+
console.log(chalk.green(`\n✅ signal-cli ${SIGNAL_CLI_VERSION} kuruldu!\n`));
|
|
227
|
+
console.log(chalk.cyan('Binary:'), chalk.white(config.signalCliPath));
|
|
228
|
+
console.log(chalk.gray('\nDaemon\'ı başlatmak için: natureco signal daemon start\n'));
|
|
229
|
+
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.log(chalk.red(`\n❌ Kurulum hatası: ${err.message}\n`));
|
|
232
|
+
console.log(chalk.gray('Manuel kurulum: https://github.com/AsamK/signal-cli#installation\n'));
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function manageDaemon(subAction) {
|
|
238
|
+
const config = getConfig();
|
|
239
|
+
if (!config.signalBotId) {
|
|
240
|
+
console.log(chalk.red('\n❌ Signal bağlı değil\n'));
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (subAction === 'start') {
|
|
245
|
+
return startDaemon(config);
|
|
246
|
+
} else if (subAction === 'stop') {
|
|
247
|
+
return stopDaemon();
|
|
248
|
+
} else if (subAction === 'status') {
|
|
249
|
+
return daemonStatus();
|
|
250
|
+
} else {
|
|
251
|
+
console.log(chalk.red('\n❌ Unknown daemon action\n'));
|
|
252
|
+
console.log(chalk.gray('Usage: natureco signal daemon <start|stop|status>\n'));
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function startDaemon(config) {
|
|
258
|
+
if (isDaemonRunning()) {
|
|
259
|
+
console.log(chalk.yellow('\n⚠️ Daemon already running\n'));
|
|
260
|
+
console.log(chalk.cyan('PID:'), chalk.white(fs.readFileSync(SIGNAL_PID_FILE, 'utf-8').trim()));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const cliPath = config.signalCliPath || findSignalCli();
|
|
265
|
+
if (!cliPath) {
|
|
266
|
+
console.log(chalk.red('\n❌ signal-cli bulunamadı\n'));
|
|
267
|
+
console.log(chalk.yellow('Önce indirin:'), chalk.cyan('natureco signal install\n'));
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (!fs.existsSync(cliPath)) {
|
|
272
|
+
console.log(chalk.red(`\n❌ signal-cli binary bulunamadı: ${cliPath}\n`));
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!fs.existsSync(SIGNAL_DIR)) {
|
|
277
|
+
fs.mkdirSync(SIGNAL_DIR, { recursive: true });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const httpUrl = config.signalHttpUrl || 'http://localhost:8080';
|
|
281
|
+
const urlObj = new URL(httpUrl);
|
|
282
|
+
const host = urlObj.hostname || '127.0.0.1';
|
|
283
|
+
const port = urlObj.port || '8080';
|
|
284
|
+
const account = config.signalAccount;
|
|
285
|
+
|
|
286
|
+
console.log(chalk.yellow(`\n⏳ signal-cli daemon başlatılıyor...\n`));
|
|
287
|
+
console.log(chalk.gray(`HTTP: ${host}:${port}`));
|
|
288
|
+
console.log(chalk.gray(`Hesap: ${account}`));
|
|
289
|
+
|
|
290
|
+
const args = [
|
|
291
|
+
'daemon',
|
|
292
|
+
'--http', `${host}:${port}`,
|
|
293
|
+
'--no-receive-stdout',
|
|
294
|
+
];
|
|
295
|
+
if (account) {
|
|
296
|
+
args.push('-a', account);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const logFd = fs.openSync(SIGNAL_LOG_FILE, 'a');
|
|
300
|
+
const child = spawn(cliPath, args, {
|
|
301
|
+
detached: true,
|
|
302
|
+
stdio: ['ignore', logFd, logFd],
|
|
303
|
+
windowsHide: true,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
child.unref();
|
|
307
|
+
fs.writeFileSync(SIGNAL_PID_FILE, String(child.pid), 'utf-8');
|
|
308
|
+
|
|
309
|
+
console.log(chalk.green('✅ Daemon başlatıldı'));
|
|
310
|
+
console.log(chalk.cyan('PID:'), chalk.white(child.pid));
|
|
311
|
+
console.log(chalk.cyan('Log:'), chalk.white(SIGNAL_LOG_FILE));
|
|
312
|
+
|
|
313
|
+
// Wait for API to be ready
|
|
314
|
+
console.log(chalk.gray('\nAPI hazır olana kadar bekleniyor...'));
|
|
315
|
+
for (let i = 0; i < 30; i++) {
|
|
316
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
317
|
+
if (probeSync(config)) {
|
|
318
|
+
console.log(chalk.green('✓ API hazır\n'));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
process.stdout.write('.');
|
|
322
|
+
}
|
|
323
|
+
console.log(chalk.yellow('\n⚠️ API yanıt vermedi, logları kontrol edin\n'));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function stopDaemon() {
|
|
327
|
+
if (!isDaemonRunning()) {
|
|
328
|
+
console.log(chalk.gray('\n⚠️ Daemon not running\n'));
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const pid = parseInt(fs.readFileSync(SIGNAL_PID_FILE, 'utf-8').trim());
|
|
333
|
+
try {
|
|
334
|
+
if (process.platform === 'win32') {
|
|
335
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
336
|
+
} else {
|
|
337
|
+
process.kill(pid, 'SIGTERM');
|
|
338
|
+
setTimeout(() => {
|
|
339
|
+
try { process.kill(pid, 0); process.kill(pid, 'SIGKILL'); } catch {}
|
|
340
|
+
}, 3000);
|
|
341
|
+
}
|
|
342
|
+
if (fs.existsSync(SIGNAL_PID_FILE)) {
|
|
343
|
+
fs.unlinkSync(SIGNAL_PID_FILE);
|
|
344
|
+
}
|
|
345
|
+
console.log(chalk.green('\n✅ Daemon durduruldu\n'));
|
|
346
|
+
} catch (err) {
|
|
347
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function stopDaemonProcess() {
|
|
352
|
+
if (isDaemonRunning()) {
|
|
353
|
+
const pid = parseInt(fs.readFileSync(SIGNAL_PID_FILE, 'utf-8').trim());
|
|
354
|
+
try {
|
|
355
|
+
if (process.platform === 'win32') {
|
|
356
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
357
|
+
} else {
|
|
358
|
+
process.kill(pid, 'SIGTERM');
|
|
359
|
+
}
|
|
360
|
+
} catch {}
|
|
361
|
+
if (fs.existsSync(SIGNAL_PID_FILE)) {
|
|
362
|
+
fs.unlinkSync(SIGNAL_PID_FILE);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function daemonStatus() {
|
|
368
|
+
const running = isDaemonRunning();
|
|
369
|
+
console.log(running
|
|
370
|
+
? chalk.green(`\n✅ Daemon is running (PID: ${fs.readFileSync(SIGNAL_PID_FILE, 'utf-8').trim()})\n`)
|
|
371
|
+
: chalk.gray('\n⚠️ Daemon is not running\n'));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function isDaemonRunning() {
|
|
375
|
+
if (!fs.existsSync(SIGNAL_PID_FILE)) return false;
|
|
376
|
+
try {
|
|
377
|
+
const pid = parseInt(fs.readFileSync(SIGNAL_PID_FILE, 'utf-8').trim());
|
|
378
|
+
process.kill(pid, 0);
|
|
379
|
+
return true;
|
|
380
|
+
} catch {
|
|
381
|
+
if (fs.existsSync(SIGNAL_PID_FILE)) {
|
|
382
|
+
fs.unlinkSync(SIGNAL_PID_FILE);
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function probeSignalCli() {
|
|
389
|
+
const config = getConfig();
|
|
390
|
+
if (!config.signalHttpUrl) {
|
|
391
|
+
console.log(chalk.red('\n❌ Signal bağlantısı yapılmamış\n'));
|
|
392
|
+
console.log(chalk.gray('Önce: natureco signal connect\n'));
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const baseUrl = config.signalHttpUrl;
|
|
397
|
+
const mode = config.signalApiMode || 'auto';
|
|
398
|
+
console.log(chalk.yellow(`\n⏳ Problanıyor: ${baseUrl}\n`));
|
|
399
|
+
|
|
400
|
+
let nativeOk = false;
|
|
401
|
+
let containerOk = false;
|
|
402
|
+
|
|
403
|
+
// Try native mode
|
|
404
|
+
try {
|
|
405
|
+
const res = await fetch(`${baseUrl}/api/v1/check`, { signal: AbortSignal.timeout(5000) });
|
|
406
|
+
nativeOk = res.ok;
|
|
407
|
+
if (nativeOk) {
|
|
408
|
+
const text = await res.text();
|
|
409
|
+
console.log(chalk.green('✓ Native JSON-RPC API:'), chalk.white(res.status, text.slice(0, 100)));
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
console.log(chalk.gray(`✗ Native JSON-RPC API: ${err.message}`));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Try container mode
|
|
416
|
+
try {
|
|
417
|
+
const res = await fetch(`${baseUrl}/v1/about`, { signal: AbortSignal.timeout(5000) });
|
|
418
|
+
containerOk = res.ok;
|
|
419
|
+
if (containerOk) {
|
|
420
|
+
const data = await res.json();
|
|
421
|
+
console.log(chalk.green('✓ Container REST API:'), chalk.white(JSON.stringify(data).slice(0, 100)));
|
|
422
|
+
}
|
|
423
|
+
} catch (err) {
|
|
424
|
+
console.log(chalk.gray(`✗ Container REST API: ${err.message}`));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (mode === 'auto') {
|
|
428
|
+
const detected = nativeOk ? 'native' : containerOk ? 'container' : 'none';
|
|
429
|
+
console.log(chalk.cyan(`\nAuto-detect sonucu: ${detected}`));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const cliPath = findSignalCli();
|
|
433
|
+
if (cliPath) {
|
|
434
|
+
console.log(chalk.gray(`\nsignal-cli binary: ${cliPath}`));
|
|
435
|
+
try {
|
|
436
|
+
const versionOut = execSync(`"${cliPath}" --version`, { encoding: 'utf-8', timeout: 10000 });
|
|
437
|
+
console.log(chalk.gray(`Version: ${versionOut.trim()}`));
|
|
438
|
+
} catch {
|
|
439
|
+
console.log(chalk.gray('Version sorgulanamadı'));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
console.log('');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function probeSync(config) {
|
|
447
|
+
if (!config.signalHttpUrl) return false;
|
|
448
|
+
const baseUrl = config.signalHttpUrl;
|
|
449
|
+
try {
|
|
450
|
+
const res = execSync(
|
|
451
|
+
`powershell -Command "try { $r = Invoke-WebRequest -Uri '${baseUrl}/api/v1/check' -TimeoutSec 3 -UseBasicParsing; exit 0 } catch { exit 1 }"`,
|
|
452
|
+
{ timeout: 10000, stdio: 'pipe' }
|
|
453
|
+
);
|
|
454
|
+
return true;
|
|
455
|
+
} catch {
|
|
456
|
+
// Also check container mode
|
|
457
|
+
try {
|
|
458
|
+
execSync(
|
|
459
|
+
`powershell -Command "try { $r = Invoke-WebRequest -Uri '${baseUrl}/v1/about' -TimeoutSec 3 -UseBasicParsing; exit 0 } catch { exit 1 }"`,
|
|
460
|
+
{ timeout: 10000, stdio: 'pipe' }
|
|
461
|
+
);
|
|
462
|
+
return true;
|
|
463
|
+
} catch {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function findSignalCli() {
|
|
470
|
+
const config = getConfig();
|
|
471
|
+
if (config.signalCliPath && fs.existsSync(config.signalCliPath)) {
|
|
472
|
+
return config.signalCliPath;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Check installed locations
|
|
476
|
+
const candidates = [
|
|
477
|
+
path.join(SIGNAL_DIR, `signal-cli-${SIGNAL_CLI_VERSION}`, 'bin', 'signal-cli' + (process.platform === 'win32' ? '.bat' : '')),
|
|
478
|
+
path.join(SIGNAL_DIR, `signal-cli-${SIGNAL_CLI_VERSION}`, 'bin', 'signal-cli'),
|
|
479
|
+
];
|
|
480
|
+
|
|
481
|
+
for (const candidate of candidates) {
|
|
482
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Check PATH
|
|
486
|
+
try {
|
|
487
|
+
const which = execSync(process.platform === 'win32' ? 'where signal-cli' : 'which signal-cli', { encoding: 'utf-8', timeout: 5000 });
|
|
488
|
+
const p = which.trim().split('\n')[0];
|
|
489
|
+
if (p && fs.existsSync(p)) return p;
|
|
490
|
+
} catch {}
|
|
491
|
+
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
module.exports = signal;
|
package/src/commands/skills.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
3
3
|
const { getSkills, installSkill, removeSkill, updateAllSkills, createSkillTemplate, getPopularSkills } = require('../utils/skills');
|
|
4
|
+
const { NatureCoError, SkillError, handleError } = require('../utils/errors');
|
|
4
5
|
|
|
5
6
|
async function skills(args) {
|
|
6
7
|
const [action, ...params] = args;
|
|
@@ -167,11 +168,15 @@ async function createSkillCommand(name) {
|
|
|
167
168
|
|
|
168
169
|
async function searchSkillsCommand(query) {
|
|
169
170
|
if (!query || query.trim().length === 0) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
try {
|
|
172
|
+
const popularSkills = await getPopularSkills();
|
|
173
|
+
console.log(chalk.yellow('\nPopüler Skill\'ler:\n'));
|
|
174
|
+
popularSkills.forEach(skill => {
|
|
175
|
+
console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
|
|
176
|
+
});
|
|
177
|
+
} catch (err) {
|
|
178
|
+
console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
|
|
179
|
+
}
|
|
175
180
|
console.log('');
|
|
176
181
|
console.log(chalk.gray('Kurmak için: '), chalk.cyan('natureco skills install <slug>'));
|
|
177
182
|
console.log(chalk.gray('Örnek: '), chalk.cyan('natureco skills install github'));
|
|
@@ -188,14 +193,14 @@ async function searchSkillsCommand(query) {
|
|
|
188
193
|
const response = await fetch(searchUrl);
|
|
189
194
|
|
|
190
195
|
if (!response.ok) {
|
|
191
|
-
throw new
|
|
196
|
+
throw new SkillError('ClawHub API\'ye erişilemedi', 'fetch', `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}`);
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
let data;
|
|
195
200
|
try {
|
|
196
201
|
data = await response.json();
|
|
197
202
|
} catch {
|
|
198
|
-
throw new
|
|
203
|
+
throw new SkillError('ClawHub geçersiz yanıt döndü (JSON bekleniyordu)', 'parse', searchUrl);
|
|
199
204
|
}
|
|
200
205
|
const results = data.skills || [];
|
|
201
206
|
|
|
@@ -211,32 +216,18 @@ async function searchSkillsCommand(query) {
|
|
|
211
216
|
});
|
|
212
217
|
console.log('');
|
|
213
218
|
} catch (err) {
|
|
214
|
-
|
|
215
|
-
console.log(chalk.gray('ClawHub\'a bağlanılamadı, yerel aramada...\n'));
|
|
216
|
-
|
|
217
|
-
const popularSkills = await getPopularSkills();
|
|
218
|
-
const results = popularSkills.filter(skill =>
|
|
219
|
-
skill.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
220
|
-
skill.description.toLowerCase().includes(query.toLowerCase()) ||
|
|
221
|
-
skill.slug.toLowerCase().includes(query.toLowerCase())
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
if (results.length === 0) {
|
|
225
|
-
console.log(chalk.yellow(`"${query}" için sonuç bulunamadı.\n`));
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
console.log(chalk.yellow(`"${query}" için ${results.length} sonuç:\n`));
|
|
230
|
-
results.forEach(skill => {
|
|
231
|
-
console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
|
|
232
|
-
console.log(chalk.gray(` Kurmak için: natureco skills install ${skill.slug}`));
|
|
233
|
-
});
|
|
234
|
-
console.log('');
|
|
219
|
+
console.log(chalk.red(`\n ❌ Arama başarısız: ${err.message}\n`));
|
|
235
220
|
}
|
|
236
221
|
}
|
|
237
222
|
|
|
238
223
|
async function browseSkillsCommand() {
|
|
239
|
-
|
|
224
|
+
let popularSkills;
|
|
225
|
+
try {
|
|
226
|
+
popularSkills = await getPopularSkills();
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
240
231
|
|
|
241
232
|
console.log(chalk.green.bold('\n╭─ Popüler Skill\'ler ─╮\n'));
|
|
242
233
|
|