bm2 1.0.22 → 1.0.24
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/package.json +3 -1
- package/src/process-container.ts +31 -33
- package/src/process-table.ts +3 -0
- package/src/startup-manager.ts +42 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bm2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"description": "A blazing-fast, full-featured process manager built entirely on Bun native APIs. The modern PM2 replacement — zero Node.js dependencies, pure Bun performance.",
|
|
5
5
|
"main": "src/api.ts",
|
|
6
6
|
"module": "src/api.ts",
|
|
@@ -65,10 +65,12 @@
|
|
|
65
65
|
],
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"cli-table3": "^0.6.5",
|
|
68
|
+
"pidusage": "^4.0.1",
|
|
68
69
|
"ws": "^8.19.0"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@types/bun": "^1.3.9",
|
|
73
|
+
"@types/pidusage": "^2.0.5",
|
|
72
74
|
"@types/ws": "^8.18.1",
|
|
73
75
|
"bun-types": "latest",
|
|
74
76
|
"typescript": "^5.9.3"
|
package/src/process-container.ts
CHANGED
|
@@ -32,6 +32,9 @@ import {
|
|
|
32
32
|
DEFAULT_LOG_MAX_SIZE,
|
|
33
33
|
DEFAULT_LOG_RETAIN,
|
|
34
34
|
} from "./constants";
|
|
35
|
+
import pidusage from "pidusage";
|
|
36
|
+
import { readdir } from "node:fs/promises";
|
|
37
|
+
|
|
35
38
|
|
|
36
39
|
export class ProcessContainer {
|
|
37
40
|
public id: number;
|
|
@@ -238,42 +241,37 @@ export class ProcessContainer {
|
|
|
238
241
|
} catch {}
|
|
239
242
|
}
|
|
240
243
|
|
|
244
|
+
|
|
241
245
|
private startMonitoring() {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
246
|
+
this.monitorInterval = setInterval(async () => {
|
|
247
|
+
|
|
248
|
+
if (!this.pid || this.status !== "online") return;
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
|
|
252
|
+
// 1. Fetch cross-platform CPU and Memory usage
|
|
253
|
+
const stats = await pidusage(this.pid);
|
|
254
|
+
|
|
255
|
+
// pidusage returns memory directly in bytes and cpu as a percentage
|
|
256
|
+
this.memory = stats.memory;
|
|
257
|
+
this.cpu = stats.cpu;
|
|
258
|
+
|
|
259
|
+
// 2. Track file descriptors (handles) on Linux
|
|
260
|
+
// (pidusage does not provide this metric, so we keep the original logic)
|
|
261
|
+
if (process.platform === "linux") {
|
|
262
|
+
try {
|
|
263
|
+
this.handles = (await readdir(`/proc/${this.pid}/fd`)).length;
|
|
264
|
+
} catch {}
|
|
252
265
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
this.
|
|
257
|
-
|
|
258
|
-
} else {
|
|
259
|
-
const ps = Bun.spawn(["ps", "-o", "rss=,pcpu=", "-p", String(this.pid)], {
|
|
260
|
-
stdout: "pipe", stderr: "pipe",
|
|
261
|
-
});
|
|
262
|
-
const output = await new Response(ps.stdout).text();
|
|
263
|
-
const parts = output.trim().split(/\s+/);
|
|
264
|
-
if (parts.length >= 2) {
|
|
265
|
-
this.memory = parseInt(parts[0]!) * 1024;
|
|
266
|
-
this.cpu = parseFloat(parts[1]!);
|
|
266
|
+
|
|
267
|
+
// 3. Max memory restart
|
|
268
|
+
if (this.config.maxMemoryRestart && this.memory > this.config.maxMemoryRestart) {
|
|
269
|
+
console.log(`[bm2] ${this.name} exceeded memory limit (${this.memory} > ${this.config.maxMemoryRestart}), restarting...`);
|
|
270
|
+
await this.restart();
|
|
267
271
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (this.config.maxMemoryRestart && this.memory > this.config.maxMemoryRestart) {
|
|
272
|
-
console.log(`[bm2] ${this.name} exceeded memory limit (${this.memory} > ${this.config.maxMemoryRestart}), restarting...`);
|
|
273
|
-
await this.restart();
|
|
274
|
-
}
|
|
275
|
-
} catch {}
|
|
276
|
-
}, MONITOR_INTERVAL);
|
|
272
|
+
|
|
273
|
+
} catch {}
|
|
274
|
+
}, MONITOR_INTERVAL);
|
|
277
275
|
}
|
|
278
276
|
|
|
279
277
|
private startLogRotation(logPaths: { outFile: string; errFile: string }) {
|
package/src/process-table.ts
CHANGED
|
@@ -106,6 +106,8 @@ export function printProcessTable(processes: ProcessState[]) {
|
|
|
106
106
|
style: { border: ["dim"] },
|
|
107
107
|
chars: minimalBorders(),
|
|
108
108
|
});
|
|
109
|
+
|
|
110
|
+
//console.log("processes===>", processes)
|
|
109
111
|
|
|
110
112
|
for (const p of processes) {
|
|
111
113
|
const cpu = p.monit?.cpu ?? 0;
|
|
@@ -158,6 +160,7 @@ export function liveWatchProcess(processes: ProcessState[], interval = 5_000) {
|
|
|
158
160
|
// Render table
|
|
159
161
|
const render = () => {
|
|
160
162
|
clear();
|
|
163
|
+
|
|
161
164
|
printProcessTable(getSortedProcesses());
|
|
162
165
|
|
|
163
166
|
console.log(color("─".repeat(50), "dim"));
|
package/src/startup-manager.ts
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { join } from "path";
|
|
18
|
-
|
|
18
|
+
import { $ } from "bun";
|
|
19
|
+
|
|
19
20
|
export class StartupManager {
|
|
20
21
|
async generate(platform?: string): Promise<string> {
|
|
21
22
|
const os = platform || process.platform;
|
|
@@ -59,7 +60,7 @@ ExecStop=${bunPath} run ${bm2Path} kill
|
|
|
59
60
|
WantedBy=multi-user.target
|
|
60
61
|
`;
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
const servicePath = "/etc/systemd/system/bm2.service";
|
|
63
64
|
return `# BM2 Systemd Service
|
|
64
65
|
# Save to: ${servicePath}
|
|
65
66
|
# Then run:
|
|
@@ -101,29 +102,41 @@ ${unit}`;
|
|
|
101
102
|
</dict>
|
|
102
103
|
</plist>`;
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
const plistPath = `${process.env.HOME}/Library/LaunchAgents/com.bm2.daemon.plist`;
|
|
106
|
+
|
|
107
|
+
return `# BM2 LaunchAgent (macOS)
|
|
108
|
+
# Save to: ${plistPath}
|
|
109
|
+
# Then run:
|
|
110
|
+
# launchctl load ${plistPath}
|
|
109
111
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
${plist}`;
|
|
113
|
+
}
|
|
112
114
|
|
|
113
115
|
async install(): Promise<string> {
|
|
114
116
|
const os = process.platform;
|
|
115
117
|
const content = await this.generate(os);
|
|
116
118
|
|
|
117
119
|
if (os === "linux") {
|
|
120
|
+
|
|
118
121
|
const servicePath = "/etc/systemd/system/bm2.service";
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
|
|
123
|
+
const unitStart = content.indexOf("[Unit]");
|
|
124
|
+
const unitContent = content.substring(unitStart);
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await Bun.write(servicePath, unitContent);
|
|
128
|
+
} catch {
|
|
129
|
+
return "Failed to create the service file. Please ensure you have sufficient permissions (try running with sudo).";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Bun.spawn(["sudo", "systemctl", "daemon-reload"], { stdout: "inherit" }).exited;
|
|
133
|
+
// Bun.spawn(["sudo", "systemctl", "enable", "bm2"], { stdout: "inherit" }).exited;
|
|
134
|
+
|
|
135
|
+
await $`systemctl daemon-reload`;
|
|
136
|
+
await $`systemctl enable bm2`;
|
|
137
|
+
await $`systemctl start bm2`;
|
|
138
|
+
|
|
139
|
+
return `Service installed at ${servicePath}`;
|
|
127
140
|
} else if (os === "darwin") {
|
|
128
141
|
const plistPath = `${process.env.HOME}/Library/LaunchAgents/com.bm2.daemon.plist`;
|
|
129
142
|
// Extract plist content
|
|
@@ -141,17 +154,21 @@ ${unit}`;
|
|
|
141
154
|
const os = process.platform;
|
|
142
155
|
|
|
143
156
|
if (os === "linux") {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
157
|
+
|
|
158
|
+
await $`systemctl stop bm2`;
|
|
159
|
+
await $`systemctl disable bm2`;
|
|
160
|
+
|
|
161
|
+
await $`rm -f /etc/systemd/system/bm2.service`;
|
|
162
|
+
await $`systemctl daemon-reload`;
|
|
163
|
+
|
|
149
164
|
return "BM2 service removed";
|
|
165
|
+
|
|
150
166
|
} else if (os === "darwin") {
|
|
167
|
+
|
|
151
168
|
const plistPath = `${process.env.HOME}/Library/LaunchAgents/com.bm2.daemon.plist`;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
|
|
170
|
+
await $`launchctl unload ${plistPath}`;
|
|
171
|
+
await $`rm -f ${plistPath}`;
|
|
155
172
|
return "BM2 launch agent removed";
|
|
156
173
|
}
|
|
157
174
|
|