bs9 1.4.2 → 1.4.6
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 +37 -24
- package/bin/bs9 +22 -0
- package/dist/bs9-nfpea7ta. +269 -0
- package/dist/bs9-xf46r11y. +269 -0
- package/dist/bs9-zmxbnn8g. +255 -0
- package/dist/bs9.js +1 -1
- package/package.json +3 -3
- package/src/commands/deploy.ts +1 -7
- package/src/commands/doctor.ts +332 -0
- package/src/commands/inspect.ts +603 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BS9 - Bun Sentinel 9
|
|
5
|
+
* High-performance, non-root process manager for Bun
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2026 BS9 (Bun Sentinel 9)
|
|
8
|
+
* Licensed under the MIT License
|
|
9
|
+
* https://github.com/xarhang/bs9
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync } from "node:child_process";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { getPlatformInfo } from "../platform/detect.js";
|
|
16
|
+
|
|
17
|
+
interface DoctorOptions {
|
|
18
|
+
check?: string;
|
|
19
|
+
verbose?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface HealthCheck {
|
|
23
|
+
name: string;
|
|
24
|
+
status: "✅ PASS" | "❌ FAIL" | "⚠️ WARN";
|
|
25
|
+
message: string;
|
|
26
|
+
details?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function doctorCommand(options: DoctorOptions): Promise<void> {
|
|
30
|
+
console.log("🏥 BS9 Health Check & Diagnostics");
|
|
31
|
+
console.log("=".repeat(80));
|
|
32
|
+
|
|
33
|
+
const checks: HealthCheck[] = [];
|
|
34
|
+
const platformInfo = getPlatformInfo();
|
|
35
|
+
|
|
36
|
+
// Basic installation checks
|
|
37
|
+
checks.push(checkBunInstallation());
|
|
38
|
+
checks.push(checkBS9Installation());
|
|
39
|
+
checks.push(checkPlatformDetection(platformInfo));
|
|
40
|
+
|
|
41
|
+
// Directory structure checks
|
|
42
|
+
checks.push(checkDirectoryStructure(platformInfo));
|
|
43
|
+
checks.push(checkPermissions(platformInfo));
|
|
44
|
+
|
|
45
|
+
// Service manager checks
|
|
46
|
+
checks.push(checkServiceManager(platformInfo));
|
|
47
|
+
|
|
48
|
+
// Network and connectivity checks
|
|
49
|
+
checks.push(checkNetworkConnectivity());
|
|
50
|
+
|
|
51
|
+
// Optional checks based on flags
|
|
52
|
+
if (options.check) {
|
|
53
|
+
const specificChecks = runSpecificCheck(options.check, platformInfo);
|
|
54
|
+
checks.push(...specificChecks);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (options.verbose) {
|
|
58
|
+
checks.push(checkSystemResources());
|
|
59
|
+
checks.push(checkDependencies());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Display results
|
|
63
|
+
displayResults(checks);
|
|
64
|
+
|
|
65
|
+
// Summary
|
|
66
|
+
const passed = checks.filter(c => c.status === "✅ PASS").length;
|
|
67
|
+
const failed = checks.filter(c => c.status === "❌ FAIL").length;
|
|
68
|
+
const warnings = checks.filter(c => c.status === "⚠️ WARN").length;
|
|
69
|
+
|
|
70
|
+
console.log("\n" + "=".repeat(80));
|
|
71
|
+
console.log(`📊 Health Check Summary:`);
|
|
72
|
+
console.log(` ✅ Passed: ${passed}`);
|
|
73
|
+
console.log(` ❌ Failed: ${failed}`);
|
|
74
|
+
console.log(` ⚠️ Warnings: ${warnings}`);
|
|
75
|
+
console.log(` 📈 Total: ${checks.length}`);
|
|
76
|
+
|
|
77
|
+
if (failed > 0) {
|
|
78
|
+
console.log(`\n❌ Health check FAILED with ${failed} error(s)`);
|
|
79
|
+
console.log("💡 Run 'bs9 doctor --verbose' for more details");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(`\n✅ Health check PASSED - BS9 is ready to use!`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function checkBunInstallation(): HealthCheck {
|
|
87
|
+
try {
|
|
88
|
+
const version = execSync("bun --version", { encoding: "utf-8" }).trim();
|
|
89
|
+
return {
|
|
90
|
+
name: "Bun Installation",
|
|
91
|
+
status: "✅ PASS",
|
|
92
|
+
message: `Bun v${version} installed`,
|
|
93
|
+
details: `Runtime: ${version}`
|
|
94
|
+
};
|
|
95
|
+
} catch {
|
|
96
|
+
return {
|
|
97
|
+
name: "Bun Installation",
|
|
98
|
+
status: "❌ FAIL",
|
|
99
|
+
message: "Bun is not installed or not in PATH",
|
|
100
|
+
details: "Install Bun from https://bun.sh"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function checkBS9Installation(): HealthCheck {
|
|
106
|
+
try {
|
|
107
|
+
const version = execSync("bs9 --version", { encoding: "utf-8" }).trim();
|
|
108
|
+
return {
|
|
109
|
+
name: "BS9 Installation",
|
|
110
|
+
status: "✅ PASS",
|
|
111
|
+
message: `BS9 ${version} installed`,
|
|
112
|
+
details: `CLI: ${version}`
|
|
113
|
+
};
|
|
114
|
+
} catch {
|
|
115
|
+
return {
|
|
116
|
+
name: "BS9 Installation",
|
|
117
|
+
status: "❌ FAIL",
|
|
118
|
+
message: "BS9 is not installed or not in PATH",
|
|
119
|
+
details: "Run 'npm install -g bs9' or install from source"
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function checkPlatformDetection(platformInfo: any): HealthCheck {
|
|
125
|
+
return {
|
|
126
|
+
name: "Platform Detection",
|
|
127
|
+
status: "✅ PASS",
|
|
128
|
+
message: `Detected ${platformInfo.platform}`,
|
|
129
|
+
details: `OS: ${platformInfo.platform}, Service Manager: ${platformInfo.serviceManager}`
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function checkDirectoryStructure(platformInfo: any): HealthCheck {
|
|
134
|
+
const requiredDirs = [
|
|
135
|
+
platformInfo.configDir,
|
|
136
|
+
platformInfo.logDir,
|
|
137
|
+
platformInfo.serviceDir
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const missingDirs = requiredDirs.filter(dir => !existsSync(dir));
|
|
141
|
+
|
|
142
|
+
if (missingDirs.length === 0) {
|
|
143
|
+
return {
|
|
144
|
+
name: "Directory Structure",
|
|
145
|
+
status: "✅ PASS",
|
|
146
|
+
message: "All required directories exist",
|
|
147
|
+
details: `Config: ${platformInfo.configDir}`
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
return {
|
|
151
|
+
name: "Directory Structure",
|
|
152
|
+
status: "❌ FAIL",
|
|
153
|
+
message: `Missing ${missingDirs.length} directories`,
|
|
154
|
+
details: `Missing: ${missingDirs.join(", ")}`
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function checkPermissions(platformInfo: any): HealthCheck {
|
|
160
|
+
try {
|
|
161
|
+
// Test write permissions
|
|
162
|
+
const testFile = join(platformInfo.configDir, ".bs9-test");
|
|
163
|
+
execSync(`touch "${testFile}"`, { stdio: "ignore" });
|
|
164
|
+
execSync(`rm "${testFile}"`, { stdio: "ignore" });
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
name: "File Permissions",
|
|
168
|
+
status: "✅ PASS",
|
|
169
|
+
message: "Write permissions OK",
|
|
170
|
+
details: `Can write to ${platformInfo.configDir}`
|
|
171
|
+
};
|
|
172
|
+
} catch {
|
|
173
|
+
return {
|
|
174
|
+
name: "File Permissions",
|
|
175
|
+
status: "❌ FAIL",
|
|
176
|
+
message: "Insufficient file permissions",
|
|
177
|
+
details: `Cannot write to ${platformInfo.configDir}`
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function checkServiceManager(platformInfo: any): HealthCheck {
|
|
183
|
+
try {
|
|
184
|
+
switch (platformInfo.platform) {
|
|
185
|
+
case "linux":
|
|
186
|
+
execSync("systemctl --user --version", { stdio: "ignore" });
|
|
187
|
+
return {
|
|
188
|
+
name: "Service Manager",
|
|
189
|
+
status: "✅ PASS",
|
|
190
|
+
message: "systemd user services available",
|
|
191
|
+
details: "systemd user mode is working"
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
case "darwin":
|
|
195
|
+
execSync("launchctl list", { stdio: "ignore" });
|
|
196
|
+
return {
|
|
197
|
+
name: "Service Manager",
|
|
198
|
+
status: "✅ PASS",
|
|
199
|
+
message: "launchd available",
|
|
200
|
+
details: "macOS launchd is working"
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
case "win32":
|
|
204
|
+
execSync("sc query", { stdio: "ignore" });
|
|
205
|
+
return {
|
|
206
|
+
name: "Service Manager",
|
|
207
|
+
status: "✅ PASS",
|
|
208
|
+
message: "Windows Services available",
|
|
209
|
+
details: "Windows Service Manager is working"
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
return {
|
|
214
|
+
name: "Service Manager",
|
|
215
|
+
status: "⚠️ WARN",
|
|
216
|
+
message: "Unsupported platform",
|
|
217
|
+
details: `Platform ${platformInfo.platform} may have limited support`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
} catch {
|
|
221
|
+
return {
|
|
222
|
+
name: "Service Manager",
|
|
223
|
+
status: "❌ FAIL",
|
|
224
|
+
message: "Service manager not available",
|
|
225
|
+
details: "Cannot access system service manager"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function checkNetworkConnectivity(): HealthCheck {
|
|
231
|
+
try {
|
|
232
|
+
// Test basic network connectivity
|
|
233
|
+
execSync("curl -s --connect-timeout 3 http://httpbin.org/ip", { stdio: "ignore" });
|
|
234
|
+
return {
|
|
235
|
+
name: "Network Connectivity",
|
|
236
|
+
status: "✅ PASS",
|
|
237
|
+
message: "Network connectivity OK",
|
|
238
|
+
details: "Can reach external services"
|
|
239
|
+
};
|
|
240
|
+
} catch {
|
|
241
|
+
return {
|
|
242
|
+
name: "Network Connectivity",
|
|
243
|
+
status: "⚠️ WARN",
|
|
244
|
+
message: "Limited network connectivity",
|
|
245
|
+
details: "Cannot reach external services (may be offline)"
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function checkSystemResources(): HealthCheck {
|
|
251
|
+
try {
|
|
252
|
+
const memory = execSync("free -h", { encoding: "utf-8" });
|
|
253
|
+
const disk = execSync("df -h .", { encoding: "utf-8" });
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
name: "System Resources",
|
|
257
|
+
status: "✅ PASS",
|
|
258
|
+
message: "System resources OK",
|
|
259
|
+
details: `Memory and disk space available`
|
|
260
|
+
};
|
|
261
|
+
} catch {
|
|
262
|
+
return {
|
|
263
|
+
name: "System Resources",
|
|
264
|
+
status: "⚠️ WARN",
|
|
265
|
+
message: "Cannot check system resources",
|
|
266
|
+
details: "Resource monitoring not available"
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function checkDependencies(): HealthCheck {
|
|
272
|
+
try {
|
|
273
|
+
const packageJson = JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8"));
|
|
274
|
+
const deps = Object.keys(packageJson.dependencies || {});
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
name: "Dependencies",
|
|
278
|
+
status: "✅ PASS",
|
|
279
|
+
message: `${deps.length} dependencies found`,
|
|
280
|
+
details: `Dependencies: ${deps.slice(0, 3).join(", ")}${deps.length > 3 ? "..." : ""}`
|
|
281
|
+
};
|
|
282
|
+
} catch {
|
|
283
|
+
return {
|
|
284
|
+
name: "Dependencies",
|
|
285
|
+
status: "⚠️ WARN",
|
|
286
|
+
message: "No package.json found",
|
|
287
|
+
details: "Not in a Node.js project directory"
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function runSpecificCheck(check: string, platformInfo: any): HealthCheck[] {
|
|
293
|
+
const checks: HealthCheck[] = [];
|
|
294
|
+
|
|
295
|
+
switch (check.toLowerCase()) {
|
|
296
|
+
case "dependencies":
|
|
297
|
+
checks.push(checkDependencies());
|
|
298
|
+
break;
|
|
299
|
+
|
|
300
|
+
case "configuration":
|
|
301
|
+
checks.push(checkDirectoryStructure(platformInfo));
|
|
302
|
+
checks.push(checkPermissions(platformInfo));
|
|
303
|
+
break;
|
|
304
|
+
|
|
305
|
+
case "platform":
|
|
306
|
+
checks.push(checkPlatformDetection(platformInfo));
|
|
307
|
+
checks.push(checkServiceManager(platformInfo));
|
|
308
|
+
break;
|
|
309
|
+
|
|
310
|
+
default:
|
|
311
|
+
checks.push({
|
|
312
|
+
name: "Specific Check",
|
|
313
|
+
status: "❌ FAIL",
|
|
314
|
+
message: `Unknown check: ${check}`,
|
|
315
|
+
details: "Available checks: dependencies, configuration, platform"
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return checks;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function displayResults(checks: HealthCheck[]): void {
|
|
323
|
+
console.log("\n🔍 Health Check Results:");
|
|
324
|
+
console.log("-".repeat(80));
|
|
325
|
+
|
|
326
|
+
for (const check of checks) {
|
|
327
|
+
console.log(`${check.status} ${check.name}: ${check.message}`);
|
|
328
|
+
if (check.details) {
|
|
329
|
+
console.log(` 📋 ${check.details}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|