unitup 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 unitup contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR A PARTICULAR PURPOSE AND CLAIM,
19
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,387 @@
1
+ # unitup
2
+
3
+ > Minimal, zero-dependency Node.js CLI & library to run Node.js scripts as `systemd` user services.
4
+
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
+
7
+ ---
8
+
9
+ ## `unitup` vs PM2: Key Differences and Core Promises
10
+
11
+ `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
+
13
+ ### Comparison Table
14
+
15
+ | Feature | `unitup` | PM2 |
16
+ | :--- | :--- | :--- |
17
+ | **Background Process (Daemon)** | **None** (0 MB RAM). Systemd directly supervises processes. | **Yes** (PM2 master daemon consumes ~50-100 MB RAM in background). |
18
+ | **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. |
20
+ | **Dependencies** | **0 Runtime Dependencies** (Uses Node.js standard modules only). | Dozens of 3rd party npm packages. |
21
+ | **Log Management** | Delegates to native Linux `journald` system (`journalctl`). | Manages `.pm2/logs` files (requires `pm2-logrotate` for rotation). |
22
+ | **Boot Startup** | Native systemd lingering (`loginctl enable-linger`). | Custom startup script launching PM2 daemon. |
23
+
24
+ ---
25
+
26
+ ### What `unitup` Promises (Core Promises)
27
+
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.
32
+
33
+ ### What `unitup` Does NOT Do (Non-Goals)
34
+
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`.
39
+
40
+ ---
41
+
42
+ ## Features
43
+
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.
48
+ - 📋 **Compact status & logs** — clean summary output from `systemctl show` and live `journalctl` streaming.
49
+ - ðŸ“Ķ **Programmatic API** — imported directly into JavaScript applications.
50
+
51
+ ---
52
+
53
+ ## Requirements
54
+
55
+ - **OS:** Linux with `systemd`
56
+ - **Node.js:** `>= 20.0.0`
57
+ - **Permissions:** Standard non-root user session
58
+
59
+ ---
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ npm install -g unitup
65
+ ```
66
+
67
+ Or install locally in your project:
68
+
69
+ ```bash
70
+ npm install unitup
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Quick Start
76
+
77
+ ```bash
78
+ # 1. Verify system readiness
79
+ unitup doctor
80
+
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
83
+
84
+ # 3. Check service status
85
+ unitup status api
86
+
87
+ # 4. Stream real-time journalctl logs
88
+ unitup logs api --follow
89
+
90
+ # 5. Stop or remove service when no longer needed
91
+ unitup stop api
92
+ unitup remove api
93
+ ```
94
+
95
+ ---
96
+
97
+ ## CLI Commands
98
+
99
+ ### `unitup doctor`
100
+
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
+ ```text
113
+ unitup doctor
114
+
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
123
+
124
+ User lingering is disabled.
125
+ The service may stop after logout.
126
+
127
+ Enable it manually:
128
+ loginctl enable-linger username
129
+ ```
130
+
131
+ ---
132
+
133
+ ### Diagnosing Node.js Runtime & Path Problems
134
+
135
+ `unitup` automatically detects and diagnoses Node.js installation issues before creating services.
136
+
137
+ #### 1. Node.js not found in PATH
138
+ ```text
139
+ ✗ Node.js not found in PATH
140
+
141
+ Install Node.js:
142
+ https://nodejs.org
143
+ or via package manager:
144
+ sudo apt install nodejs
145
+ ```
146
+
147
+ #### 2. Node.js binary exists but is not executable
148
+ ```text
149
+ ✗ Node.js binary exists but is not executable
150
+
151
+ Check permissions:
152
+ chmod +x $(which node)
153
+ ```
154
+
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:
157
+
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
164
+ ```
165
+
166
+ You can also specify an explicit Node.js binary path when creating a service:
167
+
168
+ ```bash
169
+ unitup add app.js --node /usr/bin/node
170
+ ```
171
+
172
+ If Node.js cannot be resolved, `unitup add` will safely abort and request that you run `unitup doctor`.
173
+
174
+ ---
175
+
176
+ ### `unitup add <script>`
177
+
178
+ Creates a new systemd user service unit file at `~/.config/systemd/user/unitup-<name>.service`.
179
+
180
+ ```bash
181
+ unitup add app.js
182
+ unitup add server.js --name api --env NODE_ENV=production --env PORT=3000 --start
183
+ ```
184
+
185
+ **Options:**
186
+ - `--name <name>`: Custom service name (defaults to script file name without extension).
187
+ - `--node <path>`: Explicit Node.js executable path.
188
+ - `--cwd <path>`: Working directory (defaults to script directory).
189
+ - `--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).
193
+ - `--start`: Automatically enables and starts the service immediately (`systemctl --user enable --now`).
194
+
195
+ Generated unit file example (`~/.config/systemd/user/unitup-api.service`):
196
+
197
+ ```ini
198
+ [Unit]
199
+ Description=unitup service: api
200
+ After=network.target
201
+
202
+ [Service]
203
+ Type=simple
204
+ WorkingDirectory=/home/user/projects/app
205
+ ExecStart=/usr/bin/node /home/user/projects/app/server.js
206
+ Restart=on-failure
207
+ RestartSec=3
208
+ EnvironmentFile=/home/user/projects/app/.env
209
+ Environment=PATH="/usr/bin:/usr/local/bin:/bin"
210
+ Environment=NODE_ENV="production"
211
+ Environment=PORT="3000"
212
+
213
+ [Install]
214
+ WantedBy=default.target
215
+ ```
216
+
217
+ ---
218
+
219
+ ### `unitup start <name>`
220
+
221
+ Starts an existing service unit.
222
+
223
+ ```bash
224
+ unitup start api
225
+ ```
226
+
227
+ Pass `--enable` to enable the service to start automatically on system boot:
228
+
229
+ ```bash
230
+ unitup start api --enable
231
+ ```
232
+
233
+ ---
234
+
235
+ ### `unitup stop <name>`
236
+
237
+ Stops a running service:
238
+
239
+ ```bash
240
+ unitup stop api
241
+ ```
242
+
243
+ ---
244
+
245
+ ### `unitup restart <name>`
246
+
247
+ Restarts a service:
248
+
249
+ ```bash
250
+ unitup restart api
251
+ ```
252
+
253
+ ---
254
+
255
+ ### `unitup status <name>`
256
+
257
+ Shows a compact status summary for the service:
258
+
259
+ ```text
260
+ api
261
+
262
+ Status: running
263
+ PID: 14220
264
+ Started: 12 minutes ago
265
+ Restarts: 0
266
+ Script: /home/user/projects/app/server.js
267
+ Working directory: /home/user/projects/app
268
+ ```
269
+
270
+ To view systemctl's raw output, pass `--raw`:
271
+
272
+ ```bash
273
+ unitup status api --raw
274
+ ```
275
+
276
+ ---
277
+
278
+ ### `unitup logs <name>`
279
+
280
+ Displays logs collected by systemd's `journalctl`.
281
+
282
+ ```bash
283
+ # View last 100 log lines (default)
284
+ unitup logs api
285
+
286
+ # Specify number of lines
287
+ unitup logs api --lines 30
288
+
289
+ # Live follow/stream mode
290
+ unitup logs api --follow
291
+ ```
292
+
293
+ ---
294
+
295
+ ### `unitup list`
296
+
297
+ Lists all user services managed by `unitup` (`unitup-*.service`):
298
+
299
+ ```text
300
+ NAME STATUS ENABLED
301
+ api running yes
302
+ worker stopped yes
303
+ cleanup failed no
304
+ ```
305
+
306
+ ---
307
+
308
+ ### `unitup remove <name>`
309
+
310
+ Stops, disables, and deletes the unit file, then reloads systemd:
311
+
312
+ ```bash
313
+ unitup remove api
314
+ ```
315
+
316
+ Equivalent systemctl commands executed:
317
+ 1. `systemctl --user disable --now unitup-api.service`
318
+ 2. Remove `~/.config/systemd/user/unitup-api.service`
319
+ 3. `systemctl --user daemon-reload`
320
+ 4. `systemctl --user reset-failed`
321
+
322
+ ---
323
+
324
+ ## User Lingering & Persistence Across Logout
325
+
326
+ 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**:
327
+
328
+ ```bash
329
+ loginctl enable-linger $USER
330
+ ```
331
+
332
+ `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.
333
+
334
+ ---
335
+
336
+ ## Programmatic JavaScript & TypeScript API
337
+
338
+ `unitup` includes full TypeScript declaration files (`index.d.ts`). You can import `unitup` directly into JavaScript or TypeScript applications:
339
+
340
+ ```ts
341
+ import {
342
+ createService,
343
+ startService,
344
+ stopService,
345
+ restartService,
346
+ removeService,
347
+ getServiceStatus,
348
+ listServices,
349
+ isSystemdAvailable,
350
+ CreateServiceOptions,
351
+ ServiceStatus
352
+ } from "unitup";
353
+
354
+ // Check if systemd user services are available
355
+ if (await isSystemdAvailable()) {
356
+ const options: CreateServiceOptions = {
357
+ name: "api",
358
+ script: "./server.js",
359
+ cwd: process.cwd(),
360
+ env: {
361
+ NODE_ENV: "production",
362
+ PORT: "3000"
363
+ },
364
+ restart: "on-failure"
365
+ };
366
+
367
+ // Add a service
368
+ await createService(options);
369
+
370
+ // Start the service
371
+ await startService("api");
372
+
373
+ // Get compact status
374
+ const status: ServiceStatus = await getServiceStatus("api");
375
+ console.log(`Service PID: ${status.pid}, Status: ${status.status}`);
376
+
377
+ // List all unitup services
378
+ const services = await listServices();
379
+ console.log(services);
380
+ }
381
+ ```
382
+
383
+ ---
384
+
385
+ ## License
386
+
387
+ [MIT](LICENSE)
package/bin/unitup.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '../src/cli.js';
3
+
4
+ runCli();