unitup 0.1.4 → 0.2.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/CHANGELOG.md +5 -0
- package/README.md +89 -8
- package/biome.json +0 -1
- package/docs/index.html +188 -234
- package/index.d.ts +336 -445
- package/package.json +9 -3
- package/src/cli.js +187 -101
- package/src/doctor.js +123 -56
- package/src/errors.js +131 -0
- package/src/index.js +132 -59
- package/src/logs.js +148 -0
- package/src/platform/base.js +211 -0
- package/src/platform/index.js +43 -0
- package/src/platform/linux.js +155 -0
- package/src/platform/macos.js +723 -0
- package/src/platform/windows-host.js +246 -0
- package/src/platform/windows.js +495 -0
- package/src/runtimes/bun.js +4 -3
- package/src/runtimes/common.js +24 -6
- package/src/runtimes/deno.js +4 -3
- package/src/runtimes/elixir.js +4 -3
- package/src/runtimes/go.js +4 -3
- package/src/runtimes/index.js +14 -11
- package/src/runtimes/native.js +4 -5
- package/src/runtimes/node.js +4 -3
- package/src/runtimes/php.js +4 -3
- package/src/runtimes/python.js +4 -3
- package/src/runtimes/ruby.js +4 -3
- package/src/runtimes/shell.js +4 -3
- package/src/schedule.js +31 -24
- package/src/service/config.js +55 -0
- package/src/service/manager.js +233 -0
- package/src/service/normalize.js +216 -0
- package/src/systemd.js +84 -38
- package/src/unit.js +12 -18
- package/src/utils.js +32 -18
- package/tsconfig.json +1 -1
- package/types-test/index.ts +158 -0
package/src/doctor.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
1
2
|
import os from 'node:os';
|
|
3
|
+
import { findRuntimeExecutable } from './runtimes/common.js';
|
|
2
4
|
import {
|
|
5
|
+
checkNodeDiagnostics,
|
|
6
|
+
checkUserLinger,
|
|
3
7
|
isLinux,
|
|
4
8
|
isSystemctlAvailable,
|
|
5
9
|
isSystemdPID1,
|
|
6
10
|
isUserSystemdAvailable,
|
|
7
11
|
isUserUnitDirWritable,
|
|
8
|
-
|
|
9
|
-
checkNodeDiagnostics
|
|
12
|
+
runCommand
|
|
10
13
|
} from './systemd.js';
|
|
11
14
|
import { getUserUnitDir } from './unit.js';
|
|
12
|
-
import {
|
|
15
|
+
import { getUnitupDir } from './utils.js';
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Runs system diagnostic checks and returns structured data.
|
|
@@ -17,6 +20,7 @@ import { findRuntimeExecutable } from './runtimes/common.js';
|
|
|
17
20
|
* @returns {Promise<Object>}
|
|
18
21
|
*/
|
|
19
22
|
export async function getDoctorInfo() {
|
|
23
|
+
const platform = process.platform;
|
|
20
24
|
const linux = isLinux();
|
|
21
25
|
const systemctl = await isSystemctlAvailable();
|
|
22
26
|
const pid1 = await isSystemdPID1();
|
|
@@ -25,6 +29,32 @@ export async function getDoctorInfo() {
|
|
|
25
29
|
const lingering = await checkUserLinger();
|
|
26
30
|
const nodeDiag = await checkNodeDiagnostics();
|
|
27
31
|
|
|
32
|
+
// macOS specific checks
|
|
33
|
+
let launchctlAvailable = false;
|
|
34
|
+
if (platform === 'darwin') {
|
|
35
|
+
try {
|
|
36
|
+
const res = await runCommand('launchctl', ['version']);
|
|
37
|
+
launchctlAvailable = res.code === 0 || (res.stdout && res.stdout.length > 0) || !res.stderr.includes('not found');
|
|
38
|
+
} catch {
|
|
39
|
+
launchctlAvailable = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Windows specific checks
|
|
44
|
+
let windowsScmAvailable = false;
|
|
45
|
+
let isAdmin = false;
|
|
46
|
+
if (platform === 'win32') {
|
|
47
|
+
try {
|
|
48
|
+
const res = await runCommand('sc.exe', ['query']);
|
|
49
|
+
windowsScmAvailable = res.code === 0 || !res.stderr.includes('not found');
|
|
50
|
+
// Simple admin check: net session or whoami /priv
|
|
51
|
+
const adminRes = await runCommand('net', ['session']);
|
|
52
|
+
isAdmin = adminRes.code === 0;
|
|
53
|
+
} catch {
|
|
54
|
+
windowsScmAvailable = false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
28
58
|
const nodePath = nodeDiag.execPath || (await findRuntimeExecutable(['node']));
|
|
29
59
|
const pythonPath = await findRuntimeExecutable(['python3', 'python']);
|
|
30
60
|
const rubyPath = await findRuntimeExecutable(['ruby']);
|
|
@@ -36,13 +66,13 @@ export async function getDoctorInfo() {
|
|
|
36
66
|
|
|
37
67
|
const runtimes = {
|
|
38
68
|
'Node.js': nodePath,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
69
|
+
Python: pythonPath,
|
|
70
|
+
Ruby: rubyPath,
|
|
71
|
+
PHP: phpPath,
|
|
72
|
+
Bun: bunPath,
|
|
73
|
+
Deno: denoPath,
|
|
74
|
+
Go: goPath,
|
|
75
|
+
Elixir: elixirPath
|
|
46
76
|
};
|
|
47
77
|
|
|
48
78
|
let cgroupV2 = false;
|
|
@@ -60,11 +90,20 @@ export async function getDoctorInfo() {
|
|
|
60
90
|
const memoryMaxSupported = linux && (cgroupV2 || userSystemd);
|
|
61
91
|
const memorySwapMaxSupported = linux && cgroupV2 && memoryController;
|
|
62
92
|
|
|
93
|
+
let serviceManager = 'systemd';
|
|
94
|
+
if (platform === 'darwin') serviceManager = 'launchd';
|
|
95
|
+
else if (platform === 'win32') serviceManager = 'Windows Service Manager';
|
|
96
|
+
|
|
63
97
|
return {
|
|
98
|
+
platform,
|
|
99
|
+
serviceManager,
|
|
64
100
|
linux,
|
|
65
101
|
systemctl,
|
|
66
102
|
systemdRunning: pid1,
|
|
67
103
|
userSystemdAvailable: userSystemd,
|
|
104
|
+
launchctlAvailable,
|
|
105
|
+
windowsScmAvailable,
|
|
106
|
+
isAdmin,
|
|
68
107
|
cgroupV2,
|
|
69
108
|
memoryController,
|
|
70
109
|
memoryMaxSupported,
|
|
@@ -74,6 +113,7 @@ export async function getDoctorInfo() {
|
|
|
74
113
|
nodeVersion: nodeDiag.version,
|
|
75
114
|
runtimes,
|
|
76
115
|
unitDir: getUserUnitDir(),
|
|
116
|
+
unitupDataDir: getUnitupDir(),
|
|
77
117
|
unitDirWritable,
|
|
78
118
|
lingering,
|
|
79
119
|
username: os.userInfo().username
|
|
@@ -89,27 +129,49 @@ export async function runDoctor() {
|
|
|
89
129
|
const info = await getDoctorInfo();
|
|
90
130
|
|
|
91
131
|
if (info.linux) {
|
|
132
|
+
console.log('Platform: Linux');
|
|
133
|
+
console.log('Service manager: systemd');
|
|
134
|
+
console.log(`Node: ${info.nodePath} ${info.nodeVersion ? `(${info.nodeVersion})` : ''}`);
|
|
135
|
+
console.log(`Unitup data: ${info.unitupDataDir}`);
|
|
92
136
|
console.log('✓ Linux detected');
|
|
93
|
-
} else {
|
|
94
|
-
console.log('✗ Non-Linux OS detected (systemd requires Linux)');
|
|
95
|
-
}
|
|
96
137
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
138
|
+
if (info.systemctl) {
|
|
139
|
+
console.log('✓ systemctl available');
|
|
140
|
+
} else {
|
|
141
|
+
console.log('✗ systemctl command not found');
|
|
142
|
+
}
|
|
102
143
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
144
|
+
if (info.systemdRunning) {
|
|
145
|
+
console.log('✓ systemd is running');
|
|
146
|
+
} else {
|
|
147
|
+
console.log('! systemd is not running as PID 1');
|
|
148
|
+
}
|
|
108
149
|
|
|
109
|
-
|
|
110
|
-
|
|
150
|
+
if (info.userSystemdAvailable) {
|
|
151
|
+
console.log('✓ systemd user services available');
|
|
152
|
+
} else {
|
|
153
|
+
console.log('! systemd user services unavailable');
|
|
154
|
+
}
|
|
155
|
+
} else if (info.platform === 'darwin') {
|
|
156
|
+
console.log('Platform: macOS');
|
|
157
|
+
console.log('Service manager: launchd');
|
|
158
|
+
console.log(`Node: ${info.nodePath} ${info.nodeVersion ? `(${info.nodeVersion})` : ''}`);
|
|
159
|
+
console.log(`Unitup data: ${info.unitupDataDir}`);
|
|
160
|
+
console.log('! Non-Linux OS detected (macOS uses launchd)');
|
|
161
|
+
console.log('✓ launchctl: available');
|
|
162
|
+
console.log('✓ Permissions: user services supported');
|
|
163
|
+
} else if (info.platform === 'win32') {
|
|
164
|
+
console.log('Platform: Windows');
|
|
165
|
+
console.log('Service manager: Windows Service Manager');
|
|
166
|
+
console.log(`Node: ${info.nodePath} ${info.nodeVersion ? `(${info.nodeVersion})` : ''}`);
|
|
167
|
+
console.log(`Unitup data: ${info.unitupDataDir}`);
|
|
168
|
+
console.log('! Non-Linux OS detected (Windows uses Windows Services)');
|
|
169
|
+
console.log(`Administrator: ${info.isAdmin ? 'yes' : 'no'}`);
|
|
170
|
+
if (!info.isAdmin) {
|
|
171
|
+
console.log('! Service installation requires Administrator privileges');
|
|
172
|
+
}
|
|
111
173
|
} else {
|
|
112
|
-
console.log(
|
|
174
|
+
console.log(`✗ Non-Linux OS detected (${info.platform})`);
|
|
113
175
|
}
|
|
114
176
|
|
|
115
177
|
console.log('\nDetected runtimes:');
|
|
@@ -121,48 +183,53 @@ export async function runDoctor() {
|
|
|
121
183
|
}
|
|
122
184
|
}
|
|
123
185
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
186
|
+
if (info.linux) {
|
|
187
|
+
console.log('\nMemory Controller Diagnostics:');
|
|
188
|
+
if (info.cgroupV2) {
|
|
189
|
+
console.log('✓ cgroup v2 detected');
|
|
190
|
+
} else {
|
|
191
|
+
console.log('- cgroup v2 unavailable');
|
|
192
|
+
}
|
|
130
193
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
194
|
+
if (info.memoryController) {
|
|
195
|
+
console.log('✓ Memory controller available');
|
|
196
|
+
} else {
|
|
197
|
+
console.log('- Memory controller unavailable');
|
|
198
|
+
}
|
|
136
199
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
200
|
+
if (info.memoryMaxSupported) {
|
|
201
|
+
console.log('✓ MemoryMax supported');
|
|
202
|
+
} else {
|
|
203
|
+
console.log('- MemoryMax unavailable');
|
|
204
|
+
}
|
|
142
205
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
206
|
+
if (info.memorySwapMaxSupported) {
|
|
207
|
+
console.log('✓ MemorySwapMax supported');
|
|
208
|
+
} else {
|
|
209
|
+
console.log('- MemorySwapMax unavailable');
|
|
210
|
+
}
|
|
148
211
|
|
|
149
|
-
|
|
212
|
+
console.log('');
|
|
150
213
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
214
|
+
if (info.unitDirWritable) {
|
|
215
|
+
console.log('✓ Unit directory writable');
|
|
216
|
+
} else {
|
|
217
|
+
console.log(`! Unit directory not writable (${info.unitDir})`);
|
|
218
|
+
}
|
|
155
219
|
}
|
|
156
220
|
|
|
157
221
|
if (info.lingering) {
|
|
158
222
|
console.log('✓ User lingering is enabled');
|
|
159
223
|
} else {
|
|
160
224
|
console.log('! User lingering is disabled');
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
225
|
+
if (info.linux) {
|
|
226
|
+
console.log('\nUser lingering is disabled.');
|
|
227
|
+
console.log('The service may stop after logout.');
|
|
228
|
+
console.log('\nEnable it manually:');
|
|
229
|
+
console.log(` loginctl enable-linger ${info.username}\n`);
|
|
230
|
+
}
|
|
165
231
|
}
|
|
166
232
|
|
|
233
|
+
console.log('\n✓ Unitup can manage services on this machine');
|
|
167
234
|
return info;
|
|
168
235
|
}
|
package/src/errors.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all Unitup errors.
|
|
3
|
+
*/
|
|
4
|
+
export class UnitupError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* @param {string} message
|
|
7
|
+
* @param {string} [code]
|
|
8
|
+
*/
|
|
9
|
+
constructor(message, code = 'UNITUP_ERROR') {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = this.constructor.name;
|
|
12
|
+
this.code = code;
|
|
13
|
+
if (Error.captureStackTrace) {
|
|
14
|
+
Error.captureStackTrace(this, this.constructor);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Thrown when an unsupported platform is encountered.
|
|
21
|
+
*/
|
|
22
|
+
export class UnsupportedPlatformError extends UnitupError {
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} [platform]
|
|
25
|
+
*/
|
|
26
|
+
constructor(platform = process.platform) {
|
|
27
|
+
super(`Platform "${platform}" is not supported by Unitup.`, 'ERR_UNSUPPORTED_PLATFORM');
|
|
28
|
+
this.platform = platform;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Thrown when a specified service is not found.
|
|
34
|
+
*/
|
|
35
|
+
export class ServiceNotFoundError extends UnitupError {
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} name
|
|
38
|
+
*/
|
|
39
|
+
constructor(name) {
|
|
40
|
+
super(`Service "${name}" does not exist.`, 'ERR_SERVICE_NOT_FOUND');
|
|
41
|
+
this.serviceName = name;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Thrown when attempting to create a service that already exists without overwrite/force.
|
|
47
|
+
*/
|
|
48
|
+
export class ServiceAlreadyExistsError extends UnitupError {
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} name
|
|
51
|
+
*/
|
|
52
|
+
constructor(name) {
|
|
53
|
+
super(`Service "${name}" already exists. Use --force to overwrite.`, 'ERR_SERVICE_ALREADY_EXISTS');
|
|
54
|
+
this.serviceName = name;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Thrown when elevated administrator or root privileges are required for an action.
|
|
60
|
+
*/
|
|
61
|
+
export class PermissionRequiredError extends UnitupError {
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} message
|
|
64
|
+
* @param {string} [action]
|
|
65
|
+
*/
|
|
66
|
+
constructor(message = 'Administrator/root privileges are required to perform this action.', action) {
|
|
67
|
+
super(message, 'ERR_PERMISSION_REQUIRED');
|
|
68
|
+
this.action = action;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Thrown when a service fails to start.
|
|
74
|
+
*/
|
|
75
|
+
export class ServiceStartError extends UnitupError {
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} name
|
|
78
|
+
* @param {string} [reason]
|
|
79
|
+
*/
|
|
80
|
+
constructor(name, reason) {
|
|
81
|
+
super(`Failed to start service "${name}"${reason ? `: ${reason}` : ''}`, 'ERR_SERVICE_START');
|
|
82
|
+
this.serviceName = name;
|
|
83
|
+
this.reason = reason;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Thrown when a service fails to stop.
|
|
89
|
+
*/
|
|
90
|
+
export class ServiceStopError extends UnitupError {
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} name
|
|
93
|
+
* @param {string} [reason]
|
|
94
|
+
*/
|
|
95
|
+
constructor(name, reason) {
|
|
96
|
+
super(`Failed to stop service "${name}"${reason ? `: ${reason}` : ''}`, 'ERR_SERVICE_STOP');
|
|
97
|
+
this.serviceName = name;
|
|
98
|
+
this.reason = reason;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Thrown when service configuration is invalid.
|
|
104
|
+
*/
|
|
105
|
+
export class InvalidServiceConfigError extends UnitupError {
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} message
|
|
108
|
+
* @param {string} [field]
|
|
109
|
+
*/
|
|
110
|
+
constructor(message, field) {
|
|
111
|
+
super(message, 'ERR_INVALID_CONFIG');
|
|
112
|
+
this.field = field;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Thrown when a required binary executable cannot be resolved.
|
|
118
|
+
*/
|
|
119
|
+
export class ExecutableNotFoundError extends UnitupError {
|
|
120
|
+
/**
|
|
121
|
+
* @param {string} executable
|
|
122
|
+
* @param {string} [message]
|
|
123
|
+
*/
|
|
124
|
+
constructor(executable, message) {
|
|
125
|
+
super(
|
|
126
|
+
message || `Executable "${executable}" could not be found in PATH or at specified path.`,
|
|
127
|
+
'ERR_EXECUTABLE_NOT_FOUND'
|
|
128
|
+
);
|
|
129
|
+
this.executable = executable;
|
|
130
|
+
}
|
|
131
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,78 +1,153 @@
|
|
|
1
|
+
import { getDoctorInfo, runDoctor } from './doctor.js';
|
|
2
|
+
import {
|
|
3
|
+
ExecutableNotFoundError,
|
|
4
|
+
InvalidServiceConfigError,
|
|
5
|
+
PermissionRequiredError,
|
|
6
|
+
ServiceAlreadyExistsError,
|
|
7
|
+
ServiceNotFoundError,
|
|
8
|
+
ServiceStartError,
|
|
9
|
+
ServiceStopError,
|
|
10
|
+
UnitupError,
|
|
11
|
+
UnsupportedPlatformError
|
|
12
|
+
} from './errors.js';
|
|
13
|
+
import { readServiceLogs } from './logs.js';
|
|
14
|
+
import {
|
|
15
|
+
LinuxAdapter,
|
|
16
|
+
MacOSAdapter,
|
|
17
|
+
ServiceAdapter,
|
|
18
|
+
WindowsAdapter,
|
|
19
|
+
getAdapter,
|
|
20
|
+
getPlatformCapabilities
|
|
21
|
+
} from './platform/index.js';
|
|
22
|
+
import { WindowsServiceHost } from './platform/windows-host.js';
|
|
23
|
+
import { detectRuntime, resolveRuntimeConfig } from './runtimes/index.js';
|
|
24
|
+
import {
|
|
25
|
+
createSchedule,
|
|
26
|
+
disableSchedule,
|
|
27
|
+
enableSchedule,
|
|
28
|
+
getScheduleStatus,
|
|
29
|
+
listSchedules,
|
|
30
|
+
removeSchedule,
|
|
31
|
+
runSchedule,
|
|
32
|
+
validateCalendar
|
|
33
|
+
} from './schedule.js';
|
|
34
|
+
import { ServiceManager, defaultManager } from './service/manager.js';
|
|
35
|
+
import { normalizeServiceConfig, resolveExecutable } from './service/normalize.js';
|
|
1
36
|
import {
|
|
2
37
|
addService,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
38
|
+
checkNodeDiagnostics,
|
|
39
|
+
checkUserLinger,
|
|
40
|
+
executeJournalctlMaintenance,
|
|
41
|
+
findNodeExecutable,
|
|
42
|
+
getAllServicesMemoryUsage,
|
|
43
|
+
getServiceFailures,
|
|
44
|
+
getServiceMemoryUsage,
|
|
7
45
|
getServiceStatus,
|
|
8
46
|
getServiceStatusRaw,
|
|
9
|
-
listServices,
|
|
10
|
-
inspectService,
|
|
11
|
-
getServiceFailures,
|
|
12
47
|
getServicesByGroup,
|
|
13
|
-
|
|
14
|
-
setServiceLimits,
|
|
15
|
-
executeJournalctlMaintenance,
|
|
48
|
+
inspectService,
|
|
16
49
|
isLinux,
|
|
17
50
|
isSystemctlAvailable,
|
|
18
51
|
isSystemdPID1,
|
|
19
52
|
isUserSystemdAvailable,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
53
|
+
listServices,
|
|
54
|
+
removeService,
|
|
55
|
+
resetCommandRunner,
|
|
56
|
+
restartService,
|
|
57
|
+
runCommand,
|
|
58
|
+
runJournalctlLogs,
|
|
25
59
|
setCommandRunner,
|
|
26
|
-
|
|
60
|
+
setServiceLimits,
|
|
61
|
+
startService,
|
|
62
|
+
stopService
|
|
27
63
|
} from './systemd.js';
|
|
28
|
-
import { getDoctorInfo } from './doctor.js';
|
|
29
|
-
import {
|
|
30
|
-
createSchedule,
|
|
31
|
-
listSchedules,
|
|
32
|
-
getScheduleStatus,
|
|
33
|
-
runSchedule,
|
|
34
|
-
enableSchedule,
|
|
35
|
-
disableSchedule,
|
|
36
|
-
removeSchedule,
|
|
37
|
-
validateCalendar
|
|
38
|
-
} from './schedule.js';
|
|
39
64
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
generateScheduleServiceContent,
|
|
66
|
+
generateTimerContent,
|
|
42
67
|
getTimerPath,
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
getUnitPath,
|
|
69
|
+
getUserUnitDir,
|
|
45
70
|
parseUnitContent,
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
timerFileExists,
|
|
72
|
+
unitFileExists
|
|
48
73
|
} from './unit.js';
|
|
49
74
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
getTimerFilename,
|
|
53
|
-
getServiceNameFromUnit,
|
|
54
|
-
readAppMetadata,
|
|
75
|
+
findProjectConfig,
|
|
76
|
+
formatMemoryBytes,
|
|
55
77
|
getAppMetadataPath,
|
|
56
|
-
|
|
78
|
+
getAppsDir,
|
|
79
|
+
getConfigFilepath,
|
|
57
80
|
getScheduleMetadataPath,
|
|
81
|
+
getSchedulesDir,
|
|
82
|
+
getServiceNameFromUnit,
|
|
83
|
+
getTimerFilename,
|
|
84
|
+
getUnitFilename,
|
|
85
|
+
getUnitupDir,
|
|
86
|
+
readAppMetadata,
|
|
58
87
|
readGlobalConfig,
|
|
59
|
-
saveGlobalConfig,
|
|
60
|
-
getConfigFilepath,
|
|
61
|
-
findProjectConfig,
|
|
62
88
|
readProjectConfig,
|
|
63
|
-
|
|
89
|
+
readScheduleMetadata,
|
|
64
90
|
resolveEffectiveMemoryLimits,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
validateMemorySize,
|
|
91
|
+
sanitizeServiceName,
|
|
92
|
+
saveGlobalConfig,
|
|
93
|
+
saveProjectConfig,
|
|
69
94
|
validateDuration,
|
|
70
|
-
|
|
95
|
+
validateMemorySize
|
|
71
96
|
} from './utils.js';
|
|
72
|
-
|
|
97
|
+
|
|
98
|
+
// Aliases for unified cross-platform API
|
|
99
|
+
const install = (opts) => defaultManager.install(opts);
|
|
100
|
+
const uninstall = (name, opts) => defaultManager.uninstall(name, opts);
|
|
101
|
+
const start = (name, opts) => defaultManager.start(name, opts);
|
|
102
|
+
const stop = (name, opts) => defaultManager.stop(name, opts);
|
|
103
|
+
const restart = (name, opts) => defaultManager.restart(name, opts);
|
|
104
|
+
const status = (name, opts) => defaultManager.status(name, opts);
|
|
105
|
+
const list = (opts) => defaultManager.list(opts);
|
|
106
|
+
const inspect = (name, opts) => defaultManager.inspect(name, opts);
|
|
107
|
+
const logs = (name, opts) => defaultManager.logs(name, opts);
|
|
108
|
+
const enable = (name, opts) => defaultManager.enable(name, opts);
|
|
109
|
+
const disable = (name, opts) => defaultManager.disable(name, opts);
|
|
110
|
+
const platform = (targetPlatform) => getPlatformCapabilities(targetPlatform);
|
|
73
111
|
|
|
74
112
|
export {
|
|
75
|
-
//
|
|
113
|
+
// Unified cross-platform API
|
|
114
|
+
install,
|
|
115
|
+
uninstall,
|
|
116
|
+
start,
|
|
117
|
+
stop,
|
|
118
|
+
restart,
|
|
119
|
+
status,
|
|
120
|
+
list,
|
|
121
|
+
inspect,
|
|
122
|
+
logs,
|
|
123
|
+
enable,
|
|
124
|
+
disable,
|
|
125
|
+
platform,
|
|
126
|
+
ServiceManager,
|
|
127
|
+
defaultManager,
|
|
128
|
+
// Platform Adapters & Factory
|
|
129
|
+
ServiceAdapter,
|
|
130
|
+
LinuxAdapter,
|
|
131
|
+
MacOSAdapter,
|
|
132
|
+
WindowsAdapter,
|
|
133
|
+
WindowsServiceHost,
|
|
134
|
+
getAdapter,
|
|
135
|
+
getPlatformCapabilities,
|
|
136
|
+
// Normalization & Resolution
|
|
137
|
+
normalizeServiceConfig,
|
|
138
|
+
resolveExecutable,
|
|
139
|
+
readServiceLogs,
|
|
140
|
+
// Error hierarchy
|
|
141
|
+
UnitupError,
|
|
142
|
+
UnsupportedPlatformError,
|
|
143
|
+
ServiceNotFoundError,
|
|
144
|
+
ServiceAlreadyExistsError,
|
|
145
|
+
PermissionRequiredError,
|
|
146
|
+
ServiceStartError,
|
|
147
|
+
ServiceStopError,
|
|
148
|
+
InvalidServiceConfigError,
|
|
149
|
+
ExecutableNotFoundError,
|
|
150
|
+
// Main programmatic service management API (backward compatible)
|
|
76
151
|
addService as createService,
|
|
77
152
|
addService,
|
|
78
153
|
startService,
|
|
@@ -88,9 +163,9 @@ export {
|
|
|
88
163
|
setServiceLimits,
|
|
89
164
|
getServiceMemoryUsage,
|
|
90
165
|
getAllServicesMemoryUsage,
|
|
91
|
-
executeJournalctlMaintenance
|
|
166
|
+
executeJournalctlMaintenance,
|
|
92
167
|
runJournalctlLogs as getServiceLogs,
|
|
93
|
-
|
|
168
|
+
runJournalctlLogs,
|
|
94
169
|
// Programmatic schedule management API
|
|
95
170
|
createSchedule,
|
|
96
171
|
listSchedules,
|
|
@@ -100,16 +175,13 @@ export {
|
|
|
100
175
|
disableSchedule,
|
|
101
176
|
removeSchedule,
|
|
102
177
|
validateCalendar,
|
|
103
|
-
|
|
104
178
|
// Duration & Validation helpers
|
|
105
179
|
validateMemorySize,
|
|
106
180
|
validateDuration,
|
|
107
181
|
formatMemoryBytes,
|
|
108
|
-
|
|
109
182
|
// Runtime detection & resolution
|
|
110
183
|
detectRuntime,
|
|
111
184
|
resolveRuntimeConfig,
|
|
112
|
-
|
|
113
185
|
// Metadata & Config helpers
|
|
114
186
|
readAppMetadata,
|
|
115
187
|
getAppMetadataPath,
|
|
@@ -125,7 +197,6 @@ export {
|
|
|
125
197
|
getSchedulesDir,
|
|
126
198
|
getAppsDir,
|
|
127
199
|
getUnitupDir,
|
|
128
|
-
|
|
129
200
|
// System & Doctor checks
|
|
130
201
|
isSystemctlAvailable as isSystemdAvailable,
|
|
131
202
|
isSystemctlAvailable,
|
|
@@ -136,7 +207,7 @@ export {
|
|
|
136
207
|
checkNodeDiagnostics,
|
|
137
208
|
findNodeExecutable,
|
|
138
209
|
getDoctorInfo,
|
|
139
|
-
|
|
210
|
+
runDoctor,
|
|
140
211
|
// Unit file & path helpers
|
|
141
212
|
getUserUnitDir,
|
|
142
213
|
getUnitPath,
|
|
@@ -150,8 +221,10 @@ export {
|
|
|
150
221
|
getUnitFilename,
|
|
151
222
|
getTimerFilename,
|
|
152
223
|
getServiceNameFromUnit,
|
|
153
|
-
|
|
154
224
|
// Runner override for testing
|
|
155
225
|
setCommandRunner,
|
|
156
|
-
resetCommandRunner
|
|
226
|
+
resetCommandRunner,
|
|
227
|
+
runCommand
|
|
157
228
|
};
|
|
229
|
+
|
|
230
|
+
export default defaultManager;
|