unitup 0.0.9 → 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 CHANGED
@@ -1,12 +1,25 @@
1
1
  # unitup
2
2
 
3
- > Minimal, zero-dependency Node.js CLI & library to run Node.js scripts as `systemd` user services.
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
- ## `unitup` vs PM2: Key Differences and Core Promises
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)** | **None** (0 MB RAM). Systemd directly supervises processes. | **Yes** (PM2 master daemon consumes ~50-100 MB RAM in background). |
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
- | **Privileges Required** | Does **not** require `sudo`. | Requires `sudo` / `pm2 startup` for boot startup configuration. |
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
- ### What `unitup` Promises (Core Promises)
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. ⚡ **Zero Memory & CPU Waste**: After running `unitup` commands to add or manage a service, `unitup` exits immediately. No extra Node.js master process stays running in the background.
29
- 2. 🔒 **100% Transparency & Safety**: No hidden background tasks. Generated `.service` files are saved as standard text at `~/.config/systemd/user/` for easy inspection. 100% safe against shell injection.
30
- 3. 🛠ïļ **Automatic Path & Environment Resolution**: Automatically detects `PATH` issues common with NVM, FNM, or custom Node.js installations and injects the resolved `PATH` environment into the unit file.
31
- 4. ðŸŠķ **Ultra Lightweight Footprint**: Zero bloat for your project or server; installs instantly and runs with minimal overhead.
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
- ### What `unitup` Does NOT Do (Non-Goals)
63
+ ---
34
64
 
35
- - ❌ Does not write a custom daemon or process watcher system (does not attempt to behave like PM2).
36
- - ❌ No PM2 Cluster Mode (internal load balancing). Use Nginx, HAProxy, or Node.js native `cluster` module instead.
37
- - ❌ No web dashboard, metrics panel, or telemetry.
38
- - ❌ Does not manage or rotate log files directly; delegates 100% of logging to OS-level `journald`.
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** — ultra lightweight native ESM Node 20+ package.
45
- - 🔒 **No root / sudo required** — operates entirely within systemd user scope (`~/.config/systemd/user/`).
46
- - ðŸ›Ąïļ **Secure by design** — systemd escaping, strict service name sanitization, and shell-injection safe command execution (`execFile`/`spawn` with `shell: false`).
47
- - ðŸĐš **System readiness check** — `unitup doctor` verifies OS, systemd PID 1, systemctl user bus, and user lingering state.
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,155 +155,195 @@ npm install unitup
72
155
 
73
156
  ---
74
157
 
75
- ## Quick Start
158
+ ## CLI Usage
159
+
160
+ ### Multi-Runtime Examples
76
161
 
77
162
  ```bash
78
- # 1. Verify system readiness
79
- unitup doctor
163
+ # Node.js
164
+ unitup add server.js --runtime node
80
165
 
81
- # 2. Add Node.js scripts and assign to groups
82
- unitup add server.js --name api --group myproject --env-file .env --start
83
- unitup add worker.js --name worker --group myproject --start
166
+ # Python
167
+ unitup add worker.py --runtime python
84
168
 
85
- # 3. List all services with status, PID, uptime, restarts
86
- unitup list
87
- # or alias
88
- unitup ls --group myproject
169
+ # Ruby
170
+ unitup add app.rb --runtime ruby
89
171
 
90
- # 4. Perform batch control operations on a group using @group syntax
91
- unitup restart @myproject
92
- unitup stop @myproject
172
+ # PHP (with runtime flags)
173
+ unitup add index.php --runtime php --runtime-arg -S --runtime-arg 0.0.0.0:8080
93
174
 
94
- # 5. Inspect application configuration and status (excluding secrets)
95
- unitup inspect api
175
+ # Bun
176
+ unitup add server.ts --runtime bun
96
177
 
97
- # 6. Check for failed services
98
- unitup failures
178
+ # Deno (with runtime permission flags)
179
+ unitup add server.ts --runtime deno --runtime-arg --allow-net --runtime-arg --allow-env
180
+
181
+ # Go
182
+ unitup add main.go --runtime go
183
+
184
+ # Elixir
185
+ unitup add app.exs --runtime elixir
99
186
 
100
- # 7. Stream logs or view clean console output
101
- unitup logs api -c --follow
187
+ # Native Executable
188
+ unitup add ./server --runtime native --name api
102
189
 
103
- # 8. Remove a service or an entire group
104
- unitup remove @myproject
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
105
197
  ```
106
198
 
199
+ > *Note: For production deployments, compiling the Go application and registering the resulting native binary is recommended.*
200
+
107
201
  ---
108
202
 
