bs9 1.4.6 → 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.
@@ -0,0 +1,131 @@
1
+ import { execSync } from "child_process";
2
+ import { existsSync } from "fs";
3
+
4
+ export interface ServiceInfo {
5
+ name: string;
6
+ status: string;
7
+ pid?: number;
8
+ port?: number;
9
+ }
10
+
11
+ export async function parseServiceArray(input: string): Promise<string[]> {
12
+ if (!input) return [];
13
+
14
+ // Handle "all" keyword
15
+ if (input === 'all') {
16
+ return await getAllServices();
17
+ }
18
+
19
+ // Handle array syntax [app1, app2, app-*]
20
+ const arrayMatch = input.match(/^\[(.*)\]$/);
21
+ if (!arrayMatch) {
22
+ return [input]; // Single service
23
+ }
24
+
25
+ const services = arrayMatch[1].split(',').map(s => s.trim());
26
+ const expanded: string[] = [];
27
+
28
+ for (const service of services) {
29
+ if (service.includes('*')) {
30
+ // Pattern matching
31
+ const pattern = service.replace('*', '.*');
32
+ const matching = await getServicesByPattern(pattern);
33
+ expanded.push(...matching);
34
+ } else if (service === 'all') {
35
+ // All services
36
+ const allServices = await getAllServices();
37
+ expanded.push(...allServices);
38
+ } else {
39
+ // Specific service
40
+ expanded.push(service);
41
+ }
42
+ }
43
+
44
+ // Remove duplicates and return
45
+ return [...new Set(expanded)];
46
+ }
47
+
48
+ export async function getAllServices(): Promise<string[]> {
49
+ try {
50
+ const output = execSync("systemctl --user list-units --type=service --all --no-pager --no-legend", {
51
+ encoding: "utf-8"
52
+ });
53
+
54
+ const services = output
55
+ .split('\n')
56
+ .filter(line => line.trim())
57
+ .map(line => line.split(' ')[0])
58
+ .filter(service => service.includes('bs9-'))
59
+ .map(service => service.replace('bs9-', ''));
60
+
61
+ return services;
62
+ } catch {
63
+ return [];
64
+ }
65
+ }
66
+
67
+ export async function getServicesByPattern(pattern: string): Promise<string[]> {
68
+ try {
69
+ const allServices = await getAllServices();
70
+ const regex = new RegExp(`^${pattern}$`);
71
+ return allServices.filter(service => regex.test(service));
72
+ } catch {
73
+ return [];
74
+ }
75
+ }
76
+
77
+ export async function getServiceInfo(serviceName: string): Promise<ServiceInfo | null> {
78
+ try {
79
+ const status = execSync(`systemctl --user is-active bs9-${serviceName}`, { encoding: "utf-8" }).trim();
80
+ const showOutput = execSync(`systemctl --user show bs9-${serviceName}`, { encoding: "utf-8" });
81
+
82
+ const pidMatch = showOutput.match(/MainPID=(\d+)/);
83
+ const portMatch = showOutput.match(/Environment=PORT=(\d+)/);
84
+
85
+ return {
86
+ name: serviceName,
87
+ status: status,
88
+ pid: pidMatch ? parseInt(pidMatch[1]) : undefined,
89
+ port: portMatch ? parseInt(portMatch[1]) : undefined
90
+ };
91
+ } catch {
92
+ return null;
93
+ }
94
+ }
95
+
96
+ export async function getMultipleServiceInfo(serviceNames: string[]): Promise<ServiceInfo[]> {
97
+ const results = await Promise.allSettled(
98
+ serviceNames.map(name => getServiceInfo(name))
99
+ );
100
+
101
+ return results
102
+ .filter((result): result is PromiseFulfilledResult<ServiceInfo> =>
103
+ result.status === 'fulfilled' && result.value !== null
104
+ )
105
+ .map(result => result.value);
106
+ }
107
+
108
+ export function confirmAction(message: string): Promise<boolean> {
109
+ return new Promise((resolve) => {
110
+ process.stdout.write(message);
111
+ process.stdin.setRawMode(true);
112
+ process.stdin.resume();
113
+ process.stdin.setEncoding('utf8');
114
+
115
+ const onData = (key: string) => {
116
+ if (key === 'y' || key === 'Y') {
117
+ process.stdin.setRawMode(false);
118
+ process.stdin.pause();
119
+ process.stdin.off('data', onData);
120
+ resolve(true);
121
+ } else if (key === '\n' || key === '\r' || key === 'n' || key === 'N') {
122
+ process.stdin.setRawMode(false);
123
+ process.stdin.pause();
124
+ process.stdin.off('data', onData);
125
+ resolve(false);
126
+ }
127
+ };
128
+
129
+ process.stdin.on('data', onData);
130
+ });
131
+ }