unitup 0.0.9 → 0.0.11

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,196 @@ 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
99
183
 
100
- # 7. Stream logs or view clean console output
101
- unitup logs api -c --follow
184
+ # Elixir
185
+ unitup add app.exs --runtime elixir
102
186
 
103
- # 8. Remove a service or an entire group
104
- unitup remove @myproject
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
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
+ ---
296
+
297
+ ### Missing Runtime Handling
183
298
 
184
- 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
+ ```
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`).
330
+ - `--force`, `-f`: Force overwrite of an existing service if it is currently running.
206
331
 
207
- Generated unit file example (`~/.config/systemd/user/unitup-api.service`):
332
+ Generated unit file example (`~/.config/systemd/user/unitup-worker.service`):
208
333
 
209
334
  ```ini
210
335
  [Unit]
211
- Description=unitup service: api
336
+ Description=unitup service: worker
212
337
  After=network.target
213
338
 
214
339
  [Service]
215
340
  Type=simple
216
- WorkingDirectory=/home/user/projects/app
217
- ExecStart=/usr/bin/node /home/user/projects/app/server.js
341
+ SyslogIdentifier=unitup-worker
342
+ WorkingDirectory=/home/user/apps
343
+ ExecStart=/usr/bin/python3 /home/user/apps/worker.py
218
344
  Restart=on-failure
219
345
  RestartSec=3
220
- EnvironmentFile=/home/user/projects/app/.env
221
346
  Environment=PATH="/usr/bin:/usr/local/bin:/bin"
222
- Environment=NODE_ENV="production"
223
- Environment=PORT="3000"
347
+ Environment=APP_ENV="production"
224
348
 
225
349
  [Install]
226
350
  WantedBy=default.target
@@ -228,138 +352,192 @@ WantedBy=default.target
228
352
 
229
353
  ---
230
354
 
231
- ### `unitup start <name>`
355
+ ### `unitup list` / `unitup ls`
232
356
 
233
- Starts an existing service unit.
357
+ Lists all user services managed by `unitup`:
234
358
 
235
359
  ```bash
236
- unitup start api
360
+ unitup list
237
361
  ```
238
362
 
239
- Pass `--enable` to enable the service to start automatically on system boot:
363
+ ```text
364
+ NAME RUNTIME STATUS PID COMMAND
365
+ api node running 14220 node server.js
366
+ worker python running 14302 python3 worker.py
367
+ server native stopped - ./server
368
+ ```
369
+
370
+ Filter by group:
371
+
372
+ ```bash
373
+ unitup list --group backend
374
+ ```
375
+
376
+ ---
377
+
378
+ ### `unitup inspect <name>`
379
+
380
+ View detailed configuration and status overview for a service (without revealing secrets or environment variables):
381
+
382
+ ```bash
383
+ unitup inspect worker
384
+ ```
385
+
386
+ ```text
387
+ Name: worker
388
+ Runtime: python
389
+ Group: backend
390
+ Status: running
391
+ Command: /usr/bin/python3
392
+ Arguments: /home/user/apps/worker.py
393
+ Working directory: /home/user/apps
394
+ Unit: unitup-worker.service
395
+ ```
396
+
397
+ ---
398
+
399
+ ### `unitup start <name|@group>`
400
+
401
+ Starts a service or an entire group:
240
402
 
241
403
  ```bash
242
- unitup start api --enable
404
+ unitup start worker
405
+ unitup start @backend --enable
243
406
  ```
244
407
 
245
408
  ---
246
409
 
247
- ### `unitup stop <name>`
410
+ ### `unitup stop <name|@group>`
248
411
 
249
- Stops a running service:
412
+ Stops a service or an entire group:
250
413
 
251
414
  ```bash
252
- unitup stop api
415
+ unitup stop @backend
253
416
  ```
254
417
 
255
418
  ---
256
419
 
257
- ### `unitup restart <name>`
420
+ ### `unitup restart <name|@group>`
258
421
 
259
- Restarts a service:
422
+ Restarts a service or an entire group:
260
423
 
261
424
  ```bash
262
- unitup restart api
425
+ unitup restart worker
426
+ unitup restart @backend
263
427
  ```
264
428
 
265
429
  ---
266
430
 
267
431
  ### `unitup status <name>`
268
432
 
269
- Shows a compact status summary for the service:
433
+ Shows compact status summary for the service:
270
434
 
271
435
  ```text
272
- api
436
+ worker
273
437
 
274
438
  Status: running
275
- PID: 14220
276
- Started: 12 minutes ago
439
+ PID: 14302
440
+ Started: 15 minutes ago
277
441
  Restarts: 0
278
- Script: /home/user/projects/app/server.js
279
- Working directory: /home/user/projects/app
442
+ Command: /usr/bin/python3
443
+ Arguments: /home/user/apps/worker.py
444
+ Working directory: /home/user/apps
280
445
  ```
281
446
 
282
- To view systemctl's raw output, pass `--raw`:
447
+ Pass `--raw` for raw `systemctl status` output:
283
448
 
284
449
  ```bash
285
- unitup status api --raw
450
+ unitup status worker --raw
286
451
  ```
287
452
 
288
453
  ---
289
454
 
290
455
  ### `unitup logs <name>`
291
456
 
292
- View or stream systemd journalctl logs for a service.
457
+ View or stream systemd journalctl logs for a service:
293
458
 
294
459
  ```bash
295
- # View last 100 log lines (default)
296
- unitup logs app
297
-
298
460
  # 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
461
+ unitup logs worker --follow
305
462
 