109
- ## CLI Commands
203
+ ## Automatic Runtime & Shebang Detection
110
204
 
111
- ### `unitup doctor`
205
+ `unitup` automatically detects the runtime based on file extension and shebang headers:
112
206
 
113
- Performs comprehensive system and Node.js runtime diagnostic checks:
114
- - OS check (Linux)
115
- - `systemctl` executable availability
116
- - PID 1 systemd verification
117
- - Systemd user bus accessibility
118
- - Node.js executable PATH resolution (`which node`, `command -v`, `process.execPath`)
119
- - Node.js binary execution capability (`node -v`)
120
- - Unit directory write permissions (`~/.config/systemd/user/`)
121
- - User lingering state (`loginctl enable-linger`)
122
-
123
- Example output:
124
207
  ```text
125
- unitup doctor
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
+ ```
126
216
 
127
- ✓ Linux detected
128
- ✓ systemctl available
129
- ✓ systemd is running
130
- ✓ systemd user services available
131
- ✓ Node.js: /usr/bin/node
132
- ✓ Node version: v20.11.0
133
- ✓ PATH includes node
134
- ! User lingering is disabled
217
+ Shebang examples detected automatically:
135
218
 
136
- User lingering is disabled.
137
- The service may stop after logout.
219
+ ```text
220
+ #!/usr/bin/env python3
221
+ #!/usr/bin/env node
222
+ #!/usr/bin/env ruby
223
+ #!/bin/bash
224
+ ```
138
225
 
139
- Enable it manually:
140
- loginctl enable-linger username
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
141
235
  ```
142
236
 
143
237
  ---
144
238
 
145
- ### Diagnosing Node.js Runtime & Path Problems
239
+ ## Native Executable Support
146
240
 
147
- `unitup` automatically detects and diagnoses Node.js installation issues before creating services.
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:
148
253
 
149
- #### 1. Node.js not found in PATH
150
254
  ```text
151
- ✗ Node.js not found in PATH
255
+ The executable is not runnable.
152
256
 
153
- Install Node.js:
154
- https://nodejs.org
155
- or via package manager:
156
- sudo apt install nodejs
257
+ Run:
258
+ chmod +x /home/user/apps/server
157
259
  ```
158
260
 
159
- #### 2. Node.js binary exists but is not executable
261
+ ---
262
+
263
+ ## CLI Commands Reference
264
+
265
+ ### `unitup doctor`
266
+
267
+ Performs comprehensive system readiness and runtime diagnostic checks:
268
+
160
269
  ```text
161
- ✗ Node.js binary exists but is not executable
270
+ unitup doctor
162
271
 
163
- Check permissions:
164
- chmod +x $(which node)
165
- ```
272
+ ✓ Linux detected
273
+ ✓ systemctl available
274
+ ✓ systemd is running
275
+ ✓ systemd user services available
166
276
 
167
- #### 3. Resolving custom or nvm Node.js executable paths
168
- Systemd services execute in a minimal environment. To ensure systemd finds `node` regardless of user PATH setup (nvm, fnm, etc.), `unitup` resolves absolute paths and automatically injects a `PATH` environment directive into every generated unit file:
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
169
288
 
170
- ```ini
171
- [Service]
172
- Type=simple
173
- WorkingDirectory=/home/user/projects/app
174
- Environment=PATH="/home/user/.nvm/versions/node/v20.11.0/bin:/usr/local/bin:/usr/bin:/bin"
175
- 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
176
291
  ```
177
292
 
178
- You can also specify an explicit Node.js binary path when creating a service:
293
+ *Note: Missing optional runtimes do not cause `unitup doctor` to exit with an error.*
179
294
 
180
- ```bash
181
- unitup add app.js --node /usr/bin/node
182
- ```
295
+ ---
183
296
 
184
- If Node.js cannot be resolved, `unitup add` will safely abort and request that you run `unitup doctor`.
297
+ ### Missing Runtime Handling
298
+
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
+ ```
185
307
 
186
308
  ---
187
309
 
188
- ### `unitup add <script>`
310
+ ### `unitup add`
189
311
 
190
312
  Creates a new systemd user service unit file at `~/.config/systemd/user/unitup-<name>.service`.
191
313
 
192
314
  ```bash
193
- unitup add app.js
194
- unitup add server.js --name api --env NODE_ENV=production --env PORT=3000 --start
315
+ unitup add worker.py --name worker --group backend --start
195
316
  ```
196
317
 
197
318
  **Options:**
198
319
  - `--name <name>`: Custom service name (defaults to script file name without extension).
