@aliwey/bmo 2.1.2 → 2.1.3
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/bmo.js +38 -4
- package/package.json +1 -1
- package/scripts/web_cmd.js +32 -0
package/bin/bmo.js
CHANGED
|
@@ -58,6 +58,34 @@ async function isPortOpen(port, host = '127.0.0.1') {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
function killProcessByPort(port) {
|
|
62
|
+
try {
|
|
63
|
+
if (os.platform() === 'win32') {
|
|
64
|
+
const output = execSync(`netstat -ano`, { encoding: 'utf8' });
|
|
65
|
+
const lines = output.split('\n');
|
|
66
|
+
for (const line of lines) {
|
|
67
|
+
if (line.includes(`:${port}`) && line.includes('LISTENING')) {
|
|
68
|
+
const parts = line.trim().split(/\s+/);
|
|
69
|
+
const pid = parts[parts.length - 1];
|
|
70
|
+
if (pid && pid !== '0') {
|
|
71
|
+
try {
|
|
72
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
73
|
+
} catch (e) {}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
try {
|
|
79
|
+
execSync(`fuser -k ${port}/tcp`, { stdio: 'ignore' });
|
|
80
|
+
} catch {
|
|
81
|
+
try {
|
|
82
|
+
execSync(`kill -9 $(lsof -t -i:${port})`, { stdio: 'ignore' });
|
|
83
|
+
} catch {}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {}
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
/** Resolve the embedded or system Python executable */
|
|
62
90
|
function getPython() {
|
|
63
91
|
const embeddedWin = path.join(BMO_HOME, 'python', 'python.exe');
|
|
@@ -152,12 +180,17 @@ Data lives in: ${BMO_HOME_DISPLAY}
|
|
|
152
180
|
// ── bmo --update [version] ────────────────────────────────────────────────
|
|
153
181
|
if (cmd === '--update' || cmd === '-update' || cmd === 'update') {
|
|
154
182
|
const ver = args[0] ? `@${args[0]}` : '@latest';
|
|
155
|
-
console.log(`Stopping any running BMO
|
|
183
|
+
console.log(`Stopping any running BMO processes and freeing ports...`);
|
|
184
|
+
|
|
185
|
+
// Kill processes on ports 3456 and 4097
|
|
186
|
+
killProcessByPort(3456);
|
|
187
|
+
killProcessByPort(4097);
|
|
188
|
+
|
|
156
189
|
try {
|
|
157
190
|
if (os.platform() === 'win32') {
|
|
158
|
-
execSync(`powershell -Command "Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*main.py*' -or $_.CommandLine -like '*cli.py*' -or $_.CommandLine -like '*bmo*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }"`, { stdio: 'ignore' });
|
|
191
|
+
execSync(`powershell -Command "Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*main.py*' -or $_.CommandLine -like '*cli.py*' -or $_.CommandLine -like '*bmo*' -or $_.CommandLine -like '*cloudflared*' -or $_.CommandLine -like '*server.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }"`, { stdio: 'ignore' });
|
|
159
192
|
} else {
|
|
160
|
-
execSync(`pkill -f "main.py|cli.py|bmo" || true`, { stdio: 'ignore' });
|
|
193
|
+
execSync(`pkill -f "main.py|cli.py|bmo|cloudflared|server.js" || true`, { stdio: 'ignore' });
|
|
161
194
|
}
|
|
162
195
|
} catch (e) {
|
|
163
196
|
// Ignore failures
|
|
@@ -166,7 +199,8 @@ Data lives in: ${BMO_HOME_DISPLAY}
|
|
|
166
199
|
if (os.platform() === 'win32') {
|
|
167
200
|
console.log('Launching updater in a new window to release folder/file locks...');
|
|
168
201
|
|
|
169
|
-
const
|
|
202
|
+
const psKillCmd = `powershell -Command \\"Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*main.py*' -or $_.CommandLine -like '*cli.py*' -or $_.CommandLine -like '*bmo*' -or $_.CommandLine -like '*cloudflared*' -or $_.CommandLine -like '*server.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }\\"`;
|
|
203
|
+
const cmdStr = `timeout /t 2 /nobreak >nul && ${psKillCmd} && echo [BMO Updater] Upgrading to @aliwey/bmo${ver}... && npm install -g @aliwey/bmo${ver} && echo [OK] BMO updated successfully! Press any key to close. && pause`;
|
|
170
204
|
|
|
171
205
|
spawn('cmd.exe', ['/c', 'start', 'cmd.exe', '/c', cmdStr], {
|
|
172
206
|
detached: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliwey/bmo",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "BMO — AI coding assistant with Telegram, CLI & Web sync. One command, all frontends.",
|
|
5
5
|
"keywords": ["ai", "coding-assistant", "telegram-bot", "cli", "opencode", "bfp"],
|
|
6
6
|
"homepage": "https://github.com/aliwey/bmo",
|
package/scripts/web_cmd.js
CHANGED
|
@@ -41,6 +41,34 @@ function getCloudflaredExe() {
|
|
|
41
41
|
process.exit(1);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function killProcessByPort(port) {
|
|
45
|
+
try {
|
|
46
|
+
if (os.platform() === 'win32') {
|
|
47
|
+
const output = execSync(`netstat -ano`, { encoding: 'utf8' });
|
|
48
|
+
const lines = output.split('\n');
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
if (line.includes(`:${port}`) && line.includes('LISTENING')) {
|
|
51
|
+
const parts = line.trim().split(/\s+/);
|
|
52
|
+
const pid = parts[parts.length - 1];
|
|
53
|
+
if (pid && pid !== '0') {
|
|
54
|
+
try {
|
|
55
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
56
|
+
} catch (e) {}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
try {
|
|
62
|
+
execSync(`fuser -k ${port}/tcp`, { stdio: 'ignore' });
|
|
63
|
+
} catch {
|
|
64
|
+
try {
|
|
65
|
+
execSync(`kill -9 $(lsof -t -i:${port})`, { stdio: 'ignore' });
|
|
66
|
+
} catch {}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {}
|
|
70
|
+
}
|
|
71
|
+
|
|
44
72
|
function loadTasks() {
|
|
45
73
|
try { return JSON.parse(fs.readFileSync(TASKS_FILE, 'utf8')); } catch { return {}; }
|
|
46
74
|
}
|
|
@@ -74,6 +102,10 @@ function waitForTunnelUrl(proc) {
|
|
|
74
102
|
console.log(` Local: http://127.0.0.1:${WEBCHAT_PORT}`);
|
|
75
103
|
console.log(` Public: ${existing}\n`);
|
|
76
104
|
process.exit(0);
|
|
105
|
+
} else {
|
|
106
|
+
console.log(`[Info] Port ${WEBCHAT_PORT} is in use by an unrecognized process. Freeing port...`);
|
|
107
|
+
killProcessByPort(WEBCHAT_PORT);
|
|
108
|
+
await sleep(1000); // Wait for the port to release
|
|
77
109
|
}
|
|
78
110
|
}
|
|
79
111
|
|