306
- # Specify custom journalctl output format
307
- unitup logs app --output=json
463
+ # Clean raw console output without systemd timestamp/hostname metadata prefix
464
+ unitup logs worker -c --lines 50
308
465
  ```
309
466
 
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
467
  ---
317
468
 
318
- ### `unitup list`
469
+ ### `unitup failures`
319
470
 
320
- Lists all user services managed by `unitup` (`unitup-*.service`):
471
+ Lists all currently failed services with exit codes and restart counts:
321
472
 
322
- ```text
323
- NAME STATUS ENABLED
324
- api running yes
325
- worker stopped yes
326
- cleanup failed no
473
+ ```bash
474
+ unitup failures
327
475
  ```
328
476
 
329
477
  ---
330
478
 
331
- ### `unitup remove <name>`
479
+ ### `unitup remove <name|@group>`
332
480
 
333
- Stops, disables, and deletes the unit file, then reloads systemd:
481
+ Stops, disables, and deletes the unit file, then reloads systemd. If the service is currently running, `unitup` prevents accidental deletion and requires `--force` / `-f`:
334
482
 
335
483
  ```bash
336
- unitup remove api
337
- ```
484
+ # Remove stopped service
485
+ unitup remove worker
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`
487
+ # Force remove an actively running service or group
488
+ unitup remove worker --force
489
+ unitup remove @backend -f
490
+ ```
344
491
 
345
492
  ---
346
493
 
347
494
  ## User Lingering & Persistence Across Logout
348
495
 
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**:
496
+ 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
497
 
351
498
  ```bash
352
499
  loginctl enable-linger $USER
353
500
  ```
354
501
 
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
502
  ---
358
503
 
359
504
  ## Programmatic JavaScript & TypeScript API
360
505
 
361
506
  `unitup` includes full TypeScript declaration files (`index.d.ts`). You can import `unitup` directly into JavaScript or TypeScript applications:
362
507
 
508
+ ### Generic `command + args` Example (Language-Agnostic)
509
+
510
+ ```ts
511
+ import { createService } from "unitup";
512
+
513
+ await createService({
514
+ name: "worker",
515
+ command: "/usr/bin/python3",
516
+ args: ["/home/user/apps/worker.py"],
517
+ cwd: "/home/user/apps",
518
+ restart: "on-failure",
519
+ start: true
520
+ });
521
+ ```
522
+
523
+ ### CommonJS Support
524
+
525
+ ```js
526
+ const {
527
+ createService,
528
+ startService,
529
+ getServiceStatus
530
+ } = require("unitup");
531
+
532
+ await createService({
533
+ name: "api",
534
+ script: "./server.js",
535
+ start: true
536
+ });
537
+ ```
538
+
539
+ ### Script & Runtime Example
540
+
363
541
  ```ts
364
542
  import {
365
543
  createService,
@@ -369,33 +547,32 @@ import {
369
547
  removeService,
370
548
  getServiceStatus,
371
549
  listServices,
372
- isSystemdAvailable,
550
+ inspectService,
551
+ detectRuntime,
552
+ resolveRuntimeConfig,
553
+ isSystemdAvailable
554
+ } from "unitup";
555
+
556
+ import type {
373
557
  CreateServiceOptions,
374
558
  ServiceStatus
375
559
  } from "unitup";
376
560
 
377
- // Check if systemd user services are available
378
561
  if (await isSystemdAvailable()) {
379
- const options: CreateServiceOptions = {
380
- name: "api",
381
- script: "./server.js",
382
- cwd: process.cwd(),
562
+ // Add a Python worker service via script path
563
+ await createService({
564
+ name: "worker",
565
+ script: "./worker.py",
566
+ runtime: "python",
383
567
  env: {
384
- NODE_ENV: "production",
385
- PORT: "3000"
568
+ APP_ENV: "production"
386
569
  },
387
- restart: "on-failure"
388
- };
389
-
390
- // Add a service
391
- await createService(options);
570
+ start: true
571
+ });
392
572
 
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}`);
573
+ // Inspect service configuration
574
+ const info = await inspectService("worker");
575
+ console.log(`Command: ${info.command}, Status: ${info.status}`);
399
576
 
400
577
  // List all unitup services
401
578
  const services = await listServices();
@@ -405,6 +582,49 @@ if (await isSystemdAvailable()) {
405
582
 
406
583
  ---
407
584
 
585
+ ## Declarative Project Configuration (Roadmap Preview)
586
+
587
+ Define your application stack declaratively using `unitup.yml` or `unitup.json` and sync it with systemd user services:
588
+
589
+ ```yaml
590
+ # unitup.yml
591
+ apps:
592
+ api:
593
+ runtime: node
594
+ script: ./server.js
595
+ env:
596
+ NODE_ENV: production
597
+ PORT: 3000
598
+ start: true
599
+
600
+ worker:
601
+ runtime: python
602
+ script: ./worker.py
603
+ env:
604
+ APP_ENV: production
605
+
606
+ native-service:
607
+ runtime: native
608
+ command: ./server
609
+ ```
610
+
611
+ > *Note: Relative script, command, cwd, and env-file paths are resolved relative to the configuration file.*
612
+
613
+ ### Planned Declarative Commands:
614
+
615
+ ```bash
616
+ # Preview differences between unitup.yml and active systemd units
617
+ unitup diff
618
+
619
+ # Apply unitup.yml configuration and create/update systemd user services
620
+ unitup apply
621
+
622
+ # Perform batch operations on group
623
+ unitup restart @default
624
+ ```
625
+
626
+ ---
627
+
408
628
  ## License
409
629
 
410
630
  [MIT](LICENSE)