199
- - `--node <path>`: Explicit Node.js executable path.
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`).
200
325
  - `--cwd <path>`: Working directory (defaults to script directory).
201
326
  - `--env KEY=value`: Pass environment variable (can be specified multiple times).
202
- - `--env-file <file>`: Absolute or relative path to environment file (adds `EnvironmentFile=...`).
203
- - `--restart <policy>`: Systemd restart policy (`on-failure`, `always`, `no`, `on-abnormal`, etc. Default: `on-failure`).
204
- - `--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`).
205
329
  - `--start`: Automatically enables and starts the service immediately (`systemctl --user enable --now`).
206
330
 
207
- Generated unit file example (`~/.config/systemd/user/unitup-api.service`):
331
+ Generated unit file example (`~/.config/systemd/user/unitup-worker.service`):
208
332
 
209
333
  ```ini
210
334
  [Unit]
211
- Description=unitup service: api
335
+ Description=unitup service: worker
212
336
  After=network.target
213
337
 
214
338
  [Service]
215
339
  Type=simple
216
- WorkingDirectory=/home/user/projects/app
217
- ExecStart=/usr/bin/node /home/user/projects/app/server.js
340
+ SyslogIdentifier=unitup-worker
341
+ WorkingDirectory=/home/user/apps
342
+ ExecStart=/usr/bin/python3 /home/user/apps/worker.py
218
343
  Restart=on-failure
219
344
  RestartSec=3
220
- EnvironmentFile=/home/user/projects/app/.env
221
345
  Environment=PATH="/usr/bin:/usr/local/bin:/bin"
222
- Environment=NODE_ENV="production"
223
- Environment=PORT="3000"
346
+ Environment=APP_ENV="production"
224
347
 
225
348
  [Install]
226
349
  WantedBy=default.target
@@ -228,138 +351,188 @@ WantedBy=default.target
228
351
 
229
352
  ---
230
353
 
231
- ### `unitup start <name>`
354
+ ### `unitup list` / `unitup ls`
232
355
 
233
- Starts an existing service unit.
356
+ Lists all user services managed by `unitup`:
234
357
 
235
358
  ```bash
236
- unitup start api
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
237
367
  ```
238
368
 
239
- Pass `--enable` to enable the service to start automatically on system boot:
369
+ Filter by group:
370
+
371
+ ```bash
372
+ unitup list --group backend
373
+ ```
374
+
375
+ ---
376
+
377
+ ### `unitup inspect <name>`
378
+
379
+ View detailed configuration and status overview for a service (without revealing secrets or environment variables):
380
+
381
+ ```bash
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
394
+ ```
395
+
396
+ ---
397
+
398
+ ### `unitup start <name|@group>`
399
+
400
+ Starts a service or an entire group:
240
401
 
241
402
  ```bash
242
- unitup start api --enable
403
+ unitup start worker
404
+ unitup start @backend --enable
243
405
  ```
244
406
 
245
407
  ---
246
408
 
247
- ### `unitup stop <name>`
409
+ ### `unitup stop <name|@group>`
248
410
 
249
- Stops a running service:
411
+ Stops a service or an entire group:
250
412
 
251
413
  ```bash
252
- unitup stop api
414
+ unitup stop @backend
253
415
  ```
254
416
 
255
417
  ---
256
418
 
257
- ### `unitup restart <name>`
419
+ ### `unitup restart <name|@group>`
258
420
 
259
- Restarts a service:
421
+ Restarts a service or an entire group:
260
422
 
261
423
  ```bash
262
- unitup restart api
424
+ unitup restart worker
425
+ unitup restart @backend
263
426
  ```
264
427
 
265
428
  ---
266
429
 
267
430
  ### `unitup status <name>`
268
431
 
269
- Shows a compact status summary for the service:
432
+ Shows compact status summary for the service:
270
433
 
271
434
  ```text
272
- api
435
+ worker
273
436
 
274
437
  Status: running
275
- PID: 14220
276
- Started: 12 minutes ago
438
+ PID: 14302
439
+ Started: 15 minutes ago
277
440
  Restarts: 0
278
- Script: /home/user/projects/app/server.js
279
- Working directory: /home/user/projects/app
441
+ Command: /usr/bin/python3
442
+ Arguments: /home/user/apps/worker.py
443
+ Working directory: /home/user/apps
280
444
  ```
281
445
 
282
- To view systemctl's raw output, pass `--raw`:
446
+ Pass `--raw` for raw `systemctl status` output:
283
447
 
284
448
  ```bash
285
- unitup status api --raw
449
+ unitup status worker --raw
286
450
  ```
287
451
 
288
452
  ---
289
453
 
290
454
  ### `unitup logs <name>`
291
455
 
292
- View or stream systemd journalctl logs for a service.
456
+ View or stream systemd journalctl logs for a service:
293
457
 
