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.
- package/README.md +94 -11
- package/bin/natureco.js +402 -4
- package/package.json +1 -1
- 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/clickclack.js +130 -0
- package/src/commands/commitments.js +32 -0
- package/src/commands/completion.js +76 -0
- 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/exec-policy.js +71 -0
- package/src/commands/gateway-server.js +1155 -24
- package/src/commands/health.js +18 -0
- package/src/commands/imessage.js +128 -14
- package/src/commands/infer.js +73 -0
- package/src/commands/irc.js +64 -15
- package/src/commands/mattermost.js +114 -12
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/message.js +9 -3
- package/src/commands/migrate.js +213 -2
- 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/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/setup.js +113 -7
- package/src/commands/signal.js +447 -18
- package/src/commands/sms.js +123 -19
- package/src/commands/system.js +53 -0
- 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/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- 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/memory.js +200 -0
package/src/commands/signal.js
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
3
3
|
const { getConfig, saveConfig } = require('../utils/config');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { spawn, execSync } = require('child_process');
|
|
4
8
|
|
|
5
|
-
|
|
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) {
|
|
6
15
|
if (!action || action === 'connect') return connectSignal();
|
|
7
16
|
if (action === 'disconnect') return disconnectSignal();
|
|
8
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();
|
|
9
21
|
console.log(chalk.red('\n❌ Unknown action\n'));
|
|
10
|
-
console.log(chalk.gray('Available actions: connect, disconnect, status\n'));
|
|
22
|
+
console.log(chalk.gray('Available actions: connect, disconnect, status, install, daemon, probe\n'));
|
|
11
23
|
process.exit(1);
|
|
12
24
|
}
|
|
13
25
|
|
|
@@ -18,34 +30,90 @@ async function connectSignal() {
|
|
|
18
30
|
process.exit(1);
|
|
19
31
|
}
|
|
20
32
|
console.log(chalk.yellow('\n⏳ Signal bağlantısı hazırlanıyor...\n'));
|
|
21
|
-
console.log(chalk.gray('Signal, signal-cli REST API üzerinden bağlanır
|
|
22
|
-
|
|
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
|
+
|
|
23
40
|
const answers = await inquirer.prompt([
|
|
24
|
-
{ type: 'input', name: 'httpUrl', message: 'signal-cli REST API URL
|
|
25
|
-
{ type: 'input', name: 'account', message: 'Signal hesap numarası (+905551234567):', validate: v => v.trim() ? true : 'Numara boş olamaz' },
|
|
26
|
-
{
|
|
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
|
+
]},
|
|
27
65
|
]);
|
|
66
|
+
|
|
28
67
|
const botId = `signal_${Date.now()}`;
|
|
29
|
-
config.signalHttpUrl = answers.httpUrl.trim();
|
|
68
|
+
config.signalHttpUrl = answers.httpUrl.trim().replace(/\/+$/, '');
|
|
30
69
|
config.signalAccount = answers.account.trim();
|
|
70
|
+
config.signalApiMode = answers.apiMode;
|
|
71
|
+
config.signalAutoStart = answers.autoStart;
|
|
72
|
+
config.signalReceiveMode = answers.receiveMode;
|
|
31
73
|
config.signalDmPolicy = answers.dmPolicy;
|
|
32
74
|
config.signalBotId = botId;
|
|
33
75
|
saveConfig(config);
|
|
76
|
+
|
|
34
77
|
console.log(chalk.green('\n✅ Signal bağlantısı kaydedildi!\n'));
|
|
35
78
|
console.log(chalk.cyan('Bot ID:'), chalk.white(botId));
|
|
36
|
-
console.log(chalk.cyan('API URL:'), chalk.white(
|
|
37
|
-
console.log(chalk.cyan('Hesap:'), chalk.white(
|
|
38
|
-
console.log(chalk.
|
|
39
|
-
console.log(chalk.
|
|
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'));
|
|
40
94
|
}
|
|
41
95
|
|
|
42
96
|
async function disconnectSignal() {
|
|
43
97
|
const config = getConfig();
|
|
44
|
-
if (!config.signalBotId) {
|
|
45
|
-
|
|
46
|
-
|
|
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
|
+
|
|
47
112
|
delete config.signalHttpUrl;
|
|
48
113
|
delete config.signalAccount;
|
|
114
|
+
delete config.signalApiMode;
|
|
115
|
+
delete config.signalAutoStart;
|
|
116
|
+
delete config.signalReceiveMode;
|
|
49
117
|
delete config.signalDmPolicy;
|
|
50
118
|
delete config.signalBotId;
|
|
51
119
|
saveConfig(config);
|
|
@@ -54,13 +122,374 @@ async function disconnectSignal() {
|
|
|
54
122
|
|
|
55
123
|
function statusSignal() {
|
|
56
124
|
const config = getConfig();
|
|
57
|
-
if (!config.signalBotId) {
|
|
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
|
+
|
|
58
134
|
console.log(chalk.green('\n✅ Signal connected\n'));
|
|
59
135
|
console.log(chalk.cyan('Bot ID:'), chalk.white(config.signalBotId));
|
|
60
|
-
console.log(chalk.cyan('API URL:'), chalk.white(config.signalHttpUrl));
|
|
136
|
+
console.log(chalk.cyan('REST API URL:'), chalk.white(config.signalHttpUrl));
|
|
61
137
|
console.log(chalk.cyan('Hesap:'), chalk.white(config.signalAccount));
|
|
138
|
+
console.log(chalk.cyan('API Modu:'), chalk.white(config.signalApiMode || 'auto'));
|
|
62
139
|
console.log(chalk.cyan('DM Politikası:'), chalk.white(config.signalDmPolicy || 'pairing'));
|
|
63
|
-
|
|
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;
|
|
64
493
|
}
|
|
65
494
|
|
|
66
495
|
module.exports = signal;
|