orchestrix-yuri 2.2.1 → 2.3.1
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/bin/install.js +6 -1
- package/bin/status.js +54 -0
- package/bin/stop.js +62 -0
- package/lib/gateway/channels/telegram.js +6 -2
- package/lib/gateway/index.js +10 -1
- package/package.json +1 -1
package/bin/install.js
CHANGED
|
@@ -13,8 +13,11 @@ if (command === 'install') {
|
|
|
13
13
|
const projectRoot = args[1] || process.cwd();
|
|
14
14
|
migrate(projectRoot);
|
|
15
15
|
} else if (command === 'start' || command === 'serve') {
|
|
16
|
-
// Delegate to serve.js with remaining args
|
|
17
16
|
require('./serve');
|
|
17
|
+
} else if (command === 'stop') {
|
|
18
|
+
require('./stop');
|
|
19
|
+
} else if (command === 'status') {
|
|
20
|
+
require('./status');
|
|
18
21
|
} else if (command === '--version' || command === '-v' || command === '-V') {
|
|
19
22
|
const { version } = require('../package.json');
|
|
20
23
|
console.log(version);
|
|
@@ -26,6 +29,8 @@ if (command === 'install') {
|
|
|
26
29
|
orchestrix-yuri install Install Yuri skill + global memory
|
|
27
30
|
orchestrix-yuri start Start the Channel Gateway
|
|
28
31
|
orchestrix-yuri start --token TOKEN Start & save Telegram Bot token (first time only)
|
|
32
|
+
orchestrix-yuri stop Stop the running gateway
|
|
33
|
+
orchestrix-yuri status Show gateway status
|
|
29
34
|
orchestrix-yuri migrate [path] Migrate legacy memory.yaml
|
|
30
35
|
orchestrix-yuri --version Show version
|
|
31
36
|
orchestrix-yuri --help Show this help message
|
package/bin/status.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const PID_FILE = path.join(os.homedir(), '.yuri', 'gateway.pid');
|
|
10
|
+
|
|
11
|
+
function status() {
|
|
12
|
+
// Check PID
|
|
13
|
+
let pid = null;
|
|
14
|
+
let running = false;
|
|
15
|
+
|
|
16
|
+
if (fs.existsSync(PID_FILE)) {
|
|
17
|
+
pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
|
|
18
|
+
try {
|
|
19
|
+
process.kill(pid, 0);
|
|
20
|
+
running = true;
|
|
21
|
+
} catch {
|
|
22
|
+
running = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check tmux session
|
|
27
|
+
let tmuxAlive = false;
|
|
28
|
+
try {
|
|
29
|
+
execSync('tmux has-session -t yuri-gateway 2>/dev/null');
|
|
30
|
+
tmuxAlive = true;
|
|
31
|
+
} catch {
|
|
32
|
+
tmuxAlive = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(' Yuri Gateway Status');
|
|
37
|
+
console.log(' ───────────────────');
|
|
38
|
+
console.log(` Gateway process: ${running ? `\x1b[32mrunning\x1b[0m (PID ${pid})` : '\x1b[90mnot running\x1b[0m'}`);
|
|
39
|
+
console.log(` tmux session: ${tmuxAlive ? '\x1b[32myuri-gateway (active)\x1b[0m' : '\x1b[90mnone\x1b[0m'}`);
|
|
40
|
+
|
|
41
|
+
// Check config
|
|
42
|
+
const configPath = path.join(os.homedir(), '.yuri', 'config', 'channels.yaml');
|
|
43
|
+
if (fs.existsSync(configPath)) {
|
|
44
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
45
|
+
const hasToken = /token:\s*".+"/.test(content) || /token:\s*'.+'/.test(content);
|
|
46
|
+
console.log(` Telegram token: ${hasToken ? '\x1b[32mconfigured\x1b[0m' : '\x1b[90mnot set\x1b[0m'}`);
|
|
47
|
+
} else {
|
|
48
|
+
console.log(' Config: \x1b[90mnot found\x1b[0m');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
status();
|
package/bin/stop.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const PID_FILE = path.join(os.homedir(), '.yuri', 'gateway.pid');
|
|
10
|
+
|
|
11
|
+
function stop() {
|
|
12
|
+
if (!fs.existsSync(PID_FILE)) {
|
|
13
|
+
console.log(' No gateway is running (no PID file found).');
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
|
|
18
|
+
|
|
19
|
+
// Check if process is alive
|
|
20
|
+
try {
|
|
21
|
+
process.kill(pid, 0); // signal 0 = just check existence
|
|
22
|
+
} catch {
|
|
23
|
+
console.log(` Gateway PID ${pid} is not running. Cleaning up stale PID file.`);
|
|
24
|
+
fs.unlinkSync(PID_FILE);
|
|
25
|
+
cleanupTmux();
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Send SIGTERM for graceful shutdown
|
|
30
|
+
console.log(` Stopping gateway (PID ${pid})...`);
|
|
31
|
+
try {
|
|
32
|
+
process.kill(pid, 'SIGTERM');
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(` ❌ Failed to stop: ${err.message}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Wait briefly then verify
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid, 0);
|
|
42
|
+
// Still alive, force kill
|
|
43
|
+
console.log(' Process did not exit gracefully, sending SIGKILL...');
|
|
44
|
+
process.kill(pid, 'SIGKILL');
|
|
45
|
+
} catch {
|
|
46
|
+
// Dead, good
|
|
47
|
+
}
|
|
48
|
+
cleanupTmux();
|
|
49
|
+
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
50
|
+
console.log(' ✅ Gateway stopped.');
|
|
51
|
+
}, 2000);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function cleanupTmux() {
|
|
55
|
+
try {
|
|
56
|
+
execSync('tmux kill-session -t yuri-gateway 2>/dev/null');
|
|
57
|
+
} catch {
|
|
58
|
+
// no session to kill
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
stop();
|
|
@@ -82,12 +82,16 @@ class TelegramAdapter {
|
|
|
82
82
|
log.warn(`Bot error: ${msg}`);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
//
|
|
85
|
+
// Force-disconnect any stale polling connection before starting.
|
|
86
|
+
// deleteWebhook clears webhooks but does NOT terminate existing
|
|
87
|
+
// long-polling getUpdates connections. A short getUpdates call
|
|
88
|
+
// with timeout=0 "steals" the connection, terminating the old one.
|
|
86
89
|
log.telegram('Connecting...');
|
|
87
90
|
try {
|
|
88
91
|
await this.bot.api.deleteWebhook({ drop_pending_updates: true });
|
|
92
|
+
await this.bot.api.raw.getUpdates({ offset: -1, limit: 1, timeout: 0 });
|
|
89
93
|
} catch {
|
|
90
|
-
// ignore —
|
|
94
|
+
// ignore — best effort cleanup
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
// Start polling
|
package/lib/gateway/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
3
6
|
const { loadConfig, applyCliOverrides } = require('./config');
|
|
4
7
|
const { Router } = require('./router');
|
|
5
8
|
const { TelegramAdapter } = require('./channels/telegram');
|
|
6
9
|
const { log, c } = require('./log');
|
|
7
10
|
|
|
11
|
+
const PID_FILE = path.join(os.homedir(), '.yuri', 'gateway.pid');
|
|
12
|
+
|
|
8
13
|
/**
|
|
9
14
|
* Start the Yuri Gateway.
|
|
10
15
|
*
|
|
@@ -39,7 +44,7 @@ async function startGateway(opts = {}) {
|
|
|
39
44
|
} catch (err) {
|
|
40
45
|
if (err.message.includes('409') || err.message.includes('Conflict')) {
|
|
41
46
|
log.error('Another bot instance is already running with this token.');
|
|
42
|
-
log.info('
|
|
47
|
+
log.info('Run: orchestrix-yuri stop');
|
|
43
48
|
} else {
|
|
44
49
|
log.error(`Telegram failed to start: ${err.message}`);
|
|
45
50
|
}
|
|
@@ -66,6 +71,9 @@ async function startGateway(opts = {}) {
|
|
|
66
71
|
process.exit(1);
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
// Write PID file for `orchestrix-yuri stop`
|
|
75
|
+
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
76
|
+
|
|
69
77
|
log.banner('Yuri Gateway is running. Press Ctrl+C to stop.');
|
|
70
78
|
|
|
71
79
|
// Graceful shutdown
|
|
@@ -76,6 +84,7 @@ async function startGateway(opts = {}) {
|
|
|
76
84
|
for (const adapter of adapters) {
|
|
77
85
|
await adapter.stop().catch(() => {});
|
|
78
86
|
}
|
|
87
|
+
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
79
88
|
process.exit(0);
|
|
80
89
|
};
|
|
81
90
|
|