294
458
  ```bash
295
- # View last 100 log lines (default)
296
- unitup logs app
297
-
298
459
  # Stream logs in real-time
299
- unitup logs app --follow
300
-
301
- # View last 50 lines of clean raw console output without systemd metadata prefix
302
- unitup logs app -c --lines 50
303
- # or
304
- unitup logs app --cat --lines 50
460
+ unitup logs worker --follow
305
461
 
306
- # Specify custom journalctl output format
307
- unitup logs app --output=json
462
+ # Clean raw console output without systemd timestamp/hostname metadata prefix
463
+ unitup logs worker -c --lines 50
308
464
  ```
309
465
 
310
- **Options:**
311
- - `-f`, `--follow`: Stream logs in real time.
312
- - `-n`, `--lines <N>`: Specify number of log lines to show (default: 100).
313
- - `-c`, `--cat`: Format log output cleanly without systemd timestamp/hostname metadata prefix (`journalctl -o cat`).
314
- - `--output <format>`: Custom journalctl output mode (e.g. `cat`, `short`, `json`).
315
-
316
466
  ---
317
467
 
318
- ### `unitup list`
468
+ ### `unitup failures`
319
469
 
320
- Lists all user services managed by `unitup` (`unitup-*.service`):
470
+ Lists all currently failed services with exit codes and restart counts:
321
471
 
322
- ```text
323
- NAME STATUS ENABLED
324
- api running yes
325
- worker stopped yes
326
- cleanup failed no
472
+ ```bash
473
+ unitup failures
327
474
  ```
328
475
 
329
476
  ---
330
477
 
331
- ### `unitup remove <name>`
478
+ ### `unitup remove <name|@group>`
332
479
 
333
480
  Stops, disables, and deletes the unit file, then reloads systemd:
334
481
 
335
482
  ```bash
336
- unitup remove api
483
+ unitup remove worker
484
+ unitup remove @backend
337
485
  ```
338
486
 
339
- Equivalent systemctl commands executed:
340
- 1. `systemctl --user disable --now unitup-api.service`
341
- 2. Remove `~/.config/systemd/user/unitup-api.service`
342
- 3. `systemctl --user daemon-reload`
343
- 4. `systemctl --user reset-failed`
344
-
345
487
  ---
346
488
 
347
489
  ## User Lingering & Persistence Across Logout
348
490
 
349
- By default, Linux systemd terminates user processes when a user logs out. To allow your Node.js services to run continuously in the background after logout or system startup, enable **user lingering**:
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:
350
492
 
351
493
  ```bash
352
494
  loginctl enable-linger $USER
353
495
  ```
354
496
 
355
- `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.
356
-
357
497
  ---
358
498
 
359
499
  ## Programmatic JavaScript & TypeScript API
360
500
 
361
501
  `unitup` includes full TypeScript declaration files (`index.d.ts`). You can import `unitup` directly into JavaScript or TypeScript applications:
362
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
+
363
536
  ```ts
364
537
  import {
365
538
  createService,
@@ -369,33 +542,32 @@ import {
369
542
  removeService,
370
543
  getServiceStatus,
371
544
  listServices,
372
- isSystemdAvailable,
545
+ inspectService,
546
+ detectRuntime,
547
+ resolveRuntimeConfig,
548
+ isSystemdAvailable
549
+ } from "unitup";
550
+
551
+ import type {
373
552
  CreateServiceOptions,
374
553
  ServiceStatus
375
554
  } from "unitup";
376
555
 
377
- // Check if systemd user services are available
378
556
  if (await isSystemdAvailable()) {
379
- const options: CreateServiceOptions = {
380
- name: "api",
381
- script: "./server.js",
382
- cwd: process.cwd(),
557
+ // Add a Python worker service via script path
558
+ await createService({
559
+ name: "worker",
560
+ script: "./worker.py",
561
+ runtime: "python",
383
562
  env: {
384
- NODE_ENV: "production",
385
- PORT: "3000"
563
+ APP_ENV: "production"
386
564
  },
387
- restart: "on-failure"
388
- };
389
-
390
- // Add a service
391
- await createService(options);
565
+ start: true
566
+ });
392
567
 
393
- // Start the service
394
- await startService("api");
395
-
396
- // Get compact status
397
- const status: ServiceStatus = await getServiceStatus("api");
398
- 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}`);
399
571
 
400
572
  // List all unitup services
401
573
  const services = await listServices();
@@ -405,6 +577,49 @@ if (await isSystemdAvailable()) {
405
577
 
406
578
  ---
407
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
+
408
623
  ## License
409
624
 
410
625
  [MIT](LICENSE)