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 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,143 +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
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
- # 2. Add your Node.js script as a user service and start it immediately
82
- unitup add server.js --name api --env-file .env --start
178
+ # Deno (with runtime permission flags)
179
+ unitup add server.ts --runtime deno --runtime-arg --allow-net --runtime-arg --allow-env
83
180
 
84
- # 3. Check service status
85
- unitup status api
181
+ # Go
182
+ unitup add main.go --runtime go
86
183
 
87
- # 4. Stream real-time journalctl logs
88
- unitup logs api --follow
184
+ # Elixir
185
+ unitup add app.exs --runtime elixir
89
186
 
90
- # 5. Stop or remove service when no longer needed
91
- unitup stop api
92
- unitup remove api
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
- ## CLI Commands
203
+ ## Automatic Runtime & Shebang Detection
98
204
 
99
- ### `unitup doctor`
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
- 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
+ ```
114
216
 
115
- ✓ Linux detected
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
- User lingering is disabled.
125
- 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
+ ```
126
225
 
127
- Enable it manually:
128
- 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
129
235
  ```
130
236
 
131
237
  ---
132
238
 
133
- ### Diagnosing Node.js Runtime & Path Problems
239
+ ## Native Executable Support
134
240
 
135
- `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:
136
253
 
137
- #### 1. Node.js not found in PATH
138
254
  ```text
139
- ✗ Node.js not found in PATH
255
+ The executable is not runnable.
140
256
 
141
- Install Node.js:
142
- https://nodejs.org
143
- or via package manager:
144
- sudo apt install nodejs
257
+ Run:
258
+ chmod +x /home/user/apps/server
145
259
  ```
146
260
 
147
- #### 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
+
148
269
  ```text
149
- ✗ Node.js binary exists but is not executable
270
+ unitup doctor
150
271
 
151
- Check permissions:
152
- chmod +x $(which node)
153
- ```
272
+ ✓ Linux detected
273
+ ✓ systemctl available
274
+ ✓ systemd is running
275
+ ✓ systemd user services available
154
276
 
155
- #### 3. Resolving custom or nvm Node.js executable paths
156
- 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
157
288
 
158
- ```ini
159
- [Service]
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
- 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.*
167
294
 
168
- ```bash
169
- unitup add app.js --node /usr/bin/node
170
- ```
295
+ ---
296
+
297
+ ### Missing Runtime Handling
171
298
 
172
- If Node.js cannot be resolved, `unitup add` will safely abort and request that you run `unitup doctor`.
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 <script>`
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 app.js
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
- - `--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`).
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>`: Absolute or relative path to environment file (adds `EnvironmentFile=...`).
191
- - `--restart <policy>`: Systemd restart policy (`on-failure`, `always`, `no`, `on-abnormal`, etc. Default: `on-failure`).
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-api.service`):
331
+ Generated unit file example (`~/.config/systemd/user/unitup-worker.service`):
196
332
 
197
333
  ```ini
198
334
  [Unit]
199
- Description=unitup service: api
335
+ Description=unitup service: worker
200
336
  After=network.target
201
337
 
202
338
  [Service]
203
339
  Type=simple
204
- WorkingDirectory=/home/user/projects/app
205
- 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
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=NODE_ENV="production"
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 start <name>`
354
+ ### `unitup list` / `unitup ls`
220
355
 
221
- Starts an existing service unit.
356
+ Lists all user services managed by `unitup`:
222
357
 
223
358
  ```bash
224
- 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
225
367
  ```
226
368
 
227
- Pass `--enable` to enable the service to start automatically on system boot:
369
+ Filter by group:
228
370
 
229
371
  ```bash
230
- unitup start api --enable
372
+ unitup list --group backend
231
373
  ```
232
374
 
233
375
  ---
234
376
 
235
- ### `unitup stop <name>`
377
+ ### `unitup inspect <name>`
236
378
 
237
- Stops a running service:
379
+ View detailed configuration and status overview for a service (without revealing secrets or environment variables):
238
380
 
239
381
  ```bash
240
- unitup stop api
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 restart <name>`
398
+ ### `unitup start <name|@group>`
246
399
 
247
- Restarts a service:
400
+ Starts a service or an entire group:
248
401
 
249
402
  ```bash
250
- unitup restart api
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 a compact status summary for the service:
432
+ Shows compact status summary for the service:
258
433
 
259
434
  ```text
260
- api
435
+ worker
261
436
 
262
437
  Status: running
263
- PID: 14220
264
- Started: 12 minutes ago
438
+ PID: 14302
439
+ Started: 15 minutes ago
265
440
  Restarts: 0
266
- Script: /home/user/projects/app/server.js
267
- Working directory: /home/user/projects/app
441
+ Command: /usr/bin/python3
442
+ Arguments: /home/user/apps/worker.py
443
+ Working directory: /home/user/apps
268
444
  ```
269
445
 
270
- To view systemctl's raw output, pass `--raw`:
446
+ Pass `--raw` for raw `systemctl status` output:
271
447
 
272
448
  ```bash
273
- unitup status api --raw
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 app --follow
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
- # Specify custom journalctl output format
295
- unitup logs app --output=json
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 list`
468
+ ### `unitup failures`
307
469
 
308
- Lists all user services managed by `unitup` (`unitup-*.service`):
470
+ Lists all currently failed services with exit codes and restart counts:
309
471
 
310
- ```text
311
- NAME STATUS ENABLED
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 api
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
- 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:
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
- isSystemdAvailable,
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
- const options: CreateServiceOptions = {
368
- name: "api",
369
- script: "./server.js",
370
- 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",
371
562
  env: {
372
- NODE_ENV: "production",
373
- PORT: "3000"
563
+ APP_ENV: "production"
374
564
  },
375
- restart: "on-failure"
376
- };
377
-
378
- // Add a service
379
- await createService(options);
565
+ start: true
566
+ });
380
567
 
381
- // Start the service
382
- await startService("api");
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)