bs9 1.4.3 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # BS9 (Bun Sentinel 9) 🚀
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
- [![Version](https://img.shields.io/badge/version-1.4.3-blue.svg)](https://github.com/xarhang/bs9)
4
+ [![Version](https://img.shields.io/badge/version-1.5.0-blue.svg)](https://github.com/xarhang/bs9)
5
5
  [![Security](https://img.shields.io/badge/security-Enterprise-green.svg)](SECURITY.md)
6
6
  [![Production Ready](https://img.shields.io/badge/production-Ready-brightgreen.svg)](PRODUCTION.md)
7
7
  [![Cross-Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey.svg)](https://github.com/bs9/bs9)
@@ -40,20 +40,20 @@ chmod +x ~/.local/bin/bs9
40
40
  #### 🍎 macOS
41
41
  - **Service Manager**: Launchd
42
42
  - **Features**: Native macOS integration, automatic recovery
43
- - **Commands**: All commands + `bs9 macos` for launchd management
43
+ - **Commands**: All commands work automatically on macOS
44
44
 
45
45
  #### 🪟 Windows
46
46
  - **Service Manager**: Windows Services
47
47
  - **Features**: PowerShell automation, event log integration
48
- - **Commands**: All commands + `bs9 windows` for service management
48
+ - **Commands**: All commands work automatically on Windows
49
49
 
50
50
  ```bash
51
- # Check your platform
52
- bs9 platform
51
+ # Check your platform (auto-detected)
52
+ bs9 --help # Shows platform info in help
53
53
 
54
- # Platform-specific service management
55
- bs9 macos create --name my-app --file app.js # macOS
56
- bs9 windows create --name my-app --file app.js # Windows
54
+ # Platform-specific service management (auto-detected)
55
+ bs9 start app.js # Works on Linux, macOS, Windows
56
+ bs9 deploy app.js # Works on all platforms
57
57
  ```
58
58
 
59
59
  ### 🚀 Killer Feature: Zero-Config Deployment
@@ -91,6 +91,22 @@ bs9 start app.js --host 0.0.0.0 --port 8080 # Custom host and port
91
91
  bs9 start app.js --host 192.168.1.100 --https # Custom host with HTTPS
92
92
  bs9 start app.ts --build --name myapp --port 8080 --env NODE_ENV=production --host 0.0.0.0 --https
93
93
 
94
+ # 🆕 Multi-Service Management (NEW!)
95
+ bs9 start [app1, app2, app3] # Start multiple services
96
+ bs9 start [app-*] # Start services matching pattern
97
+ bs9 start all # Start all services
98
+ bs9 stop [app1, app2] # Stop multiple services
99
+ bs9 stop [web-*] # Stop services matching pattern
100
+ bs9 stop all # Stop all services (with confirmation)
101
+ bs9 restart [app1, app2, app3] # Restart multiple services
102
+ bs9 restart [*-prod] # Restart services matching pattern
103
+ bs9 restart all # Restart all services (with confirmation)
104
+ bs9 delete [test-*] # Delete services matching pattern
105
+ bs9 delete all # Delete all services (with confirmation)
106
+ bs9 status [app1, app2, app3] # Status of multiple services
107
+ bs9 status [web-*] # Status of services matching pattern
108
+ bs9 status all # Status of all services
109
+
94
110
  # Stop service
95
111
  bs9 stop myapp
96
112
 
@@ -599,11 +615,23 @@ BS9/
599
615
 
600
616
  ## 🚀 Production Deployment
601
617
 
602
- ### System Requirements
603
- - **OS**: Linux (systemd user mode)
604
- - **Runtime**: Bun 1.3.6+
605
- - **Memory**: 512MB minimum per service
606
- - **Disk**: 1GB for metrics storage
618
+ ### System Requirements & Health Check
619
+ ```bash
620
+ # Check BS9 installation and system compatibility
621
+ bs9 doctor # Basic health check
622
+ bs9 doctor --verbose # Detailed system information
623
+ bs9 doctor --check platform # Check platform-specific setup
624
+ bs9 -V # Show BS9 version
625
+
626
+ # System inspection
627
+ bs9 inspect # Basic inspection
628
+ bs9 inspect --full # Complete system inspection
629
+ bs9 inspect --security # Security inspection only
630
+ bs9 inspect --performance # Performance inspection only
631
+ bs9 inspect --configuration # Configuration inspection only
632
+ bs9 inspect --compliance # Compliance inspection only
633
+ bs9 inspect --report json # Export inspection report
634
+ ```
607
635
 
608
636
  ### Installation
609
637
  #### One-Click Install (Recommended)
package/bin/bs9 CHANGED
@@ -31,6 +31,8 @@ import { updateCommand } from "../src/commands/update.js";
31
31
  import { dbpoolCommand } from "../src/database/pool.js";
32
32
  import { advancedMonitoringCommand } from "../src/monitoring/advanced.js";
33
33
  import { consulCommand } from "../src/discovery/consul.js";
34
+ import { doctorCommand } from "../src/commands/doctor.js";
35
+ import { inspectCommand } from "../src/commands/inspect.js";
34
36
 
35
37
  const program = new Command();
36
38
 
@@ -41,8 +43,8 @@ program
41
43
 
42
44
  program
43
45
  .command("start")
44
- .description("Start a process with hardened systemd unit")
45
- .argument("<file>", "Application file to start")
46
+ .description("Start one or more services")
47
+ .argument("[file...]", "Application file, service name, array [app1,app2], pattern [app-*], or [all]")
46
48
  .option("-n, --name <name>", "Service name")
47
49
  .option("-p, --port <port>", "Port number", "3000")
48
50
  .option("-h, --host <host>", "Host address", "localhost")
@@ -55,19 +57,20 @@ program
55
57
 
56
58
  program
57
59
  .command("stop")
58
- .description("Stop a managed service")
59
- .argument("<name>", "Service name")
60
+ .description("Stop one or more services")
61
+ .argument("[name...]", "Service name, array [app1,app2], pattern [app-*], or [all]")
60
62
  .action(stopCommand);
61
63
 
62
64
  program
63
65
  .command("restart")
64
- .description("Restart a managed service")
65
- .argument("<name>", "Service name")
66
+ .description("Restart one or more services")
67
+ .argument("[name...]", "Service name, array [app1,app2], pattern [app-*], or [all]")
66
68
  .action(restartCommand);
67
69
 
68
70
  program
69
71
  .command("status")
70
- .description("Show status and SRE metrics for all services")
72
+ .description("Show status and SRE metrics for services")
73
+ .argument("[name...]", "Service name, array [app1,app2], pattern [app-*], or [all]")
71
74
  .option("-w, --watch", "Watch mode (refresh every 2s)")
72
75
  .action(statusCommand);
73
76
 
@@ -136,10 +139,10 @@ program
136
139
 
137
140
  program
138
141
  .command("delete")
139
- .description("Delete managed services")
140
- .argument("[name]", "Service name (optional)")
142
+ .description("Delete one or more managed services")
143
+ .argument("[name...]", "Service name, array [app1,app2], pattern [test-*], or [all]")
141
144
  .option("-a, --all", "Delete all services")
142
- .option("-f, --force", "Force deletion without errors")
145
+ .option("-f, --force", "Force deletion without confirmation")
143
146
  .option("-r, --remove", "Remove service configuration files")
144
147
  .option("-t, --timeout <seconds>", "Timeout for graceful shutdown (default: 30)")
145
148
  .action(deleteCommand);
@@ -244,4 +247,24 @@ program
244
247
  .option("--service <service>", "Service name for discovery")
245
248
  .action(consulCommand);
246
249
 
250
+ program
251
+ .command("doctor")
252
+ .description("Perform comprehensive health check")
253
+ .option("--check <type>", "Specific check to run (dependencies|configuration|platform)")
254
+ .option("-v, --verbose", "Verbose output with system information")
255
+ .action(doctorCommand);
256
+
257
+ program
258
+ .command("inspect")
259
+ .description("Comprehensive system inspection and analysis")
260
+ .option("--security", "Security inspection only")
261
+ .option("--performance", "Performance inspection only")
262
+ .option("--configuration", "Configuration inspection only")
263
+ .option("--compliance", "Compliance inspection only")
264
+ .option("--full", "Complete system inspection")
265
+ .option("--report <format>", "Export report (json|csv)")
266
+ .option("--deep", "Deep system analysis")
267
+ .option("-v, --verbose", "Verbose output with detailed analysis")
268
+ .action(inspectCommand);
269
+
247
270
  program.parse();
@@ -0,0 +1,389 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { readFileSync } from "node:fs";
5
+ import { join, dirname } from "node:path";
6
+
7
+ // Read version from package.json
8
+ const packageJsonPath = join(dirname(import.meta.path), '..', 'package.json');
9
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
10
+ const version = packageJson.version;
11
+
12
+ import { startCommand } from "../src/commands/start.js";
13
+ import { stopCommand } from "../src/commands/stop.js";
14
+ import { restartCommand } from "../src/commands/restart.js";
15
+ import { statusCommand } from "../src/commands/status.js";
16
+ import { logsCommand } from "../src/commands/logs.js";
17
+ import { monitCommand } from "../src/commands/monit.js";
18
+ import { webCommand } from "../src/commands/web.js";
19
+ import { alertCommand } from "../src/commands/alert.js";
20
+ import { exportCommand } from "../src/commands/export.js";
21
+ import { depsCommand } from "../src/commands/deps.js";
22
+ import { profileCommand } from "../src/commands/profile.js";
23
+ import { deleteCommand } from "../src/commands/delete.js";
24
+ import { saveCommand } from "../src/commands/save.js";
25
+ import { resurrectCommand } from "../src/commands/resurrect.js";
26
+ import { deployCommand } from "../src/commands/deploy.js";
27
+ import { loadbalancerCommand } from "../src/loadbalancer/manager.js";
28
+ import { windowsCommand } from "../src/windows/service.js";
29
+ import { launchdCommand } from "../src/macos/launchd.js";
30
+ import { updateCommand } from "../src/commands/update.js";
31
+ import { dbpoolCommand } from "../src/database/pool.js";
32
+ import { advancedMonitoringCommand } from "../src/monitoring/advanced.js";
33
+ import { consulCommand } from "../src/discovery/consul.js";
34
+ import { doctorCommand } from "../src/commands/doctor.js";
35
+ import { inspectCommand } from "../src/commands/inspect.js";
36
+ import { startAllServices, stopAllServices, restartAllServices, deleteAllServices, listServices } from "../src/commands/services.js";
37
+ import { createAlert, listAlerts, toggleAlert, deleteAlert, testAlert, monitorAlerts, setGlobalConfig } from "../src/commands/custom-alerts.js";
38
+
39
+ const program = new Command();
40
+
41
+ program
42
+ .name("bs9")
43
+ .description("BS9 (Bun Sentinel 9) — Mission-critical process manager CLI")
44
+ .version(version);
45
+
46
+ program
47
+ .command("start")
48
+ .description("Start a process with hardened systemd unit")
49
+ .argument("<file>", "Application file to start")
50
+ .option("-n, --name <name>", "Service name")
51
+ .option("-p, --port <port>", "Port number", "3000")
52
+ .option("-h, --host <host>", "Host address", "localhost")
53
+ .option("--https", "Use HTTPS protocol")
54
+ .option("-e, --env <env>", "Environment variables (can be used multiple times)", (value, previous) => [...(previous || []), value])
55
+ .option("--otel", "Enable OpenTelemetry instrumentation", true)
56
+ .option("--prometheus", "Enable Prometheus metrics", true)
57
+ .option("--build", "Build TypeScript to JavaScript before starting")
58
+ .action(startCommand);
59
+
60
+ program
61
+ .command("stop")
62
+ .description("Stop a managed service")
63
+ .argument("<name>", "Service name")
64
+ .action(stopCommand);
65
+
66
+ program
67
+ .command("restart")
68
+ .description("Restart a managed service")
69
+ .argument("<name>", "Service name")
70
+ .action(restartCommand);
71
+
72
+ program
73
+ .command("status")
74
+ .description("Show status and SRE metrics for all services")
75
+ .option("-w, --watch", "Watch mode (refresh every 2s)")
76
+ .action(statusCommand);
77
+
78
+ program
79
+ .command("logs")
80
+ .description("Show logs for a service (via journalctl)")
81
+ .argument("<name>", "Service name")
82
+ .option("-f, --follow", "Follow logs")
83
+ .option("-n, --lines <number>", "Number of lines", "50")
84
+ .action(logsCommand);
85
+
86
+ program
87
+ .command("monit")
88
+ .description("Real-time terminal dashboard for all services")
89
+ .option("-r, --refresh <seconds>", "Refresh interval in seconds", "2")
90
+ .action(monitCommand);
91
+
92
+ program
93
+ .command("web")
94
+ .description("Start web-based monitoring dashboard")
95
+ .option("-p, --port <port>", "Port for web dashboard", "8080")
96
+ .option("-d, --detach", "Run in background")
97
+ .action(webCommand);
98
+
99
+ program
100
+ .command("alert")
101
+ .description("Configure alert thresholds and webhooks")
102
+ .option("--enable", "Enable alerts")
103
+ .option("--disable", "Disable alerts")
104
+ .option("--webhook <url>", "Set webhook URL for alerts")
105
+ .option("--cpu <percentage>", "CPU threshold percentage")
106
+ .option("--memory <percentage>", "Memory threshold percentage")
107
+ .option("--errorRate <percentage>", "Error rate threshold percentage")
108
+ .option("--uptime <percentage>", "Uptime threshold percentage")
109
+ .option("--cooldown <seconds>", "Alert cooldown period in seconds")
110
+ .option("--service <name>", "Configure alerts for specific service")
111
+ .option("--list", "List current alert configuration")
112
+ .option("--test", "Test webhook connectivity")
113
+ .action(alertCommand);
114
+
115
+ program
116
+ .command("export")
117
+ .description("Export historical metrics data")
118
+ .option("-f, --format <format>", "Export format (json|csv)", "json")
119
+ .option("-h, --hours <hours>", "Hours of data to export", "24")
120
+ .option("-o, --output <file>", "Output file path")
121
+ .option("-s, --service <name>", "Export specific service metrics")
122
+ .action(exportCommand);
123
+
124
+ program
125
+ .command("deps")
126
+ .description("Visualize service dependencies")
127
+ .option("-f, --format <format>", "Output format (text|dot|json)", "text")
128
+ .option("-o, --output <file>", "Output file path")
129
+ .action(depsCommand);
130
+
131
+ program
132
+ .command("profile")
133
+ .description("Performance profiling for services")
134
+ .option("-d, --duration <seconds>", "Profiling duration", "60")
135
+ .option("-i, --interval <ms>", "Sampling interval", "1000")
136
+ .option("-s, --service <name>", "Service name to profile")
137
+ .option("--flamegraph", "Generate flame graph")
138
+ .option("--top <number>", "Show top N functions", "10")
139
+ .action(profileCommand);
140
+
141
+ program
142
+ .command("delete")
143
+ .description("Delete managed services")
144
+ .argument("[name]", "Service name (optional)")
145
+ .option("-a, --all", "Delete all services")
146
+ .option("-f, --force", "Force deletion without errors")
147
+ .option("-r, --remove", "Remove service configuration files")
148
+ .option("-t, --timeout <seconds>", "Timeout for graceful shutdown (default: 30)")
149
+ .action(deleteCommand);
150
+
151
+ program
152
+ .command("save")
153
+ .description("Save service configurations to backup")
154
+ .argument("[name]", "Service name (optional)")
155
+ .option("-a, --all", "Save all services")
156
+ .option("-f, --force", "Force save without errors")
157
+ .option("-b, --backup", "Create timestamped backup")
158
+ .action(saveCommand);
159
+
160
+ program
161
+ .command("resurrect")
162
+ .description("Resurrect services from backup")
163
+ .argument("[name]", "Service name (optional)")
164
+ .option("-a, --all", "Resurrect all services")
165
+ .option("-f, --force", "Force resurrection without errors")
166
+ .option("-c, --config <file>", "Configuration file to use")
167
+ .action(resurrectCommand);
168
+
169
+ program
170
+ .command("deploy")
171
+ .description("🚀 Deploy applications with zero-config production setup")
172
+ .argument("<file>", "Application file to deploy")
173
+ .option("-n, --name <name>", "Service name")
174
+ .option("-p, --port <port>", "Port number", "3000")
175
+ .option("-h, --host <host>", "Host address", "localhost")
176
+ .option("-e, --env <env>", "Environment variables (multiple)", (value, previous) => [...(previous || []), value])
177
+ .option("-i, --instances <number>", "Number of instances")
178
+ .option("--memory <memory>", "Memory limit")
179
+ .option("--cpu <cpu>", "CPU limit")
180
+ .option("--log-level <level>", "Log level")
181
+ .option("--log-file <file>", "Log file path")
182
+ .option("--restart <policy>", "Restart policy")
183
+ .option("--no-health", "Skip health check")
184
+ .option("--no-metrics", "Disable metrics")
185
+ .option("--no-otel", "Disable OpenTelemetry")
186
+ .option("--no-prometheus", "Disable Prometheus")
187
+ .option("--https", "Enable HTTPS")
188
+ .option("--no-linger", "Don't enable linger")
189
+ .option("-f, --force", "Force deployment")
190
+ .option("--reload", "Reload existing service")
191
+ .option("--build", "Build TypeScript")
192
+ .action(deployCommand);
193
+
194
+ program
195
+ .command("loadbalancer")
196
+ .description("Load balancer management")
197
+ .argument("<action>", "Action to perform")
198
+ .option("-p, --port <port>", "Load balancer port", "8080")
199
+ .option("-a, --algorithm <type>", "Load balancing algorithm", "round-robin")
200
+ .option("-b, --backends <list>", "Backend servers (host:port,host:port)")
201
+ .option("--health-check", "Enable health checking", true)
202
+ .option("--health-path <path>", "Health check path", "/healthz")
203
+ .option("--health-interval <ms>", "Health check interval", "10000")
204
+ .action(loadbalancerCommand);
205
+
206
+ program
207
+ .command("dbpool")
208
+ .description("Database connection pool management")
209
+ .argument("<action>", "Action to perform")
210
+ .option("--host <host>", "Database host", "localhost")
211
+ .option("--port <port>", "Database port", "5432")
212
+ .option("--database <name>", "Database name", "testdb")
213
+ .option("--username <user>", "Database username", "user")
214
+ .option("--password <pass>", "Database password", "password")
215
+ .option("--max-connections <num>", "Maximum connections", "10")
216
+ .option("--min-connections <num>", "Minimum connections", "2")
217
+ .option("--concurrency <num>", "Test concurrency", "10")
218
+ .option("--iterations <num>", "Test iterations", "100")
219
+ .action(dbpoolCommand);
220
+
221
+ program
222
+ .command("update")
223
+ .description("Update BS9 to latest version")
224
+ .option("--check", "Check for updates without installing")
225
+ .option("--force", "Force update even if already latest")
226
+ .option("--rollback", "Rollback to previous version")
227
+ .option("--version <version>", "Update to specific version")
228
+ .action(updateCommand);
229
+
230
+ program
231
+ .command("advanced")
232
+ .description("Advanced monitoring dashboard")
233
+ .option("--port <port>", "Dashboard port", "8090")
234
+ .action(advancedMonitoringCommand);
235
+
236
+ program
237
+ .command("consul")
238
+ .description("Consul service discovery")
239
+ .argument("<action>", "Action to perform")
240
+ .option("--consul-url <url>", "Consul URL", "http://localhost:8500")
241
+ .option("--name <name>", "Service name")
242
+ .option("--id <id>", "Service ID")
243
+ .option("--address <address>", "Service address")
244
+ .option("--port <port>", "Service port")
245
+ .option("--tags <tags>", "Service tags (comma-separated)")
246
+ .option("--health-check <url>", "Health check URL")
247
+ .option("--meta <json>", "Service metadata (JSON)")
248
+ .option("--service <service>", "Service name for discovery")
249
+ .action(consulCommand);
250
+
251
+ program
252
+ .command("doctor")
253
+ .description("Perform comprehensive health check")
254
+ .option("--check <type>", "Specific check to run (dependencies|configuration|platform)")
255
+ .option("-v, --verbose", "Verbose output with system information")
256
+ .action(doctorCommand);
257
+
258
+ program
259
+ .command("inspect")
260
+ .description("Comprehensive system inspection and analysis")
261
+ .option("--security", "Security inspection only")
262
+ .option("--performance", "Performance inspection only")
263
+ .option("--configuration", "Configuration inspection only")
264
+ .option("--compliance", "Compliance inspection only")
265
+ .option("--full", "Complete system inspection")
266
+ .option("--report <format>", "Export report (json|csv)")
267
+ .option("--deep", "Deep system analysis")
268
+ .option("-v, --verbose", "Verbose output with detailed analysis")
269
+ .action(inspectCommand);
270
+
271
+ program
272
+ .command("services")
273
+ .description("Multi-service management commands")
274
+ .option("--all", "Apply to all services")
275
+ .option("--pattern <pattern>", "Filter services by name pattern")
276
+ .option("--pid <pid>", "Filter services by PID")
277
+ .option("--status <status>", "Filter services by status")
278
+ .option("--force", "Skip confirmation prompts")
279
+ .action(listServices);
280
+
281
+ program
282
+ .command("start-all")
283
+ .description("Start all stopped services")
284
+ .option("--all", "Start all services")
285
+ .option("--pattern <pattern>", "Start services matching pattern")
286
+ .option("--status <status>", "Start services with specific status")
287
+ .action(startAllServices);
288
+
289
+ program
290
+ .command("stop-all")
291
+ .description("Stop all running services")
292
+ .option("--all", "Stop all services")
293
+ .option("--pattern <pattern>", "Stop services matching pattern")
294
+ .option("--pid <pid>", "Stop service by PID")
295
+ .action(stopAllServices);
296
+
297
+ program
298
+ .command("restart-all")
299
+ .description("Restart multiple services")
300
+ .option("--all", "Restart all services")
301
+ .option("--pattern <pattern>", "Restart services matching pattern")
302
+ .option("--status <status>", "Restart services with specific status")
303
+ .action(restartAllServices);
304
+
305
+ program
306
+ .command("delete-all")
307
+ .description("Delete multiple services")
308
+ .option("--all", "Delete all services")
309
+ .option("--pattern <pattern>", "Delete services matching pattern")
310
+ .option("--force", "Skip confirmation prompts")
311
+ .action(deleteAllServices);
312
+
313
+ program
314
+ .command("alert-create")
315
+ .description("Create a custom alert")
316
+ .option("--name <name>", "Alert name")
317
+ .option("--service <service>", "Service name (optional)")
318
+ .option("--metric <metric>", "Metric to monitor")
319
+ .option("--threshold <threshold>", "Alert threshold")
320
+ .option("--operator <operator>", "Comparison operator (>, <, =, >=, <=)")
321
+ .option("--webhook <webhook>", "Webhook URL")
322
+ .option("--email <email>", "Email address")
323
+ .option("--cooldown <cooldown>", "Cooldown period in seconds")
324
+ .option("--severity <severity>", "Alert severity (low, medium, high, critical)")
325
+ .option("--description <description>", "Alert description")
326
+ .action((options) => {
327
+ if (!options.name || !options.metric || !options.threshold || !options.operator || !options.severity || !options.description) {
328
+ console.error("❌ Required options: --name, --metric, --threshold, --operator, --severity, --description");
329
+ return;
330
+ }
331
+ createAlert({
332
+ name: options.name,
333
+ service: options.service,
334
+ metric: options.metric,
335
+ threshold: parseFloat(options.threshold),
336
+ operator: options.operator,
337
+ webhook: options.webhook,
338
+ email: options.email,
339
+ cooldown: options.cooldown ? parseInt(options.cooldown) : undefined,
340
+ severity: options.severity,
341
+ description: options.description
342
+ });
343
+ });
344
+
345
+ program
346
+ .command("alert-list")
347
+ .description("List custom alerts")
348
+ .option("--service <service>", "Filter by service")
349
+ .option("--enabled", "Show only enabled alerts")
350
+ .action(listAlerts);
351
+
352
+ program
353
+ .command("alert-enable")
354
+ .description("Enable a custom alert")
355
+ .argument("<alert-id>", "Alert ID")
356
+ .action((alertId) => toggleAlert(alertId, true));
357
+
358
+ program
359
+ .command("alert-disable")
360
+ .description("Disable a custom alert")
361
+ .argument("<alert-id>", "Alert ID")
362
+ .action((alertId) => toggleAlert(alertId, false));
363
+
364
+ program
365
+ .command("alert-delete")
366
+ .description("Delete a custom alert")
367
+ .argument("<alert-id>", "Alert ID")
368
+ .action(deleteAlert);
369
+
370
+ program
371
+ .command("alert-test")
372
+ .description("Test a custom alert")
373
+ .argument("<alert-id>", "Alert ID")
374
+ .action(testAlert);
375
+
376
+ program
377
+ .command("alert-monitor")
378
+ .description("Monitor and trigger alerts")
379
+ .action(monitorAlerts);
380
+
381
+ program
382
+ .command("alert-config")
383
+ .description("Set global alert configuration")
384
+ .option("--webhook <webhook>", "Global webhook URL")
385
+ .option("--email <email>", "Global email address")
386
+ .option("--cooldown <cooldown>", "Default cooldown in seconds")
387
+ .action(setGlobalConfig);
388
+
389
+ program.parse();