bs9 1.0.0 → 1.3.0
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 +105 -9
- package/bin/bs9 +91 -7
- package/dist/bs9-064xs9r9. +148 -0
- package/dist/bs9-0gqcrp5t. +144 -0
- package/dist/bs9-33vcpmb9. +181 -0
- package/dist/bs9-nv7nseny. +197 -0
- package/dist/bs9-r6b9zpw0. +156 -0
- package/dist/bs9.js +2 -0
- package/package.json +3 -4
- package/src/commands/deps.ts +295 -0
- package/src/commands/profile.ts +338 -0
- package/src/commands/restart.ts +28 -3
- package/src/commands/start.ts +201 -21
- package/src/commands/status.ts +154 -109
- package/src/commands/stop.ts +31 -3
- package/src/commands/update.ts +322 -0
- package/src/commands/web.ts +29 -3
- package/src/database/pool.ts +335 -0
- package/src/discovery/consul.ts +285 -0
- package/src/loadbalancer/manager.ts +481 -0
- package/src/macos/launchd.ts +402 -0
- package/src/monitoring/advanced.ts +341 -0
- package/src/platform/detect.ts +137 -0
- package/src/windows/service.ts +391 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { serve } from "bun";
|
|
4
|
+
import { randomBytes } from "node:crypto";
|
|
5
|
+
|
|
6
|
+
interface AdvancedWidget {
|
|
7
|
+
id: string;
|
|
8
|
+
type: 'metric' | 'chart' | 'alert' | 'custom';
|
|
9
|
+
title: string;
|
|
10
|
+
config: Record<string, any>;
|
|
11
|
+
position: { x: number; y: number; width: number; height: number };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface AnomalyDetection {
|
|
15
|
+
service: string;
|
|
16
|
+
metric: string;
|
|
17
|
+
baseline: number;
|
|
18
|
+
threshold: number;
|
|
19
|
+
detected: boolean;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface AlertCorrelation {
|
|
24
|
+
id: string;
|
|
25
|
+
alerts: Array<{
|
|
26
|
+
service: string;
|
|
27
|
+
type: string;
|
|
28
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}>;
|
|
31
|
+
correlation: number;
|
|
32
|
+
rootCause?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class AdvancedMonitoring {
|
|
36
|
+
private widgets: Map<string, AdvancedWidget> = new Map();
|
|
37
|
+
private anomalies: Map<string, AnomalyDetection> = new Map();
|
|
38
|
+
private correlations: Map<string, AlertCorrelation> = new Map();
|
|
39
|
+
private baselines: Map<string, number> = new Map();
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
this.initializeDefaultWidgets();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private initializeDefaultWidgets(): void {
|
|
46
|
+
// CPU Usage Widget
|
|
47
|
+
this.widgets.set('cpu-usage', {
|
|
48
|
+
id: 'cpu-usage',
|
|
49
|
+
type: 'metric',
|
|
50
|
+
title: 'CPU Usage',
|
|
51
|
+
config: {
|
|
52
|
+
metric: 'cpu',
|
|
53
|
+
unit: '%',
|
|
54
|
+
threshold: 80,
|
|
55
|
+
refreshInterval: 5000
|
|
56
|
+
},
|
|
57
|
+
position: { x: 0, y: 0, width: 300, height: 200 }
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Memory Usage Widget
|
|
61
|
+
this.widgets.set('memory-usage', {
|
|
62
|
+
id: 'memory-usage',
|
|
63
|
+
type: 'metric',
|
|
64
|
+
title: 'Memory Usage',
|
|
65
|
+
config: {
|
|
66
|
+
metric: 'memory',
|
|
67
|
+
unit: 'MB',
|
|
68
|
+
threshold: 90,
|
|
69
|
+
refreshInterval: 5000
|
|
70
|
+
},
|
|
71
|
+
position: { x: 320, y: 0, width: 300, height: 200 }
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Service Health Chart
|
|
75
|
+
this.widgets.set('service-health', {
|
|
76
|
+
id: 'service-health',
|
|
77
|
+
type: 'chart',
|
|
78
|
+
title: 'Service Health',
|
|
79
|
+
config: {
|
|
80
|
+
chartType: 'line',
|
|
81
|
+
timeRange: '1h',
|
|
82
|
+
metrics: ['cpu', 'memory', 'response_time'],
|
|
83
|
+
refreshInterval: 10000
|
|
84
|
+
},
|
|
85
|
+
position: { x: 0, y: 220, width: 620, height: 300 }
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Alert Status Widget
|
|
89
|
+
this.widgets.set('alert-status', {
|
|
90
|
+
id: 'alert-status',
|
|
91
|
+
type: 'alert',
|
|
92
|
+
title: 'Active Alerts',
|
|
93
|
+
config: {
|
|
94
|
+
severity: ['high', 'critical'],
|
|
95
|
+
refreshInterval: 3000
|
|
96
|
+
},
|
|
97
|
+
position: { x: 640, y: 0, width: 300, height: 200 }
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
addWidget(widget: AdvancedWidget): void {
|
|
102
|
+
this.widgets.set(widget.id, widget);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
removeWidget(widgetId: string): void {
|
|
106
|
+
this.widgets.delete(widgetId);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
updateWidget(widgetId: string, updates: Partial<AdvancedWidget>): void {
|
|
110
|
+
const widget = this.widgets.get(widgetId);
|
|
111
|
+
if (widget) {
|
|
112
|
+
Object.assign(widget, updates);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
getWidgets(): AdvancedWidget[] {
|
|
117
|
+
return Array.from(this.widgets.values());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async detectAnomalies(serviceMetrics: Record<string, any>): Promise<AnomalyDetection[]> {
|
|
121
|
+
const anomalies: AnomalyDetection[] = [];
|
|
122
|
+
|
|
123
|
+
for (const [serviceName, metrics] of Object.entries(serviceMetrics)) {
|
|
124
|
+
for (const [metricName, value] of Object.entries(metrics)) {
|
|
125
|
+
const key = `${serviceName}-${metricName}`;
|
|
126
|
+
const baseline = this.baselines.get(key) || 0;
|
|
127
|
+
|
|
128
|
+
// Simple anomaly detection using statistical deviation
|
|
129
|
+
const deviation = Math.abs((value as number) - baseline) / baseline;
|
|
130
|
+
const threshold = 0.3; // 30% deviation threshold
|
|
131
|
+
|
|
132
|
+
if (deviation > threshold) {
|
|
133
|
+
const anomaly: AnomalyDetection = {
|
|
134
|
+
service: serviceName,
|
|
135
|
+
metric: metricName,
|
|
136
|
+
baseline,
|
|
137
|
+
threshold: baseline * (1 + threshold),
|
|
138
|
+
detected: true,
|
|
139
|
+
timestamp: Date.now()
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
anomalies.push(anomaly);
|
|
143
|
+
this.anomalies.set(key, anomaly);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return anomalies;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async correlateAlerts(alerts: Array<any>): Promise<AlertCorrelation[]> {
|
|
152
|
+
const correlations: AlertCorrelation[] = [];
|
|
153
|
+
|
|
154
|
+
// Simple correlation based on time proximity and service relationships
|
|
155
|
+
for (let i = 0; i < alerts.length; i++) {
|
|
156
|
+
for (let j = i + 1; j < alerts.length; j++) {
|
|
157
|
+
const alert1 = alerts[i];
|
|
158
|
+
const alert2 = alerts[j];
|
|
159
|
+
|
|
160
|
+
const timeDiff = Math.abs(alert1.timestamp - alert2.timestamp);
|
|
161
|
+
const timeThreshold = 60000; // 1 minute
|
|
162
|
+
|
|
163
|
+
if (timeDiff < timeThreshold) {
|
|
164
|
+
const correlation: AlertCorrelation = {
|
|
165
|
+
id: randomBytes(8).toString('hex'),
|
|
166
|
+
alerts: [alert1, alert2],
|
|
167
|
+
correlation: 1 - (timeDiff / timeThreshold)
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
correlations.push(correlation);
|
|
171
|
+
this.correlations.set(correlation.id, correlation);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return correlations;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
updateBaseline(service: string, metric: string, value: number): void {
|
|
180
|
+
const key = `${service}-${metric}`;
|
|
181
|
+
const currentBaseline = this.baselines.get(key) || 0;
|
|
182
|
+
|
|
183
|
+
// Exponential moving average for baseline
|
|
184
|
+
const alpha = 0.1;
|
|
185
|
+
const newBaseline = alpha * (value as number) + (1 - alpha) * currentBaseline;
|
|
186
|
+
|
|
187
|
+
this.baselines.set(key, newBaseline);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getAnomalies(): AnomalyDetection[] {
|
|
191
|
+
return Array.from(this.anomalies.values());
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
getCorrelations(): AlertCorrelation[] {
|
|
195
|
+
return Array.from(this.correlations.values());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
generateDashboard(): string {
|
|
199
|
+
const widgets = this.getWidgets();
|
|
200
|
+
|
|
201
|
+
return `
|
|
202
|
+
<!DOCTYPE html>
|
|
203
|
+
<html lang="en">
|
|
204
|
+
<head>
|
|
205
|
+
<meta charset="UTF-8">
|
|
206
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
207
|
+
<title>BS9 Advanced Monitoring Dashboard</title>
|
|
208
|
+
<style>
|
|
209
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
|
|
210
|
+
.dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; max-width: 1400px; margin: 0 auto; }
|
|
211
|
+
.widget { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
212
|
+
.widget-header { font-size: 18px; font-weight: 600; margin-bottom: 15px; color: #333; }
|
|
213
|
+
.widget-content { min-height: 150px; }
|
|
214
|
+
.metric-value { font-size: 36px; font-weight: bold; color: #007bff; }
|
|
215
|
+
.metric-unit { font-size: 14px; color: #666; margin-left: 5px; }
|
|
216
|
+
.alert-item { padding: 10px; margin: 5px 0; border-left: 4px solid #dc3545; background: #f8d7da; }
|
|
217
|
+
.anomaly-item { padding: 10px; margin: 5px 0; border-left: 4px solid #ffc107; background: #fff3cd; }
|
|
218
|
+
.chart-container { height: 200px; background: #f8f9fa; border-radius: 4px; display: flex; align-items: center; justify-content: center; }
|
|
219
|
+
</style>
|
|
220
|
+
</head>
|
|
221
|
+
<body>
|
|
222
|
+
<h1>🔍 BS9 Advanced Monitoring Dashboard</h1>
|
|
223
|
+
|
|
224
|
+
<div class="dashboard">
|
|
225
|
+
${widgets.map(widget => this.renderWidget(widget)).join('')}
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
<script>
|
|
229
|
+
// Auto-refresh widgets
|
|
230
|
+
setInterval(() => {
|
|
231
|
+
fetch('/api/advanced-metrics')
|
|
232
|
+
.then(response => response.json())
|
|
233
|
+
.then(data => {
|
|
234
|
+
updateWidgets(data);
|
|
235
|
+
})
|
|
236
|
+
.catch(error => console.error('Failed to fetch metrics:', error));
|
|
237
|
+
}, 5000);
|
|
238
|
+
|
|
239
|
+
function updateWidgets(data) {
|
|
240
|
+
// Update widget content based on data
|
|
241
|
+
console.log('Updating widgets with data:', data);
|
|
242
|
+
}
|
|
243
|
+
</script>
|
|
244
|
+
</body>
|
|
245
|
+
</html>`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private renderWidget(widget: AdvancedWidget): string {
|
|
249
|
+
switch (widget.type) {
|
|
250
|
+
case 'metric':
|
|
251
|
+
return `
|
|
252
|
+
<div class="widget" style="grid-column: span ${Math.ceil(widget.position.width / 300)};">
|
|
253
|
+
<div class="widget-header">${widget.title}</div>
|
|
254
|
+
<div class="widget-content">
|
|
255
|
+
<div class="metric-value" id="${widget.id}-value">${typeof widget.config.value === 'number' ? widget.config.value : '--'}</div>
|
|
256
|
+
<span class="metric-unit">${widget.config.unit}</span>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
`;
|
|
260
|
+
|
|
261
|
+
case 'chart':
|
|
262
|
+
return `
|
|
263
|
+
<div class="widget" style="grid-column: span ${Math.ceil(widget.position.width / 300)};">
|
|
264
|
+
<div class="widget-header">${widget.title}</div>
|
|
265
|
+
<div class="widget-content">
|
|
266
|
+
<div class="chart-container">
|
|
267
|
+
📊 ${widget.config.chartType.toUpperCase()} Chart
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
`;
|
|
272
|
+
|
|
273
|
+
case 'alert':
|
|
274
|
+
return `
|
|
275
|
+
<div class="widget" style="grid-column: span ${Math.ceil(widget.position.width / 300)};">
|
|
276
|
+
<div class="widget-header">${widget.title}</div>
|
|
277
|
+
<div class="widget-content" id="${widget.id}-alerts">
|
|
278
|
+
<div class="alert-item">No active alerts</div>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
`;
|
|
282
|
+
|
|
283
|
+
default:
|
|
284
|
+
return `
|
|
285
|
+
<div class="widget">
|
|
286
|
+
<div class="widget-header">${widget.title}</div>
|
|
287
|
+
<div class="widget-content">
|
|
288
|
+
Custom widget content
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export async function advancedMonitoringCommand(options: any): Promise<void> {
|
|
297
|
+
const monitoring = new AdvancedMonitoring();
|
|
298
|
+
|
|
299
|
+
console.log('🔍 Starting Advanced Monitoring Dashboard...');
|
|
300
|
+
console.log('📊 Features:');
|
|
301
|
+
console.log(' - Custom widgets');
|
|
302
|
+
console.log(' - Anomaly detection');
|
|
303
|
+
console.log(' - Alert correlation');
|
|
304
|
+
console.log(' - Performance baselines');
|
|
305
|
+
|
|
306
|
+
const server = serve({
|
|
307
|
+
port: options.port || 8090,
|
|
308
|
+
async fetch(req) {
|
|
309
|
+
const url = new URL(req.url);
|
|
310
|
+
|
|
311
|
+
if (url.pathname === '/') {
|
|
312
|
+
return new Response(monitoring.generateDashboard(), {
|
|
313
|
+
headers: { 'Content-Type': 'text/html' }
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (url.pathname === '/api/advanced-metrics') {
|
|
318
|
+
// Mock advanced metrics data
|
|
319
|
+
const metrics = {
|
|
320
|
+
widgets: monitoring.getWidgets(),
|
|
321
|
+
anomalies: monitoring.getAnomalies(),
|
|
322
|
+
correlations: monitoring.getCorrelations(),
|
|
323
|
+
timestamp: Date.now()
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
return new Response(JSON.stringify(metrics), {
|
|
327
|
+
headers: { 'Content-Type': 'application/json' }
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return new Response('Not Found', { status: 404 });
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
console.log(`✅ Advanced monitoring dashboard started on http://localhost:${options.port || 8090}`);
|
|
336
|
+
console.log('🔗 Features available:');
|
|
337
|
+
console.log(' - Real-time anomaly detection');
|
|
338
|
+
console.log(' - Alert correlation analysis');
|
|
339
|
+
console.log(' - Custom widget configuration');
|
|
340
|
+
console.log(' - Performance baseline tracking');
|
|
341
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { platform } from "node:os";
|
|
4
|
+
|
|
5
|
+
export type Platform = 'linux' | 'darwin' | 'win32';
|
|
6
|
+
|
|
7
|
+
export interface PlatformInfo {
|
|
8
|
+
platform: Platform;
|
|
9
|
+
isLinux: boolean;
|
|
10
|
+
isMacOS: boolean;
|
|
11
|
+
isWindows: boolean;
|
|
12
|
+
serviceManager: 'systemd' | 'launchd' | 'windows-service';
|
|
13
|
+
configDir: string;
|
|
14
|
+
logDir: string;
|
|
15
|
+
serviceDir: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getPlatformInfo(): PlatformInfo {
|
|
19
|
+
const currentPlatform = platform() as Platform;
|
|
20
|
+
|
|
21
|
+
const baseInfo: PlatformInfo = {
|
|
22
|
+
platform: currentPlatform,
|
|
23
|
+
isLinux: currentPlatform === 'linux',
|
|
24
|
+
isMacOS: currentPlatform === 'darwin',
|
|
25
|
+
isWindows: currentPlatform === 'win32',
|
|
26
|
+
serviceManager: 'systemd',
|
|
27
|
+
configDir: '',
|
|
28
|
+
logDir: '',
|
|
29
|
+
serviceDir: ''
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
switch (currentPlatform) {
|
|
33
|
+
case 'linux':
|
|
34
|
+
baseInfo.serviceManager = 'systemd';
|
|
35
|
+
baseInfo.configDir = `${process.env.HOME}/.config/bs9`;
|
|
36
|
+
baseInfo.logDir = `${process.env.HOME}/.local/share/bs9/logs`;
|
|
37
|
+
baseInfo.serviceDir = `${process.env.HOME}/.config/systemd/user`;
|
|
38
|
+
break;
|
|
39
|
+
|
|
40
|
+
case 'darwin':
|
|
41
|
+
baseInfo.serviceManager = 'launchd';
|
|
42
|
+
baseInfo.configDir = `${process.env.HOME}/.bs9`;
|
|
43
|
+
baseInfo.logDir = `${process.env.HOME}/.bs9/logs`;
|
|
44
|
+
baseInfo.serviceDir = `${process.env.HOME}/Library/LaunchAgents`;
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
case 'win32':
|
|
48
|
+
baseInfo.serviceManager = 'windows-service';
|
|
49
|
+
baseInfo.configDir = `${process.env.USERPROFILE}/.bs9`;
|
|
50
|
+
baseInfo.logDir = `${process.env.USERPROFILE}/.bs9/logs`;
|
|
51
|
+
baseInfo.serviceDir = `${process.env.USERPROFILE}/.bs9/services`;
|
|
52
|
+
break;
|
|
53
|
+
|
|
54
|
+
default:
|
|
55
|
+
throw new Error(`Unsupported platform: ${currentPlatform}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return baseInfo;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function isSupportedPlatform(): boolean {
|
|
62
|
+
const supportedPlatforms: Platform[] = ['linux', 'darwin', 'win32'];
|
|
63
|
+
return supportedPlatforms.includes(platform() as Platform);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getPlatformSpecificCommands(): string[] {
|
|
67
|
+
const currentPlatform = platform() as Platform;
|
|
68
|
+
|
|
69
|
+
switch (currentPlatform) {
|
|
70
|
+
case 'linux':
|
|
71
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool'];
|
|
72
|
+
|
|
73
|
+
case 'darwin':
|
|
74
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'macos'];
|
|
75
|
+
|
|
76
|
+
case 'win32':
|
|
77
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'windows'];
|
|
78
|
+
|
|
79
|
+
default:
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function getPlatformHelp(): string {
|
|
85
|
+
const currentPlatform = platform() as Platform;
|
|
86
|
+
|
|
87
|
+
switch (currentPlatform) {
|
|
88
|
+
case 'linux':
|
|
89
|
+
return `
|
|
90
|
+
🐧 Linux Platform Features:
|
|
91
|
+
• Systemd-based service management
|
|
92
|
+
• User-mode service execution
|
|
93
|
+
• Advanced security hardening
|
|
94
|
+
• Resource limits and sandboxing
|
|
95
|
+
|
|
96
|
+
Available Commands:
|
|
97
|
+
${getPlatformSpecificCommands().join(', ')}
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
case 'darwin':
|
|
101
|
+
return `
|
|
102
|
+
🍎 macOS Platform Features:
|
|
103
|
+
• Launchd service management
|
|
104
|
+
• Native macOS integration
|
|
105
|
+
• Automatic service recovery
|
|
106
|
+
• Standard macOS logging
|
|
107
|
+
|
|
108
|
+
Available Commands:
|
|
109
|
+
${getPlatformSpecificCommands().join(', ')}
|
|
110
|
+
|
|
111
|
+
macOS-specific:
|
|
112
|
+
• bs9 macos create - Create launchd service
|
|
113
|
+
• bs9 macos start - Start launchd service
|
|
114
|
+
• bs9 macos stop - Stop launchd service
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
case 'win32':
|
|
118
|
+
return `
|
|
119
|
+
🪟 Windows Platform Features:
|
|
120
|
+
• Windows service management
|
|
121
|
+
• PowerShell-based automation
|
|
122
|
+
• Event log integration
|
|
123
|
+
• Service recovery policies
|
|
124
|
+
|
|
125
|
+
Available Commands:
|
|
126
|
+
${getPlatformSpecificCommands().join(', ')}
|
|
127
|
+
|
|
128
|
+
Windows-specific:
|
|
129
|
+
• bs9 windows create - Create Windows service
|
|
130
|
+
• bs9 windows start - Start Windows service
|
|
131
|
+
• bs9 windows stop - Stop Windows service
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
default:
|
|
135
|
+
return `❌ Platform ${currentPlatform} is not supported`;
|
|
136
|
+
}
|
|
137
|
+
}
|