bs9 1.3.9 ā 1.4.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/README.md +8 -7
- package/package.json +1 -1
- package/src/commands/resurrect.ts +12 -14
- package/src/commands/save.ts +10 -12
- package/src/commands/status.ts +105 -19
- package/src/platform/detect.ts +37 -14
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# BS9 (Bun Sentinel 9) š
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://github.com/xarhang/bs9)
|
|
5
5
|
[](SECURITY.md)
|
|
6
6
|
[](PRODUCTION.md)
|
|
7
7
|
[](https://github.com/bs9/bs9)
|
|
@@ -26,24 +26,25 @@ chmod +x ~/.local/bin/bs9
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
### Platform Support
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
### š Platform Support
|
|
30
|
+
- **ā
Auto-Detection**: Automatically detects platform and creates directories
|
|
31
|
+
- **ā
Zero Configuration**: No manual setup required
|
|
32
|
+
- **ā
Cross-Platform**: Same commands work on all platforms
|
|
32
33
|
|
|
33
34
|
#### š§ Linux
|
|
34
35
|
- **Service Manager**: Systemd (user-mode)
|
|
35
36
|
- **Features**: Advanced security hardening, resource limits, sandboxing
|
|
36
|
-
- **Commands**: All
|
|
37
|
+
- **Commands**: All 21 commands available
|
|
37
38
|
|
|
38
39
|
#### š macOS
|
|
39
40
|
- **Service Manager**: Launchd
|
|
40
41
|
- **Features**: Native macOS integration, automatic recovery
|
|
41
|
-
- **Commands**:
|
|
42
|
+
- **Commands**: All commands + `bs9 macos` for launchd management
|
|
42
43
|
|
|
43
44
|
#### šŖ Windows
|
|
44
45
|
- **Service Manager**: Windows Services
|
|
45
46
|
- **Features**: PowerShell automation, event log integration
|
|
46
|
-
- **Commands**:
|
|
47
|
+
- **Commands**: All commands + `bs9 windows` for service management
|
|
47
48
|
|
|
48
49
|
```bash
|
|
49
50
|
# Check your platform
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { execSync } from "node:child_process";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import { getPlatformInfo } from "../platform/detect.js";
|
|
14
|
+
import { getPlatformInfo, initializePlatformDirectories } from "../platform/detect.js";
|
|
15
15
|
|
|
16
16
|
interface ResurrectOptions {
|
|
17
17
|
all?: boolean;
|
|
@@ -28,6 +28,9 @@ function isValidServiceName(name: string): boolean {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export async function resurrectCommand(name: string, options: ResurrectOptions): Promise<void> {
|
|
31
|
+
// Initialize platform directories
|
|
32
|
+
initializePlatformDirectories();
|
|
33
|
+
|
|
31
34
|
const platformInfo = getPlatformInfo();
|
|
32
35
|
|
|
33
36
|
// Handle resurrect all services
|
|
@@ -48,8 +51,7 @@ export async function resurrectCommand(name: string, options: ResurrectOptions):
|
|
|
48
51
|
const escapedName = name.replace(/[^a-zA-Z0-9._-]/g, '');
|
|
49
52
|
|
|
50
53
|
// Check if service exists in backup
|
|
51
|
-
const
|
|
52
|
-
const backupFile = join(backupDir, `${escapedName}.json`);
|
|
54
|
+
const backupFile = join(platformInfo.backupDir, `${escapedName}.json`);
|
|
53
55
|
|
|
54
56
|
if (!require('node:fs').existsSync(backupFile)) {
|
|
55
57
|
console.error(`ā No backup found for service '${name}'`);
|
|
@@ -115,16 +117,12 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
115
117
|
try {
|
|
116
118
|
console.log("š Resurrecting all BS9 services from backup...");
|
|
117
119
|
|
|
120
|
+
// Initialize platform directories
|
|
121
|
+
initializePlatformDirectories();
|
|
122
|
+
|
|
118
123
|
if (platformInfo.isLinux) {
|
|
119
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
120
|
-
|
|
121
|
-
if (!require('node:fs').existsSync(backupDir)) {
|
|
122
|
-
console.log("ā¹ļø No backup directory found");
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
124
|
// Get all backup files
|
|
127
|
-
const backupFiles = require('node:fs').readdirSync(backupDir)
|
|
125
|
+
const backupFiles = require('node:fs').readdirSync(platformInfo.backupDir)
|
|
128
126
|
.filter((file: string) => file.endsWith('.json'));
|
|
129
127
|
|
|
130
128
|
if (backupFiles.length === 0) {
|
|
@@ -137,7 +135,7 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
137
135
|
for (const backupFile of backupFiles) {
|
|
138
136
|
try {
|
|
139
137
|
const serviceName = backupFile.replace('.json', '');
|
|
140
|
-
const backupPath = join(backupDir, backupFile);
|
|
138
|
+
const backupPath = join(platformInfo.backupDir, backupFile);
|
|
141
139
|
const backupConfig = JSON.parse(require('node:fs').readFileSync(backupPath, 'utf8'));
|
|
142
140
|
|
|
143
141
|
// Restore service using backup configuration
|
|
@@ -161,11 +159,11 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
161
159
|
|
|
162
160
|
} else if (platformInfo.isMacOS) {
|
|
163
161
|
console.log("š To resurrect all services on macOS, you need to manually restore the plist files from:");
|
|
164
|
-
console.log(` ${
|
|
162
|
+
console.log(` ${platformInfo.backupDir}/*.plist`);
|
|
165
163
|
console.log(" And then run: launchctl load ~/Library/LaunchAgents/bs9.*.plist");
|
|
166
164
|
} else if (platformInfo.isWindows) {
|
|
167
165
|
console.log("š To resurrect all services on Windows, use PowerShell:");
|
|
168
|
-
console.log(" Get-ChildItem -Path \"${
|
|
166
|
+
console.log(" Get-ChildItem -Path \"${platformInfo.backupDir}\" | ForEach-Object { Restore-Service $_.Name }");
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
console.log(`ā
All BS9 services resurrection process completed`);
|
package/src/commands/save.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { execSync } from "node:child_process";
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
|
-
import { getPlatformInfo } from "../platform/detect.js";
|
|
14
|
+
import { getPlatformInfo, initializePlatformDirectories } from "../platform/detect.js";
|
|
15
15
|
|
|
16
16
|
interface SaveOptions {
|
|
17
17
|
all?: boolean;
|
|
@@ -28,6 +28,9 @@ function isValidServiceName(name: string): boolean {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export async function saveCommand(name: string, options: SaveOptions): Promise<void> {
|
|
31
|
+
// Initialize platform directories
|
|
32
|
+
initializePlatformDirectories();
|
|
33
|
+
|
|
31
34
|
const platformInfo = getPlatformInfo();
|
|
32
35
|
|
|
33
36
|
// Handle save all services
|
|
@@ -62,12 +65,8 @@ export async function saveCommand(name: string, options: SaveOptions): Promise<v
|
|
|
62
65
|
// Parse service configuration to extract startup parameters
|
|
63
66
|
const config = parseServiceConfig(serviceConfig, statusOutput);
|
|
64
67
|
|
|
65
|
-
// Create backup directory if it doesn't exist
|
|
66
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
67
|
-
require('node:fs').mkdirSync(backupDir, { recursive: true });
|
|
68
|
-
|
|
69
68
|
// Save configuration to backup
|
|
70
|
-
const backupFile = join(backupDir, `${escapedName}.json`);
|
|
69
|
+
const backupFile = join(platformInfo.backupDir, `${escapedName}.json`);
|
|
71
70
|
const backupData = {
|
|
72
71
|
name: name,
|
|
73
72
|
file: extractFileFromConfig(serviceConfig),
|
|
@@ -89,7 +88,7 @@ export async function saveCommand(name: string, options: SaveOptions): Promise<v
|
|
|
89
88
|
if (options.backup) {
|
|
90
89
|
// Create additional backup with timestamp
|
|
91
90
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
92
|
-
const timestampedBackup = join(backupDir, `${escapedName}-${timestamp}.json`);
|
|
91
|
+
const timestampedBackup = join(platformInfo.backupDir, `${escapedName}-${timestamp}.json`);
|
|
93
92
|
require('node:fs').writeFileSync(timestampedBackup, JSON.stringify(backupData, null, 2));
|
|
94
93
|
console.log(`š¦ Additional backup created: ${timestampedBackup}`);
|
|
95
94
|
}
|
|
@@ -118,6 +117,9 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
118
117
|
try {
|
|
119
118
|
console.log("š¾ Saving all BS9 service configurations...");
|
|
120
119
|
|
|
120
|
+
// Initialize platform directories
|
|
121
|
+
initializePlatformDirectories();
|
|
122
|
+
|
|
121
123
|
if (platformInfo.isLinux) {
|
|
122
124
|
// Get all BS9 services
|
|
123
125
|
const listOutput = execSync("systemctl --user list-units --type=service --no-pager --no-legend", { encoding: "utf-8" });
|
|
@@ -144,10 +146,6 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
144
146
|
|
|
145
147
|
console.log(`Found ${bs9Services.length} BS9 services to save...`);
|
|
146
148
|
|
|
147
|
-
// Create backup directory
|
|
148
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
149
|
-
require('node:fs').mkdirSync(backupDir, { recursive: true });
|
|
150
|
-
|
|
151
149
|
for (const serviceName of bs9Services) {
|
|
152
150
|
try {
|
|
153
151
|
const serviceFile = join(platformInfo.serviceDir, `${serviceName}.service`);
|
|
@@ -157,7 +155,7 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
157
155
|
const statusOutput = execSync(`systemctl --user show "${serviceName}"`, { encoding: "utf-8" });
|
|
158
156
|
const config = parseServiceConfig(serviceConfig, statusOutput);
|
|
159
157
|
|
|
160
|
-
const backupFile = join(backupDir, `${serviceName}.json`);
|
|
158
|
+
const backupFile = join(platformInfo.backupDir, `${serviceName}.json`);
|
|
161
159
|
const backupData = {
|
|
162
160
|
name: serviceName,
|
|
163
161
|
file: extractFileFromConfig(serviceConfig),
|
package/src/commands/status.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface ServiceStatus {
|
|
|
27
27
|
memory?: string;
|
|
28
28
|
uptime?: string;
|
|
29
29
|
tasks?: string;
|
|
30
|
+
pid?: string;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export async function statusCommand(options: StatusOptions): Promise<void> {
|
|
@@ -93,20 +94,46 @@ async function getLinuxServices(): Promise<ServiceStatus[]> {
|
|
|
93
94
|
description,
|
|
94
95
|
};
|
|
95
96
|
|
|
96
|
-
// Get additional metrics
|
|
97
|
+
// Get additional metrics with better error handling
|
|
97
98
|
try {
|
|
98
|
-
|
|
99
|
+
// Get comprehensive service information
|
|
100
|
+
const showOutput = execSync(`systemctl --user show ${name}`, { encoding: "utf-8" });
|
|
101
|
+
|
|
102
|
+
// Extract CPU usage
|
|
99
103
|
const cpuMatch = showOutput.match(/CPUUsageNSec=(\d+)/);
|
|
104
|
+
if (cpuMatch) {
|
|
105
|
+
status.cpu = formatCPU(Number(cpuMatch[1]));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Extract memory usage
|
|
100
109
|
const memMatch = showOutput.match(/MemoryCurrent=(\d+)/);
|
|
110
|
+
if (memMatch) {
|
|
111
|
+
const memoryBytes = Number(memMatch[1]);
|
|
112
|
+
status.memory = formatMemory(memoryBytes);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Extract startup time and calculate uptime
|
|
101
116
|
const timeMatch = showOutput.match(/ActiveEnterTimestamp=(.+)/);
|
|
117
|
+
if (timeMatch) {
|
|
118
|
+
status.uptime = formatUptime(timeMatch[1]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Extract task count
|
|
102
122
|
const tasksMatch = showOutput.match(/TasksCurrent=(\d+)/);
|
|
123
|
+
if (tasksMatch) {
|
|
124
|
+
status.tasks = tasksMatch[1];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get process ID for additional info
|
|
128
|
+
const pidMatch = showOutput.match(/MainPID=(\d+)/);
|
|
129
|
+
if (pidMatch && pidMatch[1] !== "0") {
|
|
130
|
+
// We could get more detailed process info here if needed
|
|
131
|
+
status.pid = pidMatch[1];
|
|
132
|
+
}
|
|
103
133
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (tasksMatch) status.tasks = tasksMatch[1];
|
|
108
|
-
} catch {
|
|
109
|
-
// Metrics might not be available
|
|
134
|
+
} catch (metricsError: any) {
|
|
135
|
+
// If metrics fail, at least we have basic status
|
|
136
|
+
console.warn(`ā ļø Could not get metrics for ${name}: ${metricsError?.message || metricsError}`);
|
|
110
137
|
}
|
|
111
138
|
|
|
112
139
|
services.push(status);
|
|
@@ -145,25 +172,84 @@ async function getWindowsServices(): Promise<ServiceStatus[]> {
|
|
|
145
172
|
}
|
|
146
173
|
|
|
147
174
|
function displayServices(services: ServiceStatus[]): void {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
175
|
+
if (services.length === 0) {
|
|
176
|
+
console.log("š No BS9 services found");
|
|
177
|
+
console.log("š” Use 'bs9 start <file>' to create a service");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Header with better formatting
|
|
182
|
+
console.log(`${"SERVICE".padEnd(18)} ${"STATUS".padEnd(15)} ${"CPU".padEnd(10)} ${"MEMORY".padEnd(12)} ${"UPTIME".padEnd(12)} ${"TASKS".padEnd(8)} DESCRIPTION`);
|
|
183
|
+
console.log("ā".repeat(100));
|
|
151
184
|
|
|
152
|
-
|
|
153
|
-
|
|
185
|
+
// Sort services by status (running first, then by name)
|
|
186
|
+
const sortedServices = services.sort((a, b) => {
|
|
187
|
+
const aRunning = a.active === "active" && a.sub === "running";
|
|
188
|
+
const bRunning = b.active === "active" && b.sub === "running";
|
|
189
|
+
if (aRunning !== bRunning) return bRunning ? 1 : -1;
|
|
190
|
+
return a.name.localeCompare(b.name);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
for (const svc of sortedServices) {
|
|
194
|
+
// Better status formatting with colors/indicators
|
|
195
|
+
let statusIndicator = "";
|
|
196
|
+
let status = `${svc.active}/${svc.sub}`;
|
|
197
|
+
|
|
198
|
+
if (svc.active === "active" && svc.sub === "running") {
|
|
199
|
+
statusIndicator = "ā
";
|
|
200
|
+
status = "running";
|
|
201
|
+
} else if (svc.active === "activating" && svc.sub.includes("auto-restart")) {
|
|
202
|
+
statusIndicator = "š";
|
|
203
|
+
status = "restarting";
|
|
204
|
+
} else if (svc.active === "failed" || svc.sub === "failed") {
|
|
205
|
+
statusIndicator = "ā";
|
|
206
|
+
status = "failed";
|
|
207
|
+
} else if (svc.active === "inactive") {
|
|
208
|
+
statusIndicator = "āøļø";
|
|
209
|
+
status = "stopped";
|
|
210
|
+
} else {
|
|
211
|
+
statusIndicator = "ā ļø";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const displayStatus = `${statusIndicator} ${status}`;
|
|
215
|
+
|
|
154
216
|
console.log(
|
|
155
|
-
`${svc.name.padEnd(
|
|
217
|
+
`${svc.name.padEnd(18)} ${displayStatus.padEnd(15)} ${(svc.cpu || "-").padEnd(10)} ${(svc.memory || "-").padEnd(12)} ${(svc.uptime || "-").padEnd(12)} ${(svc.tasks || "-").padEnd(8)} ${svc.description}`
|
|
156
218
|
);
|
|
157
219
|
}
|
|
158
220
|
|
|
159
|
-
|
|
221
|
+
// Enhanced summary
|
|
222
|
+
console.log("\nš Service Summary:");
|
|
160
223
|
const totalServices = services.length;
|
|
161
|
-
const runningServices = services.filter(s => s.active === "active").length;
|
|
224
|
+
const runningServices = services.filter(s => s.active === "active" && s.sub === "running").length;
|
|
225
|
+
const failedServices = services.filter(s => s.active === "failed" || s.sub === "failed").length;
|
|
226
|
+
const restartingServices = services.filter(s => s.active === "activating" && s.sub.includes("auto-restart")).length;
|
|
162
227
|
const totalMemory = services.reduce((sum, s) => sum + (s.memory ? parseMemory(s.memory) : 0), 0);
|
|
163
228
|
|
|
164
|
-
console.log(`
|
|
165
|
-
console.log(`
|
|
166
|
-
console.log(`
|
|
229
|
+
console.log(` š Status: ${runningServices} running, ${failedServices} failed, ${restartingServices} restarting`);
|
|
230
|
+
console.log(` š¦ Total: ${runningServices}/${totalServices} services running`);
|
|
231
|
+
console.log(` š¾ Memory: ${formatMemory(totalMemory)}`);
|
|
232
|
+
console.log(` š Last updated: ${new Date().toLocaleString()}`);
|
|
233
|
+
|
|
234
|
+
// Show failed services details
|
|
235
|
+
if (failedServices > 0) {
|
|
236
|
+
console.log("\nā Failed Services:");
|
|
237
|
+
const failed = services.filter(s => s.active === "failed" || s.sub === "failed");
|
|
238
|
+
for (const svc of failed) {
|
|
239
|
+
console.log(` ⢠${svc.name}: ${svc.active}/${svc.sub}`);
|
|
240
|
+
console.log(` š” Try: bs9 logs ${svc.name} --tail 20`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Show restarting services details
|
|
245
|
+
if (restartingServices > 0) {
|
|
246
|
+
console.log("\nš Restarting Services:");
|
|
247
|
+
const restarting = services.filter(s => s.active === "activating" && s.sub.includes("auto-restart"));
|
|
248
|
+
for (const svc of restarting) {
|
|
249
|
+
console.log(` ⢠${svc.name}: ${svc.active}/${svc.sub}`);
|
|
250
|
+
console.log(` š” Try: bs9 logs ${svc.name} --tail 20`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
167
253
|
}
|
|
168
254
|
|
|
169
255
|
function formatCPU(nsec: number): string {
|
package/src/platform/detect.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* https://github.com/xarhang/bs9
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { platform } from "node:os";
|
|
12
|
+
import { platform, homedir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
13
14
|
|
|
14
15
|
export type Platform = 'linux' | 'darwin' | 'win32';
|
|
15
16
|
|
|
@@ -22,10 +23,12 @@ export interface PlatformInfo {
|
|
|
22
23
|
configDir: string;
|
|
23
24
|
logDir: string;
|
|
24
25
|
serviceDir: string;
|
|
26
|
+
backupDir: string;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export function getPlatformInfo(): PlatformInfo {
|
|
28
30
|
const currentPlatform = platform() as Platform;
|
|
31
|
+
const userHome = homedir();
|
|
29
32
|
|
|
30
33
|
const baseInfo: PlatformInfo = {
|
|
31
34
|
platform: currentPlatform,
|
|
@@ -35,29 +38,33 @@ export function getPlatformInfo(): PlatformInfo {
|
|
|
35
38
|
serviceManager: 'systemd',
|
|
36
39
|
configDir: '',
|
|
37
40
|
logDir: '',
|
|
38
|
-
serviceDir: ''
|
|
41
|
+
serviceDir: '',
|
|
42
|
+
backupDir: ''
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
switch (currentPlatform) {
|
|
42
46
|
case 'linux':
|
|
43
47
|
baseInfo.serviceManager = 'systemd';
|
|
44
|
-
baseInfo.configDir =
|
|
45
|
-
baseInfo.logDir =
|
|
46
|
-
baseInfo.serviceDir =
|
|
48
|
+
baseInfo.configDir = join(userHome, '.config', 'bs9');
|
|
49
|
+
baseInfo.logDir = join(userHome, '.local', 'share', 'bs9', 'logs');
|
|
50
|
+
baseInfo.serviceDir = join(userHome, '.config', 'systemd', 'user');
|
|
51
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
47
52
|
break;
|
|
48
53
|
|
|
49
54
|
case 'darwin':
|
|
50
55
|
baseInfo.serviceManager = 'launchd';
|
|
51
|
-
baseInfo.configDir =
|
|
52
|
-
baseInfo.logDir =
|
|
53
|
-
baseInfo.serviceDir =
|
|
56
|
+
baseInfo.configDir = join(userHome, '.bs9');
|
|
57
|
+
baseInfo.logDir = join(userHome, '.bs9', 'logs');
|
|
58
|
+
baseInfo.serviceDir = join(userHome, 'Library', 'LaunchAgents');
|
|
59
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
54
60
|
break;
|
|
55
61
|
|
|
56
62
|
case 'win32':
|
|
57
63
|
baseInfo.serviceManager = 'windows-service';
|
|
58
|
-
baseInfo.configDir =
|
|
59
|
-
baseInfo.logDir =
|
|
60
|
-
baseInfo.serviceDir =
|
|
64
|
+
baseInfo.configDir = join(userHome, '.bs9');
|
|
65
|
+
baseInfo.logDir = join(userHome, '.bs9', 'logs');
|
|
66
|
+
baseInfo.serviceDir = join(userHome, '.bs9', 'services');
|
|
67
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
61
68
|
break;
|
|
62
69
|
|
|
63
70
|
default:
|
|
@@ -77,13 +84,13 @@ export function getPlatformSpecificCommands(): string[] {
|
|
|
77
84
|
|
|
78
85
|
switch (currentPlatform) {
|
|
79
86
|
case 'linux':
|
|
80
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool'];
|
|
87
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool'];
|
|
81
88
|
|
|
82
89
|
case 'darwin':
|
|
83
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'macos'];
|
|
90
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool', 'macos'];
|
|
84
91
|
|
|
85
92
|
case 'win32':
|
|
86
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'windows'];
|
|
93
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool', 'windows'];
|
|
87
94
|
|
|
88
95
|
default:
|
|
89
96
|
return [];
|
|
@@ -144,3 +151,19 @@ Windows-specific:
|
|
|
144
151
|
return `ā Platform ${currentPlatform} is not supported`;
|
|
145
152
|
}
|
|
146
153
|
}
|
|
154
|
+
|
|
155
|
+
// Auto-detect and initialize platform-specific directories
|
|
156
|
+
export function initializePlatformDirectories(): void {
|
|
157
|
+
const platformInfo = getPlatformInfo();
|
|
158
|
+
|
|
159
|
+
// Create directories if they don't exist
|
|
160
|
+
const fs = require('node:fs');
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
fs.mkdirSync(platformInfo.configDir, { recursive: true });
|
|
164
|
+
fs.mkdirSync(platformInfo.logDir, { recursive: true });
|
|
165
|
+
fs.mkdirSync(platformInfo.backupDir, { recursive: true });
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.warn(`ā ļø Warning: Could not create platform directories: ${error}`);
|
|
168
|
+
}
|
|
169
|
+
}
|