unitup 0.0.8 â 0.0.10
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 +398 -171
- package/docs/index.html +531 -0
- package/index.d.ts +204 -134
- package/package.json +4 -1
- package/src/cli.js +393 -90
- package/src/doctor.js +73 -14
- package/src/index.js +32 -1
- package/src/runtimes/bun.js +46 -0
- package/src/runtimes/common.js +73 -0
- package/src/runtimes/deno.js +46 -0
- package/src/runtimes/elixir.js +46 -0
- package/src/runtimes/go.js +46 -0
- package/src/runtimes/index.js +155 -0
- package/src/runtimes/native.js +38 -0
- package/src/runtimes/node.js +57 -0
- package/src/runtimes/php.js +46 -0
- package/src/runtimes/python.js +46 -0
- package/src/runtimes/ruby.js +46 -0
- package/src/runtimes/shell.js +46 -0
- package/src/systemd.js +349 -25
- package/src/unit.js +72 -22
- package/src/utils.js +220 -0
package/README.md
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
# unitup
|
|
2
2
|
|
|
3
|
-
> Minimal, zero-dependency
|
|
3
|
+
> Minimal, zero-dependency CLI & library to run Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell scripts, and native binaries as `systemd` user services.
|
|
4
4
|
|
|
5
5
|
`unitup` provides a thin, user-level layer over Linux `systemd`. It does **not** create a custom daemon, manage process trees, or act as a PM2 alternative. Instead, it generates and manages native systemd user units (`~/.config/systemd/user/unitup-<name>.service`), letting systemd handle process supervision, auto-restarts, logging, and OS boot startup without requiring `sudo` privileges.
|
|
6
6
|
|
|
7
|
+
```bash
|
|
8
|
+
# Quick Start
|
|
9
|
+
npm install -g unitup
|
|
10
|
+
|
|
11
|
+
unitup add server.js --start
|
|
12
|
+
unitup status server
|
|
13
|
+
unitup logs server --follow
|
|
14
|
+
|
|
15
|
+
# Multi-runtime & Native Executables
|
|
16
|
+
unitup add worker.py --runtime python --start
|
|
17
|
+
unitup add ./server --runtime native --name api --start
|
|
18
|
+
```
|
|
19
|
+
|
|
7
20
|
---
|
|
8
21
|
|
|
9
|
-
##
|
|
22
|
+
## unitup vs PM2
|
|
10
23
|
|
|
11
24
|
`unitup` is **not** a PM2 replacement or an independent process manager. While PM2 runs its own master daemon, `unitup` is strictly a thin and transparent CLI layer on top of Linux `systemd`.
|
|
12
25
|
|
|
@@ -14,39 +27,109 @@
|
|
|
14
27
|
|
|
15
28
|
| Feature | `unitup` | PM2 |
|
|
16
29
|
| :--- | :--- | :--- |
|
|
17
|
-
| **Background Process (Daemon)** | **
|
|
30
|
+
| **Background Process (Daemon)** | **No resident unitup daemon**. Systemd directly supervises processes. | **Runs a persistent process-management daemon**. |
|
|
18
31
|
| **System Integration** | Native Linux OS `systemd` user service (`~/.config/systemd/user/`). | Custom process monitoring via PM2's internal daemon. |
|
|
19
|
-
| **
|
|
32
|
+
| **Multi-Runtime & Executable Support** | **Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell, and native binaries** out of the box. | **Node.js-focused process manager with support for running other commands**. |
|
|
33
|
+
| **Privileges Required** | Does **not** require `sudo`. | Boot integration commonly requires running the PM2 startup setup command with elevated privileges. |
|
|
20
34
|
| **Dependencies** | **0 Runtime Dependencies** (Uses Node.js standard modules only). | Dozens of 3rd party npm packages. |
|
|
21
35
|
| **Log Management** | Delegates to native Linux `journald` system (`journalctl`). | Manages `.pm2/logs` files (requires `pm2-logrotate` for rotation). |
|
|
22
36
|
| **Boot Startup** | Native systemd lingering (`loginctl enable-linger`). | Custom startup script launching PM2 daemon. |
|
|
23
37
|
|
|
24
38
|
---
|
|
25
39
|
|
|
26
|
-
###
|
|
40
|
+
### Core Architecture
|
|
41
|
+
|
|
42
|
+
At its core, `unitup` generates systemd service unit files directly from a generic `command + args` model rather than being hardcoded to Node.js:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
{
|
|
46
|
+
command: "/usr/bin/python3",
|
|
47
|
+
args: ["/home/user/apps/worker.py"],
|
|
48
|
+
cwd: "/home/user/apps",
|
|
49
|
+
env: {
|
|
50
|
+
APP_ENV: "production"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Core Promises
|
|
27
56
|
|
|
28
|
-
1. ⥠**
|
|
29
|
-
2.
|
|
30
|
-
3.
|
|
31
|
-
4.
|
|
57
|
+
1. ⥠**No persistent unitup CPU or memory overhead**: After running `unitup` commands, `unitup` exits immediately. No extra master process stays running in the background.
|
|
58
|
+
2. ð **Language-Agnostic & Executable Ready**: Works out of the box with Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell scripts, or compiled native binaries.
|
|
59
|
+
3. ð **Transparent systemd-native configuration**: Avoids shell execution and validates generated unit arguments (`shell: false`). Generated `.service` files are saved as standard text at `~/.config/systemd/user/`.
|
|
60
|
+
4. ð ïļ **Automatic Absolute Path & PATH Resolution**: Resolves absolute binary and script paths, automatically injecting proper `PATH` environment into unit files.
|
|
61
|
+
5. ð **Backward Compatible**: Full support for existing Node.js projects, legacy CLI parameters, and old metadata formats (`{ node, script }`).
|
|
32
62
|
|
|
33
|
-
|
|
63
|
+
---
|
|
34
64
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
65
|
+
## Supported Runtimes
|
|
66
|
+
|
|
67
|
+
- **Node.js**: `.js`, `.mjs`, `.cjs`
|
|
68
|
+
- **Python**: `.py` (resolves `python3` then `python`)
|
|
69
|
+
- **Ruby**: `.rb` (`ruby`)
|
|
70
|
+
- **PHP**: `.php` (`php`)
|
|
71
|
+
- **Bun**: `bun`
|
|
72
|
+
- **Deno**: `deno` (default command: `deno run <script>`)
|
|
73
|
+
- **Go**: `.go` (`go run <script>`)
|
|
74
|
+
- **Elixir**: `.ex`, `.exs` (`elixir <script>`)
|
|
75
|
+
- **Shell Scripts**: `.sh` (`bash`, `sh`)
|
|
76
|
+
- **Native Executables**: `./server` (compiled Go, Rust, C/C++, etc.)
|
|
39
77
|
|
|
40
78
|
---
|
|
41
79
|
|
|
42
80
|
## Features
|
|
43
81
|
|
|
44
|
-
- ⥠**Zero runtime dependencies** â
|
|
45
|
-
- ð **No
|
|
46
|
-
- ðĄïļ **Secure by design** â
|
|
47
|
-
-
|
|
82
|
+
- ⥠**Zero runtime dependencies** â lightweight, ESM-first package with CommonJS support.
|
|
83
|
+
- ð **No sudo required for normal service creation and management** â operates entirely within systemd user scope (`~/.config/systemd/user/`).
|
|
84
|
+
- ðĄïļ **Secure by design** â avoids shell-based command execution, validates service names, escapes systemd arguments, and sanitizes input to prevent shell injection.
|
|
85
|
+
- ð§ **Systemd-Native Memory Limits** â Configure `MemoryHigh`, `MemoryMax`, and `MemorySwapMax` per service without extra monitoring daemons.
|
|
86
|
+
- ð **Journald Log Maintenance** â Advanced log streaming with filters (`--since`, `--until`, `--priority`, `--grep`, `--boot`, `--json`) and journal maintenance (`disk-usage`, `rotate`, `vacuum`).
|
|
87
|
+
- ðĐš **System readiness & runtime check** â `unitup doctor` verifies OS, systemd PID 1, systemctl user bus, cgroup v2 memory controller support, user lingering, and detected runtimes.
|
|
48
88
|
- ð **Compact status & logs** â clean summary output from `systemctl show` and live `journalctl` streaming.
|
|
49
|
-
- ðĶ **Programmatic API** â imported directly into JavaScript applications.
|
|
89
|
+
- ðĶ **Programmatic API** â imported directly into JavaScript and TypeScript applications.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## CLI Usage
|
|
94
|
+
|
|
95
|
+
### Memory Limits
|
|
96
|
+
|
|
97
|
+
`unitup` allows you to set native systemd memory limits for your services without running background monitoring daemons:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Add a service with memory limits
|
|
101
|
+
unitup add server.js \
|
|
102
|
+
--memory-high 400M \
|
|
103
|
+
--memory-max 512M \
|
|
104
|
+
--swap-max 256M
|
|
105
|
+
|
|
106
|
+
# Update limits on an existing service
|
|
107
|
+
unitup limits api --memory-high 400M --memory-max 512M
|
|
108
|
+
|
|
109
|
+
# Reset memory limits back to system defaults
|
|
110
|
+
unitup limits api --reset-memory
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
*Supported size units:* `128K`, `256M`, `1G`, `infinity`, `max`, or raw byte integers.
|
|
114
|
+
|
|
115
|
+
### Journald Log Maintenance
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Filter logs by time, priority, grep keyword, boot, or JSON output
|
|
119
|
+
unitup logs api --since 1h --until now
|
|
120
|
+
unitup logs api --priority err --grep "timeout"
|
|
121
|
+
unitup logs api --boot --json
|
|
122
|
+
|
|
123
|
+
# Journal storage maintenance
|
|
124
|
+
unitup journal disk-usage
|
|
125
|
+
unitup journal rotate
|
|
126
|
+
unitup journal vacuum --size 500M
|
|
127
|
+
unitup journal vacuum --time 14d
|
|
128
|
+
unitup journal vacuum --files 10 --yes
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> [!NOTE]
|
|
132
|
+
> `unitup journal vacuum` prompts for user confirmation before executing system-wide log cleanup unless `--yes` / `-y` or `--dry-run` is provided. If permissions are insufficient, `unitup` handles it gracefully without executing `sudo`.
|
|
50
133
|
|
|
51
134
|
---
|
|
52
135
|
|
|
@@ -72,143 +155,195 @@ npm install unitup
|
|
|
72
155
|
|
|
73
156
|
---
|
|
74
157
|
|
|
75
|
-
##
|
|
158
|
+
## CLI Usage
|
|
159
|
+
|
|
160
|
+
### Multi-Runtime Examples
|
|
76
161
|
|
|
77
162
|
```bash
|
|
78
|
-
#
|
|
79
|
-
unitup
|
|
163
|
+
# Node.js
|
|
164
|
+
unitup add server.js --runtime node
|
|
165
|
+
|
|
166
|
+
# Python
|
|
167
|
+
unitup add worker.py --runtime python
|
|
168
|
+
|
|
169
|
+
# Ruby
|
|
170
|
+
unitup add app.rb --runtime ruby
|
|
171
|
+
|
|
172
|
+
# PHP (with runtime flags)
|
|
173
|
+
unitup add index.php --runtime php --runtime-arg -S --runtime-arg 0.0.0.0:8080
|
|
174
|
+
|
|
175
|
+
# Bun
|
|
176
|
+
unitup add server.ts --runtime bun
|
|
80
177
|
|
|
81
|
-
#
|
|
82
|
-
unitup add server.
|
|
178
|
+
# Deno (with runtime permission flags)
|
|
179
|
+
unitup add server.ts --runtime deno --runtime-arg --allow-net --runtime-arg --allow-env
|
|
83
180
|
|
|
84
|
-
#
|
|
85
|
-
unitup
|
|
181
|
+
# Go
|
|
182
|
+
unitup add main.go --runtime go
|
|
86
183
|
|
|
87
|
-
#
|
|
88
|
-
unitup
|
|
184
|
+
# Elixir
|
|
185
|
+
unitup add app.exs --runtime elixir
|
|
89
186
|
|
|
90
|
-
#
|
|
91
|
-
unitup
|
|
92
|
-
|
|
187
|
+
# Native Executable
|
|
188
|
+
unitup add ./server --runtime native --name api
|
|
189
|
+
|
|
190
|
+
# Generic Command Line Usage (bypasses runtime detection)
|
|
191
|
+
unitup add \
|
|
192
|
+
--name worker \
|
|
193
|
+
--command /usr/bin/python3 \
|
|
194
|
+
--arg /home/user/apps/worker.py \
|
|
195
|
+
--arg --port \
|
|
196
|
+
--arg 3000
|
|
93
197
|
```
|
|
94
198
|
|
|
199
|
+
> *Note: For production deployments, compiling the Go application and registering the resulting native binary is recommended.*
|
|
200
|
+
|
|
95
201
|
---
|
|
96
202
|
|
|
97
|
-
##
|
|
203
|
+
## Automatic Runtime & Shebang Detection
|
|
98
204
|
|
|
99
|
-
|
|
205
|
+
`unitup` automatically detects the runtime based on file extension and shebang headers:
|
|
100
206
|
|
|
101
|
-
Performs comprehensive system and Node.js runtime diagnostic checks:
|
|
102
|
-
- OS check (Linux)
|
|
103
|
-
- `systemctl` executable availability
|
|
104
|
-
- PID 1 systemd verification
|
|
105
|
-
- Systemd user bus accessibility
|
|
106
|
-
- Node.js executable PATH resolution (`which node`, `command -v`, `process.execPath`)
|
|
107
|
-
- Node.js binary execution capability (`node -v`)
|
|
108
|
-
- Unit directory write permissions (`~/.config/systemd/user/`)
|
|
109
|
-
- User lingering state (`loginctl enable-linger`)
|
|
110
|
-
|
|
111
|
-
Example output:
|
|
112
207
|
```text
|
|
113
|
-
|
|
208
|
+
.js, .mjs, .cjs â node
|
|
209
|
+
.py â python
|
|
210
|
+
.rb â ruby
|
|
211
|
+
.php â php
|
|
212
|
+
.sh â shell
|
|
213
|
+
.go â go
|
|
214
|
+
.ex, .exs â elixir
|
|
215
|
+
```
|
|
114
216
|
|
|
115
|
-
|
|
116
|
-
â systemctl available
|
|
117
|
-
â systemd is running
|
|
118
|
-
â systemd user services available
|
|
119
|
-
â Node.js: /usr/bin/node
|
|
120
|
-
â Node version: v20.11.0
|
|
121
|
-
â PATH includes node
|
|
122
|
-
! User lingering is disabled
|
|
217
|
+
Shebang examples detected automatically:
|
|
123
218
|
|
|
124
|
-
|
|
125
|
-
|
|
219
|
+
```text
|
|
220
|
+
#!/usr/bin/env python3
|
|
221
|
+
#!/usr/bin/env node
|
|
222
|
+
#!/usr/bin/env ruby
|
|
223
|
+
#!/bin/bash
|
|
224
|
+
```
|
|
126
225
|
|
|
127
|
-
|
|
128
|
-
|
|
226
|
+
For ambiguous extensions such as `.ts`, `unitup` requires explicit runtime selection:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
Could not determine runtime for server.ts.
|
|
230
|
+
|
|
231
|
+
Specify one:
|
|
232
|
+
unitup add server.ts --runtime bun
|
|
233
|
+
unitup add server.ts --runtime deno
|
|
234
|
+
unitup add server.ts --runtime node
|
|
129
235
|
```
|
|
130
236
|
|
|
131
237
|
---
|
|
132
238
|
|
|
133
|
-
|
|
239
|
+
## Native Executable Support
|
|
134
240
|
|
|
135
|
-
|
|
241
|
+
When adding a native executable:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
unitup add ./server --runtime native --name api
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`unitup` checks that the file:
|
|
248
|
+
1. Exists
|
|
249
|
+
2. Is a regular file
|
|
250
|
+
3. Has execute permission (`chmod +x`)
|
|
251
|
+
|
|
252
|
+
If execute permission is missing, `unitup` does **not** modify permissions automatically; it provides a helpful command suggestion:
|
|
136
253
|
|
|
137
|
-
#### 1. Node.js not found in PATH
|
|
138
254
|
```text
|
|
139
|
-
|
|
255
|
+
The executable is not runnable.
|
|
140
256
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
or via package manager:
|
|
144
|
-
sudo apt install nodejs
|
|
257
|
+
Run:
|
|
258
|
+
chmod +x /home/user/apps/server
|
|
145
259
|
```
|
|
146
260
|
|
|
147
|
-
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## CLI Commands Reference
|
|
264
|
+
|
|
265
|
+
### `unitup doctor`
|
|
266
|
+
|
|
267
|
+
Performs comprehensive system readiness and runtime diagnostic checks:
|
|
268
|
+
|
|
148
269
|
```text
|
|
149
|
-
|
|
270
|
+
unitup doctor
|
|
150
271
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
272
|
+
â Linux detected
|
|
273
|
+
â systemctl available
|
|
274
|
+
â systemd is running
|
|
275
|
+
â systemd user services available
|
|
154
276
|
|
|
155
|
-
|
|
156
|
-
|
|
277
|
+
Detected runtimes:
|
|
278
|
+
â Node.js: /usr/bin/node
|
|
279
|
+
â Python: /usr/bin/python3
|
|
280
|
+
â Ruby: /usr/bin/ruby
|
|
281
|
+
â Go: /usr/local/go/bin/go
|
|
282
|
+
- Bun: not found
|
|
283
|
+
- Deno: not found
|
|
284
|
+
- Elixir: not found
|
|
285
|
+
|
|
286
|
+
â Unit directory writable
|
|
287
|
+
! User lingering is disabled
|
|
157
288
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
Type=simple
|
|
161
|
-
WorkingDirectory=/home/user/projects/app
|
|
162
|
-
Environment=PATH="/home/user/.nvm/versions/node/v20.11.0/bin:/usr/local/bin:/usr/bin:/bin"
|
|
163
|
-
ExecStart=/home/user/.nvm/versions/node/v20.11.0/bin/node /home/user/projects/app/server.js
|
|
289
|
+
Enable it manually:
|
|
290
|
+
loginctl enable-linger username
|
|
164
291
|
```
|
|
165
292
|
|
|
166
|
-
|
|
293
|
+
*Note: Missing optional runtimes do not cause `unitup doctor` to exit with an error.*
|
|
167
294
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### Missing Runtime Handling
|
|
171
298
|
|
|
172
|
-
If
|
|
299
|
+
If a requested runtime is not installed on the system, `unitup` provides clear installation guidance:
|
|
300
|
+
|
|
301
|
+
```text
|
|
302
|
+
Python runtime could not be found.
|
|
303
|
+
|
|
304
|
+
Install Python or specify its path:
|
|
305
|
+
unitup add worker.py --command /usr/bin/python3
|
|
306
|
+
```
|
|
173
307
|
|
|
174
308
|
---
|
|
175
309
|
|
|
176
|
-
### `unitup add
|
|
310
|
+
### `unitup add`
|
|
177
311
|
|
|
178
312
|
Creates a new systemd user service unit file at `~/.config/systemd/user/unitup-<name>.service`.
|
|
179
313
|
|
|
180
314
|
```bash
|
|
181
|
-
unitup add
|
|
182
|
-
unitup add server.js --name api --env NODE_ENV=production --env PORT=3000 --start
|
|
315
|
+
unitup add worker.py --name worker --group backend --start
|
|
183
316
|
```
|
|
184
317
|
|
|
185
318
|
**Options:**
|
|
186
319
|
- `--name <name>`: Custom service name (defaults to script file name without extension).
|
|
187
|
-
- `--
|
|
320
|
+
- `--runtime <name>`: Specify runtime (`node`, `python`, `ruby`, `php`, `bun`, `deno`, `shell`, `go`, `elixir`, `native`).
|
|
321
|
+
- `--runtime-arg <val>`: Pass flag/argument to runtime binary (can be specified multiple times).
|
|
322
|
+
- `--command <path>`: Explicit binary executable path (bypasses auto-detection).
|
|
323
|
+
- `--arg <value>`: Script/command argument (can be specified multiple times).
|
|
324
|
+
- `--group <group>`: Assign service to a group (default: `default`).
|
|
188
325
|
- `--cwd <path>`: Working directory (defaults to script directory).
|
|
189
326
|
- `--env KEY=value`: Pass environment variable (can be specified multiple times).
|
|
190
|
-
- `--env-file <file>`:
|
|
191
|
-
- `--restart <policy>`: Systemd restart policy (`on-failure`, `always`, `no`, `on-abnormal
|
|
192
|
-
- `--arg <value>`: Script positional arguments (can be specified multiple times).
|
|
327
|
+
- `--env-file <file>`: Path to environment file (adds `EnvironmentFile=...`).
|
|
328
|
+
- `--restart <policy>`: Systemd restart policy (`on-failure`, `always`, `no`, `on-abnormal`. Default: `on-failure`).
|
|
193
329
|
- `--start`: Automatically enables and starts the service immediately (`systemctl --user enable --now`).
|
|
194
330
|
|
|
195
|
-
Generated unit file example (`~/.config/systemd/user/unitup-
|
|
331
|
+
Generated unit file example (`~/.config/systemd/user/unitup-worker.service`):
|
|
196
332
|
|
|
197
333
|
```ini
|
|
198
334
|
[Unit]
|
|
199
|
-
Description=unitup service:
|
|
335
|
+
Description=unitup service: worker
|
|
200
336
|
After=network.target
|
|
201
337
|
|
|
202
338
|
[Service]
|
|
203
339
|
Type=simple
|
|
204
|
-
|
|
205
|
-
|
|
340
|
+
SyslogIdentifier=unitup-worker
|
|
341
|
+
WorkingDirectory=/home/user/apps
|
|
342
|
+
ExecStart=/usr/bin/python3 /home/user/apps/worker.py
|
|
206
343
|
Restart=on-failure
|
|
207
344
|
RestartSec=3
|
|
208
|
-
EnvironmentFile=/home/user/projects/app/.env
|
|
209
345
|
Environment=PATH="/usr/bin:/usr/local/bin:/bin"
|
|
210
|
-
Environment=
|
|
211
|
-
Environment=PORT="3000"
|
|
346
|
+
Environment=APP_ENV="production"
|
|
212
347
|
|
|
213
348
|
[Install]
|
|
214
349
|
WantedBy=default.target
|
|
@@ -216,138 +351,188 @@ WantedBy=default.target
|
|
|
216
351
|
|
|
217
352
|
---
|
|
218
353
|
|
|
219
|
-
### `unitup
|
|
354
|
+
### `unitup list` / `unitup ls`
|
|
220
355
|
|
|
221
|
-
|
|
356
|
+
Lists all user services managed by `unitup`:
|
|
222
357
|
|
|
223
358
|
```bash
|
|
224
|
-
unitup
|
|
359
|
+
unitup list
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
NAME RUNTIME STATUS PID COMMAND
|
|
364
|
+
api node running 14220 node server.js
|
|
365
|
+
worker python running 14302 python3 worker.py
|
|
366
|
+
server native stopped - ./server
|
|
225
367
|
```
|
|
226
368
|
|
|
227
|
-
|
|
369
|
+
Filter by group:
|
|
228
370
|
|
|
229
371
|
```bash
|
|
230
|
-
unitup
|
|
372
|
+
unitup list --group backend
|
|
231
373
|
```
|
|
232
374
|
|
|
233
375
|
---
|
|
234
376
|
|
|
235
|
-
### `unitup
|
|
377
|
+
### `unitup inspect <name>`
|
|
236
378
|
|
|
237
|
-
|
|
379
|
+
View detailed configuration and status overview for a service (without revealing secrets or environment variables):
|
|
238
380
|
|
|
239
381
|
```bash
|
|
240
|
-
unitup
|
|
382
|
+
unitup inspect worker
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
```text
|
|
386
|
+
Name: worker
|
|
387
|
+
Runtime: python
|
|
388
|
+
Group: backend
|
|
389
|
+
Status: running
|
|
390
|
+
Command: /usr/bin/python3
|
|
391
|
+
Arguments: /home/user/apps/worker.py
|
|
392
|
+
Working directory: /home/user/apps
|
|
393
|
+
Unit: unitup-worker.service
|
|
241
394
|
```
|
|
242
395
|
|
|
243
396
|
---
|
|
244
397
|
|
|
245
|
-
### `unitup
|
|
398
|
+
### `unitup start <name|@group>`
|
|
246
399
|
|
|
247
|
-
|
|
400
|
+
Starts a service or an entire group:
|
|
248
401
|
|
|
249
402
|
```bash
|
|
250
|
-
unitup
|
|
403
|
+
unitup start worker
|
|
404
|
+
unitup start @backend --enable
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
### `unitup stop <name|@group>`
|
|
410
|
+
|
|
411
|
+
Stops a service or an entire group:
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
unitup stop @backend
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### `unitup restart <name|@group>`
|
|
420
|
+
|
|
421
|
+
Restarts a service or an entire group:
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
unitup restart worker
|
|
425
|
+
unitup restart @backend
|
|
251
426
|
```
|
|
252
427
|
|
|
253
428
|
---
|
|
254
429
|
|
|
255
430
|
### `unitup status <name>`
|
|
256
431
|
|
|
257
|
-
Shows
|
|
432
|
+
Shows compact status summary for the service:
|
|
258
433
|
|
|
259
434
|
```text
|
|
260
|
-
|
|
435
|
+
worker
|
|
261
436
|
|
|
262
437
|
Status: running
|
|
263
|
-
PID:
|
|
264
|
-
Started:
|
|
438
|
+
PID: 14302
|
|
439
|
+
Started: 15 minutes ago
|
|
265
440
|
Restarts: 0
|
|
266
|
-
|
|
267
|
-
|
|
441
|
+
Command: /usr/bin/python3
|
|
442
|
+
Arguments: /home/user/apps/worker.py
|
|
443
|
+
Working directory: /home/user/apps
|
|
268
444
|
```
|
|
269
445
|
|
|
270
|
-
|
|
446
|
+
Pass `--raw` for raw `systemctl status` output:
|
|
271
447
|
|
|
272
448
|
```bash
|
|
273
|
-
unitup status
|
|
449
|
+
unitup status worker --raw
|
|
274
450
|
```
|
|
275
451
|
|
|
276
452
|
---
|
|
277
453
|
|
|
278
454
|
### `unitup logs <name>`
|
|
279
455
|
|
|
280
|
-
View or stream systemd journalctl logs for a service
|
|
456
|
+
View or stream systemd journalctl logs for a service:
|
|
281
457
|
|
|
282
458
|
```bash
|
|
283
|
-
# View last 100 log lines (default)
|
|
284
|
-
unitup logs app
|
|
285
|
-
|
|
286
459
|
# Stream logs in real-time
|
|
287
|
-
unitup logs
|
|
288
|
-
|
|
289
|
-
# View last 50 lines of clean raw console output without systemd metadata prefix
|
|
290
|
-
unitup logs app -c --lines 50
|
|
291
|
-
# or
|
|
292
|
-
unitup logs app --cat --lines 50
|
|
460
|
+
unitup logs worker --follow
|
|
293
461
|
|
|
294
|
-
#
|
|
295
|
-
unitup logs
|
|
462
|
+
# Clean raw console output without systemd timestamp/hostname metadata prefix
|
|
463
|
+
unitup logs worker -c --lines 50
|
|
296
464
|
```
|
|
297
465
|
|
|
298
|
-
**Options:**
|
|
299
|
-
- `-f`, `--follow`: Stream logs in real time.
|
|
300
|
-
- `-n`, `--lines <N>`: Specify number of log lines to show (default: 100).
|
|
301
|
-
- `-c`, `--cat`: Format log output cleanly without systemd timestamp/hostname metadata prefix (`journalctl -o cat`).
|
|
302
|
-
- `--output <format>`: Custom journalctl output mode (e.g. `cat`, `short`, `json`).
|
|
303
|
-
|
|
304
466
|
---
|
|
305
467
|
|
|
306
|
-
### `unitup
|
|
468
|
+
### `unitup failures`
|
|
307
469
|
|
|
308
|
-
Lists all
|
|
470
|
+
Lists all currently failed services with exit codes and restart counts:
|
|
309
471
|
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
api running yes
|
|
313
|
-
worker stopped yes
|
|
314
|
-
cleanup failed no
|
|
472
|
+
```bash
|
|
473
|
+
unitup failures
|
|
315
474
|
```
|
|
316
475
|
|
|
317
476
|
---
|
|
318
477
|
|
|
319
|
-
### `unitup remove <name>`
|
|
478
|
+
### `unitup remove <name|@group>`
|
|
320
479
|
|
|
321
480
|
Stops, disables, and deletes the unit file, then reloads systemd:
|
|
322
481
|
|
|
323
482
|
```bash
|
|
324
|
-
unitup remove
|
|
483
|
+
unitup remove worker
|
|
484
|
+
unitup remove @backend
|
|
325
485
|
```
|
|
326
486
|
|
|
327
|
-
Equivalent systemctl commands executed:
|
|
328
|
-
1. `systemctl --user disable --now unitup-api.service`
|
|
329
|
-
2. Remove `~/.config/systemd/user/unitup-api.service`
|
|
330
|
-
3. `systemctl --user daemon-reload`
|
|
331
|
-
4. `systemctl --user reset-failed`
|
|
332
|
-
|
|
333
487
|
---
|
|
334
488
|
|
|
335
489
|
## User Lingering & Persistence Across Logout
|
|
336
490
|
|
|
337
|
-
|
|
491
|
+
Depending on the Linux distribution and systemd-logind configuration, user services may stop after logout. Enable lingering to allow them to continue running without an active login session:
|
|
338
492
|
|
|
339
493
|
```bash
|
|
340
494
|
loginctl enable-linger $USER
|
|
341
495
|
```
|
|
342
496
|
|
|
343
|
-
`unitup` checks this state in `unitup doctor` and warns if lingering is disabled. `unitup` will never attempt to run `loginctl` or `sudo` automatically on your behalf.
|
|
344
|
-
|
|
345
497
|
---
|
|
346
498
|
|
|
347
499
|
## Programmatic JavaScript & TypeScript API
|
|
348
500
|
|
|
349
501
|
`unitup` includes full TypeScript declaration files (`index.d.ts`). You can import `unitup` directly into JavaScript or TypeScript applications:
|
|
350
502
|
|
|
503
|
+
### Generic `command + args` Example (Language-Agnostic)
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
import { createService } from "unitup";
|
|
507
|
+
|
|
508
|
+
await createService({
|
|
509
|
+
name: "worker",
|
|
510
|
+
command: "/usr/bin/python3",
|
|
511
|
+
args: ["/home/user/apps/worker.py"],
|
|
512
|
+
cwd: "/home/user/apps",
|
|
513
|
+
restart: "on-failure",
|
|
514
|
+
start: true
|
|
515
|
+
});
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### CommonJS Support
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
const {
|
|
522
|
+
createService,
|
|
523
|
+
startService,
|
|
524
|
+
getServiceStatus
|
|
525
|
+
} = require("unitup");
|
|
526
|
+
|
|
527
|
+
await createService({
|
|
528
|
+
name: "api",
|
|
529
|
+
script: "./server.js",
|
|
530
|
+
start: true
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Script & Runtime Example
|
|
535
|
+
|
|
351
536
|
```ts
|
|
352
537
|
import {
|
|
353
538
|
createService,
|
|
@@ -357,33 +542,32 @@ import {
|
|
|
357
542
|
removeService,
|
|
358
543
|
getServiceStatus,
|
|
359
544
|
listServices,
|
|
360
|
-
|
|
545
|
+
inspectService,
|
|
546
|
+
detectRuntime,
|
|
547
|
+
resolveRuntimeConfig,
|
|
548
|
+
isSystemdAvailable
|
|
549
|
+
} from "unitup";
|
|
550
|
+
|
|
551
|
+
import type {
|
|
361
552
|
CreateServiceOptions,
|
|
362
553
|
ServiceStatus
|
|
363
554
|
} from "unitup";
|
|
364
555
|
|
|
365
|
-
// Check if systemd user services are available
|
|
366
556
|
if (await isSystemdAvailable()) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
557
|
+
// Add a Python worker service via script path
|
|
558
|
+
await createService({
|
|
559
|
+
name: "worker",
|
|
560
|
+
script: "./worker.py",
|
|
561
|
+
runtime: "python",
|
|
371
562
|
env: {
|
|
372
|
-
|
|
373
|
-
PORT: "3000"
|
|
563
|
+
APP_ENV: "production"
|
|
374
564
|
},
|
|
375
|
-
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
// Add a service
|
|
379
|
-
await createService(options);
|
|
565
|
+
start: true
|
|
566
|
+
});
|
|
380
567
|
|
|
381
|
-
//
|
|
382
|
-
await
|
|
383
|
-
|
|
384
|
-
// Get compact status
|
|
385
|
-
const status: ServiceStatus = await getServiceStatus("api");
|
|
386
|
-
console.log(`Service PID: ${status.pid}, Status: ${status.status}`);
|
|
568
|
+
// Inspect service configuration
|
|
569
|
+
const info = await inspectService("worker");
|
|
570
|
+
console.log(`Command: ${info.command}, Status: ${info.status}`);
|
|
387
571
|
|
|
388
572
|
// List all unitup services
|
|
389
573
|
const services = await listServices();
|
|
@@ -393,6 +577,49 @@ if (await isSystemdAvailable()) {
|
|
|
393
577
|
|
|
394
578
|
---
|
|
395
579
|
|
|
580
|
+
## Declarative Project Configuration (Roadmap Preview)
|
|
581
|
+
|
|
582
|
+
Define your application stack declaratively using `unitup.yml` or `unitup.json` and sync it with systemd user services:
|
|
583
|
+
|
|
584
|
+
```yaml
|
|
585
|
+
# unitup.yml
|
|
586
|
+
apps:
|
|
587
|
+
api:
|
|
588
|
+
runtime: node
|
|
589
|
+
script: ./server.js
|
|
590
|
+
env:
|
|
591
|
+
NODE_ENV: production
|
|
592
|
+
PORT: 3000
|
|
593
|
+
start: true
|
|
594
|
+
|
|
595
|
+
worker:
|
|
596
|
+
runtime: python
|
|
597
|
+
script: ./worker.py
|
|
598
|
+
env:
|
|
599
|
+
APP_ENV: production
|
|
600
|
+
|
|
601
|
+
native-service:
|
|
602
|
+
runtime: native
|
|
603
|
+
command: ./server
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
> *Note: Relative script, command, cwd, and env-file paths are resolved relative to the configuration file.*
|
|
607
|
+
|
|
608
|
+
### Planned Declarative Commands:
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
# Preview differences between unitup.yml and active systemd units
|
|
612
|
+
unitup diff
|
|
613
|
+
|
|
614
|
+
# Apply unitup.yml configuration and create/update systemd user services
|
|
615
|
+
unitup apply
|
|
616
|
+
|
|
617
|
+
# Perform batch operations on group
|
|
618
|
+
unitup restart @default
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
396
623
|
## License
|
|
397
624
|
|
|
398
625
|
[MIT](LICENSE)
|