unitup 0.1.5 → 0.3.0

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.
Files changed (55) hide show
  1. package/.agents/AGENTS.md +35 -0
  2. package/.agents/skills/multi-runtime-management/SKILL.md +80 -0
  3. package/.agents/skills/platform-service-adapters/SKILL.md +108 -0
  4. package/.agents/skills/unitup-development-and-qa/SKILL.md +88 -0
  5. package/.agents/skills/zero-downtime-deployment/SKILL.md +135 -0
  6. package/CHANGELOG.md +5 -3
  7. package/README.md +89 -8
  8. package/biome.json +0 -1
  9. package/docs/index.html +188 -234
  10. package/index.d.ts +467 -440
  11. package/package.json +9 -3
  12. package/src/cli.js +561 -103
  13. package/src/core/drain-manager.js +70 -0
  14. package/src/core/generation-manager.js +414 -0
  15. package/src/core/index.js +8 -0
  16. package/src/core/ipc.js +236 -0
  17. package/src/core/lock.js +133 -0
  18. package/src/core/process-manager.js +313 -0
  19. package/src/core/readiness.js +243 -0
  20. package/src/core/router.js +390 -0
  21. package/src/core/supervisor.js +222 -0
  22. package/src/deploy/deployment-manager.js +407 -0
  23. package/src/deploy/index.js +9 -0
  24. package/src/deploy/rollback-manager.js +186 -0
  25. package/src/doctor.js +123 -56
  26. package/src/errors.js +131 -0
  27. package/src/index.js +186 -59
  28. package/src/logs.js +148 -0
  29. package/src/platform/base.js +211 -0
  30. package/src/platform/index.js +43 -0
  31. package/src/platform/linux.js +155 -0
  32. package/src/platform/macos.js +726 -0
  33. package/src/platform/windows-host.js +246 -0
  34. package/src/platform/windows.js +498 -0
  35. package/src/runtimes/bun.js +1 -1
  36. package/src/runtimes/common.js +24 -6
  37. package/src/runtimes/deno.js +1 -1
  38. package/src/runtimes/elixir.js +1 -1
  39. package/src/runtimes/go.js +1 -1
  40. package/src/runtimes/index.js +7 -7
  41. package/src/runtimes/native.js +2 -4
  42. package/src/runtimes/node.js +1 -1
  43. package/src/runtimes/php.js +1 -1
  44. package/src/runtimes/python.js +1 -1
  45. package/src/runtimes/ruby.js +1 -1
  46. package/src/runtimes/shell.js +1 -1
  47. package/src/schedule.js +31 -24
  48. package/src/service/config.js +63 -0
  49. package/src/service/manager.js +233 -0
  50. package/src/service/normalize.js +245 -0
  51. package/src/systemd.js +84 -38
  52. package/src/unit.js +17 -19
  53. package/src/utils.js +112 -18
  54. package/tsconfig.json +1 -1
  55. package/types-test/index.ts +158 -0
package/docs/index.html CHANGED
@@ -4,7 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta name="color-scheme" content="light dark" />
7
- <meta name="description" content="unitup — Minimal, zero-dependency systemd-native service manager for Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell, and native binaries." />
7
+ <title>unitup — Cross-Platform Background Service Manager</title>
8
+ <meta name="description" content="unitup — Minimal, zero-dependency cross-platform native service manager (systemd, launchd, Windows Services) for Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell, and native binaries." />
8
9
  <!-- Google tag (gtag.js) -->
9
10
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-MEASUREMENT_ID"></script>
10
11
  <script>
@@ -22,6 +23,8 @@
22
23
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
23
24
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/bash.min.js"></script>
24
25
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/typescript.min.js"></script>
26
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/xml.min.js"></script>
27
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/json.min.js"></script>
25
28
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/yaml.min.js"></script>
26
29
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/ini.min.js"></script>
27
30
  <style>
@@ -47,7 +50,7 @@
47
50
  <div class="flex items-center justify-between mb-8 sm:mb-10 gap-4 flex-wrap pb-6 border-b border-slate-200 dark:border-slate-800">
48
51
  <div class="flex items-center gap-2.5 sm:gap-3">
49
52
  <span class="text-2xl font-black tracking-tight text-cyan-600 dark:text-cyan-400">unitup</span>
50
- <span class="text-xs px-2.5 py-0.5 rounded-full bg-cyan-100 text-cyan-800 dark:bg-cyan-950 dark:text-cyan-300 font-semibold border border-cyan-300 dark:border-cyan-800">v0.0.11</span>
53
+ <span class="text-xs px-2.5 py-0.5 rounded-full bg-cyan-100 text-cyan-800 dark:bg-cyan-950 dark:text-cyan-300 font-semibold border border-cyan-300 dark:border-cyan-800">v0.1.5</span>
51
54
  <a href="https://github.com/litepacks/unitup" target="_blank" rel="noopener noreferrer" class="text-slate-500 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 transition-colors p-1" aria-label="GitHub Repository">
52
55
  <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
53
56
  </a>
@@ -65,14 +68,13 @@
65
68
 
66
69
  <nav id="nav-menu" class="hidden md:flex w-full md:w-auto flex-col md:flex-row flex-wrap gap-x-4 gap-y-2 text-sm font-medium pt-3 md:pt-0 border-t md:border-t-0 border-slate-200 dark:border-slate-800" aria-label="Page sections">
67
70
  <a href="#overview" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Overview</a>
71
+ <a href="#platforms" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Platforms</a>
68
72
  <a href="#comparison" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">vs PM2</a>
69
73
  <a href="#architecture" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Architecture</a>
70
74
  <a href="#runtimes" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Runtimes</a>
71
75
  <a href="#cli" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">CLI Reference</a>
72
76
  <a href="#schedules" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Schedules</a>
73
77
  <a href="#api" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">API</a>
74
- <a href="#declarative" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Roadmap</a>
75
- <a href="#troubleshooting" class="text-slate-600 hover:text-cyan-600 dark:text-slate-400 dark:hover:text-cyan-400 py-1">Lingering</a>
76
78
  <a href="https://github.com/litepacks/unitup" target="_blank" rel="noopener noreferrer" class="text-cyan-600 dark:text-cyan-400 hover:underline flex items-center gap-1 font-semibold py-1">GitHub &rarr;</a>
77
79
  </nav>
78
80
  </div>
@@ -80,31 +82,30 @@
80
82
  <!-- Header / Hero Section -->
81
83
  <header class="mb-14">
82
84
  <div class="inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs font-semibold bg-cyan-50 dark:bg-cyan-950/60 text-cyan-700 dark:text-cyan-300 border border-cyan-200 dark:border-cyan-800 mb-4">
83
- ⚡ Zero-Daemon · Systemd-Native · Multi-Runtime
85
+ ⚡ Zero-Daemon · Linux systemd · macOS launchd · Windows Services
84
86
  </div>
85
87
  <h1 class="text-4xl sm:text-5xl font-extrabold text-slate-900 dark:text-white tracking-tight mb-4">
86
- Systemd Service Management,<br class="hidden sm:inline" />Simplified for Any App.
88
+ Cross-Platform Service Management,<br class="hidden sm:inline" />Simplified for Any App.
87
89
  </h1>
88
90
  <p class="text-lg text-slate-600 dark:text-slate-400 max-w-3xl leading-relaxed mb-6">
89
- <strong class="text-slate-800 dark:text-slate-200">unitup</strong> is a zero-dependency CLI & library to run Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell scripts, and compiled native executables as native OS <code class="text-cyan-700 dark:text-cyan-400">systemd</code> user services without requiring <code class="text-cyan-700 dark:text-cyan-400">sudo</code>.
91
+ <strong class="text-slate-800 dark:text-slate-200">unitup</strong> is a zero-dependency CLI & library to run Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell scripts, and compiled native executables as native background services across <strong>Linux (<code class="text-cyan-700 dark:text-cyan-400">systemd</code>)</strong>, <strong>macOS (<code class="text-cyan-700 dark:text-cyan-400">launchd</code>)</strong>, and <strong>Windows (<code class="text-cyan-700 dark:text-cyan-400">Windows Services</code>)</strong>.
90
92
  </p>
91
93
 
92
94
  <!-- Quick Try Code Block -->
93
95
  <div class="rounded-xl border border-slate-200 dark:border-slate-800 bg-slate-900 p-4 max-w-2xl shadow-xl">
94
96
  <div class="flex items-center justify-between text-xs text-slate-400 mb-2 font-mono border-b border-slate-800 pb-2">
95
- <span>Quick Start (30-second try)</span>
97
+ <span>Quick Start</span>
96
98
  <span>bash</span>
97
99
  </div>
98
100
  <pre><code class="language-bash">npm install -g unitup
99
101
 
100
- # Add & start Node.js server
101
- unitup add server.js --start
102
- unitup status server
103
- unitup logs server --follow
102
+ # Install & start service natively on Linux, macOS, or Windows
103
+ unitup install server.js --name api --start
104
+ unitup status api
105
+ unitup logs api --follow
104
106
 
105
- # Multi-runtime & Native executables
106
- unitup add worker.py --runtime python --start
107
- unitup add ./server --runtime native --name api --start</code></pre>
107
+ # Preview generated native service configuration without installing
108
+ unitup install server.js --name api --dry-run</code></pre>
108
109
  </div>
109
110
  </header>
110
111
 
@@ -115,47 +116,124 @@ unitup add ./server --runtime native --name api --start</code></pre>
115
116
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
116
117
  <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">⚡ No Resident Daemon</div>
117
118
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
118
- Exits immediately after configuring services. Zero persistent memory or CPU overhead from unitup itself.
119
+ Exits immediately after configuring services. No resident unitup master process continuously eating CPU or RAM.
119
120
  </p>
120
121
  </div>
121
122
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
122
- <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🌐 Multi-Runtime</div>
123
+ <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🖥️ Cross-Platform</div>
123
124
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
124
- Out-of-the-box support for Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell, and native binaries.
125
+ First-class adapters for Linux (<code class="text-xs">systemd</code>), macOS (<code class="text-xs">launchd</code>), and Windows (<code class="text-xs">SCM</code>).
125
126
  </p>
126
127
  </div>
127
128
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
128
- <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🔒 Safe & Transparent</div>
129
+ <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🌐 Multi-Runtime</div>
129
130
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
130
- Avoids shell execution (<code class="text-xs">shell: false</code>). Saves standard text unit files directly to <code class="text-xs">~/.config/systemd/user/</code>.
131
+ Out-of-the-box support for Node.js, Python, Ruby, PHP, Bun, Deno, Go, Elixir, Shell, and native binaries.
131
132
  </p>
132
133
  </div>
133
134
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
134
- <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🛠️ Absolute Pathing</div>
135
+ <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🔍 Dry-Run Mode</div>
135
136
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
136
- Resolves absolute binary & script paths and automatically injects proper <code class="text-xs">PATH</code> environment into unit files.
137
+ Use <code class="text-xs">--dry-run</code> to inspect exact generated unit files or XML plists before installing.
137
138
  </p>
138
139
  </div>
139
140
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
140
141
  <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">📦 Zero Dependencies</div>
141
142
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
142
- Built strictly with Node.js standard library modules. Extremely lightweight ESM & CJS footprint.
143
+ Built strictly with Node.js standard libraries. Zero heavy third-party npm dependencies or native bindings.
143
144
  </p>
144
145
  </div>
145
146
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 shadow-sm">
146
147
  <div class="text-cyan-600 dark:text-cyan-400 text-xl font-bold mb-1">🔄 100% Backward Compatible</div>
147
148
  <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
148
- Full support for existing Node.js configurations and legacy metadata formats without breaking changes.
149
+ Full support for existing Linux systemd workflows, timers, and legacy metadata without breaking changes.
149
150
  </p>
150
151
  </div>
151
152
  </div>
152
153
  </section>
153
154
 
155
+ <!-- Section: Platforms -->
156
+ <section id="platforms" class="doc-section mb-14">
157
+ <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Platform Support Matrix</h2>
158
+ <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
159
+ Unitup provides unified command syntax while leveraging the native service architecture on each operating system:
160
+ </p>
161
+
162
+ <div class="table-container">
163
+ <table>
164
+ <thead>
165
+ <tr>
166
+ <th>Feature</th>
167
+ <th>Linux (<code class="text-xs">systemd</code>)</th>
168
+ <th>macOS (<code class="text-xs">launchd</code>)</th>
169
+ <th>Windows (<code class="text-xs">Windows Services</code>)</th>
170
+ </tr>
171
+ </thead>
172
+ <tbody class="text-sm">
173
+ <tr>
174
+ <td class="font-semibold">Install / Uninstall</td>
175
+ <td><code class="text-xs">systemd</code> user/system unit</td>
176
+ <td><code class="text-xs">launchd</code> agent/daemon <code class="text-xs">.plist</code></td>
177
+ <td>Windows Service (<code class="text-xs">sc.exe</code>)</td>
178
+ </tr>
179
+ <tr>
180
+ <td class="font-semibold">Start / Stop / Restart</td>
181
+ <td><code class="text-xs">systemctl</code></td>
182
+ <td><code class="text-xs">launchctl kickstart / kill</code></td>
183
+ <td><code class="text-xs">sc.exe start / stop</code></td>
184
+ </tr>
185
+ <tr>
186
+ <td class="font-semibold">Auto-Start on Boot</td>
187
+ <td><code class="text-xs">systemctl enable</code></td>
188
+ <td><code class="text-xs">RunAtLoad: true</code></td>
189
+ <td>Automatic Service Startup</td>
190
+ </tr>
191
+ <tr>
192
+ <td class="font-semibold">Environment Variables</td>
193
+ <td><code class="text-xs">Environment=</code></td>
194
+ <td><code class="text-xs">EnvironmentVariables</code> plist dict</td>
195
+ <td>Process Environment Forwarding</td>
196
+ </tr>
197
+ <tr>
198
+ <td class="font-semibold">Logs</td>
199
+ <td><code class="text-xs">journalctl</code></td>
200
+ <td>File-based streaming (<code class="text-xs">~/.config/unitup/logs/</code>)</td>
201
+ <td>File-based streaming (<code class="text-xs">~/.config/unitup/logs/</code>)</td>
202
+ </tr>
203
+ <tr>
204
+ <td class="font-semibold">Crash Recovery</td>
205
+ <td><code class="text-xs">Restart=on-failure</code></td>
206
+ <td><code class="text-xs">KeepAlive</code> plist dictionary</td>
207
+ <td>Host supervisor auto-restart & uptime reset</td>
208
+ </tr>
209
+ <tr>
210
+ <td class="font-semibold">User Services</td>
211
+ <td><code class="text-xs">~/.config/systemd/user/</code></td>
212
+ <td><code class="text-xs">~/Library/LaunchAgents/</code></td>
213
+ <td>Supported</td>
214
+ </tr>
215
+ <tr>
216
+ <td class="font-semibold">System Services</td>
217
+ <td><code class="text-xs">/etc/systemd/system/</code> (<code class="text-xs">--system</code>)</td>
218
+ <td><code class="text-xs">/Library/LaunchDaemons/</code> (<code class="text-xs">--system</code>)</td>
219
+ <td>Native Windows Service</td>
220
+ </tr>
221
+ <tr>
222
+ <td class="font-semibold">Dry-Run Inspection</td>
223
+ <td><code class="text-xs">--dry-run</code> (systemd unit)</td>
224
+ <td><code class="text-xs">--dry-run</code> (plist XML)</td>
225
+ <td><code class="text-xs">--dry-run</code> (service JSON)</td>
226
+ </tr>
227
+ </tbody>
228
+ </table>
229
+ </div>
230
+ </section>
231
+
154
232
  <!-- Section: Comparison -->
155
233
  <section id="comparison" class="doc-section mb-14">
156
234
  <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">unitup vs PM2</h2>
157
235
  <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
158
- <strong class="text-slate-800 dark:text-slate-200">unitup</strong> is not a PM2 replacement or an independent process manager. While PM2 runs its own master daemon, unitup is strictly a thin, transparent CLI layer on top of Linux OS <code class="text-cyan-600 dark:text-cyan-400">systemd</code>.
236
+ <strong class="text-slate-800 dark:text-slate-200">unitup</strong> is not a PM2 replacement or an independent process manager. While PM2 runs its own master daemon, unitup is strictly a thin, transparent CLI layer on top of native OS service managers.
159
237
  </p>
160
238
 
161
239
  <div class="table-container">
@@ -170,12 +248,12 @@ unitup add ./server --runtime native --name api --start</code></pre>
170
248
  <tbody class="text-sm">
171
249
  <tr>
172
250
  <td class="font-semibold">Background Process (Daemon)</td>
173
- <td><strong class="text-emerald-600 dark:text-emerald-400">No resident daemon</strong>. Systemd directly supervises processes.</td>
251
+ <td><strong class="text-emerald-600 dark:text-emerald-400">No resident daemon</strong>. OS directly supervises processes.</td>
174
252
  <td>Runs a persistent process-management daemon.</td>
175
253
  </tr>
176
254
  <tr>
177
255
  <td class="font-semibold">System Integration</td>
178
- <td>Native Linux OS <code class="text-xs">systemd</code> user service (<code class="text-xs">~/.config/systemd/user/</code>).</td>
256
+ <td>Native OS service managers (<code class="text-xs">systemd</code>, <code class="text-xs">launchd</code>, <code class="text-xs">Windows Services</code>).</td>
179
257
  <td>Custom process monitoring via PM2's internal daemon.</td>
180
258
  </tr>
181
259
  <tr>
@@ -185,7 +263,7 @@ unitup add ./server --runtime native --name api --start</code></pre>
185
263
  </tr>
186
264
  <tr>
187
265
  <td class="font-semibold">Privileges Required</td>
188
- <td>Does <strong class="text-emerald-600 dark:text-emerald-400">not</strong> require <code class="text-xs">sudo</code> for normal service creation and management.</td>
266
+ <td>Does <strong class="text-emerald-600 dark:text-emerald-400">not</strong> require elevated permissions for user services.</td>
189
267
  <td>Boot integration commonly requires running PM2 startup with elevated privileges.</td>
190
268
  </tr>
191
269
  <tr>
@@ -195,14 +273,9 @@ unitup add ./server --runtime native --name api --start</code></pre>
195
273
  </tr>
196
274
  <tr>
197
275
  <td class="font-semibold">Log Management</td>
198
- <td>Delegates 100% to native Linux <code class="text-xs">journald</code> system (<code class="text-xs">journalctl</code>).</td>
276
+ <td>Native <code class="text-xs">journald</code> (Linux) / Cross-platform streaming tail files.</td>
199
277
  <td>Manages <code class="text-xs">.pm2/logs</code> files (requires <code class="text-xs">pm2-logrotate</code> plugin).</td>
200
278
  </tr>
201
- <tr>
202
- <td class="font-semibold">Boot Startup</td>
203
- <td>Native systemd lingering (<code class="text-xs">loginctl enable-linger</code>).</td>
204
- <td>Custom startup script launching PM2 master daemon.</td>
205
- </tr>
206
279
  </tbody>
207
280
  </table>
208
281
  </div>
@@ -212,40 +285,51 @@ unitup add ./server --runtime native --name api --start</code></pre>
212
285
  <section id="architecture" class="doc-section mb-14">
213
286
  <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Core Architecture</h2>
214
287
  <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
215
- At its core, unitup generates systemd service unit files directly from a generic <code class="text-cyan-600 dark:text-cyan-400">command + args</code> model rather than being hardcoded to Node.js:
288
+ Unitup generates native service definitions directly from a canonical <code class="text-cyan-600 dark:text-cyan-400">command + args</code> model:
216
289
  </p>
217
290
 
218
291
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
219
292
  <div class="min-w-0">
220
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">JSON Execution Model</h3>
221
- <pre><code class="language-json">{
222
- "command": "/usr/bin/python3",
223
- "args": ["/home/user/apps/worker.py"],
224
- "cwd": "/home/user/apps",
225
- "env": {
226
- "APP_ENV": "production"
227
- }
228
- }</code></pre>
229
- </div>
230
- <div class="min-w-0">
231
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2 flex flex-wrap items-center gap-1">Generated Unit File <span class="lowercase font-mono text-xs normal-case opacity-90 break-all">(unitup-worker.service)</span></h3>
293
+ <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">Linux (systemd unit)</h3>
232
294
  <pre><code class="language-ini">[Unit]
233
295
  Description=unitup service: worker
234
296
  After=network.target
235
297
 
236
298
  [Service]
237
299
  Type=simple
238
- SyslogIdentifier=unitup-worker
239
300
  WorkingDirectory=/home/user/apps
240
301
  ExecStart=/usr/bin/python3 /home/user/apps/worker.py
241
302
  Restart=on-failure
242
303
  RestartSec=3
243
- Environment=PATH="/usr/bin:/usr/local/bin:/bin"
244
304
  Environment=APP_ENV="production"
245
305
 
246
306
  [Install]
247
307
  WantedBy=default.target</code></pre>
248
308
  </div>
309
+ <div class="min-w-0">
310
+ <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">macOS (launchd plist)</h3>
311
+ <pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
312
+ &lt;plist version="1.0"&gt;
313
+ &lt;dict&gt;
314
+ &lt;key&gt;Label&lt;/key&gt;
315
+ &lt;string&gt;dev.unitup.worker&lt;/string&gt;
316
+ &lt;key&gt;ProgramArguments&lt;/key&gt;
317
+ &lt;array&gt;
318
+ &lt;string&gt;/usr/bin/python3&lt;/string&gt;
319
+ &lt;string&gt;/home/user/apps/worker.py&lt;/string&gt;
320
+ &lt;/array&gt;
321
+ &lt;key&gt;WorkingDirectory&lt;/key&gt;
322
+ &lt;string&gt;/home/user/apps&lt;/string&gt;
323
+ &lt;key&gt;RunAtLoad&lt;/key&gt;
324
+ &lt;true/&gt;
325
+ &lt;key&gt;KeepAlive&lt;/key&gt;
326
+ &lt;dict&gt;
327
+ &lt;key&gt;SuccessfulExit&lt;/key&gt;&lt;false/&gt;
328
+ &lt;key&gt;Crashed&lt;/key&gt;&lt;true/&gt;
329
+ &lt;/dict&gt;
330
+ &lt;/dict&gt;
331
+ &lt;/plist&gt;</code></pre>
332
+ </div>
249
333
  </div>
250
334
  </section>
251
335
 
@@ -316,10 +400,6 @@ WantedBy=default.target</code></pre>
316
400
  </tbody>
317
401
  </table>
318
402
  </div>
319
-
320
- <div class="p-4 rounded-xl border border-amber-200 dark:border-amber-900/60 bg-amber-50/60 dark:bg-amber-950/20 text-sm text-amber-900 dark:text-amber-300">
321
- 💡 <strong>Go Production Recommendation:</strong> For production deployments, compiling the Go application and registering the resulting native binary (<code class="text-xs">unitup add ./server --runtime native</code>) is recommended instead of <code class="text-xs">go run</code>.
322
- </div>
323
403
  </section>
324
404
 
325
405
  <!-- Section: CLI Reference -->
@@ -330,27 +410,28 @@ WantedBy=default.target</code></pre>
330
410
  <!-- doctor -->
331
411
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
332
412
  <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup doctor</code></h3>
333
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Runs system readiness diagnostics (Linux OS, systemd PID 1, user bus, lingering, unit directory permissions, and detected runtimes).</p>
413
+ <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Runs cross-platform diagnostics (Platform, Service manager, Node.js path, data directory, permissions, lingering, and detected runtimes).</p>
334
414
  <pre><code class="language-bash">unitup doctor</code></pre>
335
415
  </div>
336
416
 
337
- <!-- add -->
417
+ <!-- install / add -->
338
418
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
339
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup add &lt;script|exec&gt; [options]</code></h3>
340
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Generates and registers a new systemd user service unit file.</p>
419
+ <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup install / add &lt;script|exec&gt; [options]</code></h3>
420
+ <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Generates and installs a new native background service.</p>
341
421
  <pre><code class="language-bash"># Flags:
342
422
  # --name <name> Service name (default: script basename)
343
423
  # --runtime <name> Specify runtime (node, python, ruby, php, bun, deno, shell, go, elixir, native)
344
- # --runtime-arg <val> Argument passed to binary (e.g. -S 0.0.0.0:8080 or --allow-net)
345
- # --command <path> Explicit binary executable (bypasses auto-detection)
346
- # --arg <val> Argument to pass to command
347
- # --group <group> Assign service to group (default: default)
348
- # --env KEY=val Set environment variable
349
- # --env-file <path> Load environment file
350
- # --start Enable and start service immediately
351
- # --force, -f Force overwrite of currently running service
352
-
353
- unitup add worker.py --name worker --group backend --env APP_ENV=production --start</code></pre>
424
+ # --command <path> Explicit binary executable (bypasses auto-detection)
425
+ # --env KEY=val Set environment variable
426
+ # --env-file <path> Load environment file
427
+ # --dry-run Preview generated service file without installing
428
+ # --system Install as system-wide service (LaunchDaemons / root systemd)
429
+ # --start Enable and start service immediately
430
+ # --force, -f Force overwrite of currently running service
431
+
432
+ unitup install server.js --name api --start
433
+ unitup install worker.py --name worker --group backend --env APP_ENV=production --start
434
+ unitup install server.js --dry-run</code></pre>
354
435
  </div>
355
436
 
356
437
  <!-- list / ls -->
@@ -363,112 +444,67 @@ unitup add worker.py --name worker --group backend --env APP_ENV=production --st
363
444
  <!-- inspect -->
364
445
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
365
446
  <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup inspect &lt;name&gt;</code></h3>
366
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Displays full service configuration overview (Command, Arguments, Working directory, Unit file) without revealing secrets or environment variables.</p>
367
- <pre><code class="language-bash">unitup inspect worker</code></pre>
447
+ <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Displays full service configuration overview without revealing secrets or environment variables.</p>
448
+ <pre><code class="language-bash">unitup inspect api</code></pre>
368
449
  </div>
369
450
 
370
451
  <!-- start / stop / restart -->
371
452
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
372
453
  <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup start / stop / restart &lt;name|@group&gt;</code></h3>
373
454
  <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Controls service state individually or in batch using <code class="text-xs">@group</code> syntax.</p>
374
- <pre><code class="language-bash">unitup start @backend --enable
375
- unitup restart worker
376
- unitup stop @backend</code></pre>
455
+ <pre><code class="language-bash">unitup start api
456
+ unitup restart @backend
457
+ unitup stop api</code></pre>
377
458
  </div>
378
459
 
379
- <!-- limits -->
460
+ <!-- enable / disable -->
380
461
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
381
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup limits &lt;name&gt; [options]</code></h3>
382
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Configures native systemd memory limits for a service or resets limits back to system defaults.</p>
383
- <pre><code class="language-bash">unitup limits api --memory-high 400M --memory-max 512M --swap-max 256M
384
- unitup limits api --reset-memory</code></pre>
385
- </div>
386
-
387
- <!-- memory / top -->
388
- <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
389
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup memory</code> / <code class="text-base">unitup top</code></h3>
390
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Displays memory usage overview across all running apps and schedules, with aggregated total memory consumption summary.</p>
391
- <pre><code class="language-bash">unitup top
392
- unitup memory api
393
- unitup mem --group backend</code></pre>
462
+ <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup enable / disable &lt;name&gt;</code></h3>
463
+ <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Enables or disables service startup on boot.</p>
464
+ <pre><code class="language-bash">unitup enable api
465
+ unitup disable api</code></pre>
394
466
  </div>
395
467
 
396
468
  <!-- status & logs -->
397
469
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
398
470
  <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup status / logs &lt;name&gt;</code></h3>
399
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Inspects process status with live memory metrics or streams journalctl logs with advanced filtering.</p>
400
- <pre><code class="language-bash">unitup status worker
401
- unitup logs worker --follow --since 1h --priority err --json</code></pre>
402
- </div>
403
-
404
- <!-- journal -->
405
- <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
406
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup journal &lt;action&gt; [options]</code></h3>
407
- <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Performs safe journalctl storage maintenance (disk-usage, rotate, vacuum by size, time, or file count).</p>
408
- <pre><code class="language-bash">unitup journal disk-usage
409
- unitup journal rotate
410
- unitup journal vacuum --size 500M --yes
411
- unitup journal vacuum --time 14d --dry-run</code></pre>
471
+ <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Inspects process status with live metrics or streams service logs with advanced filtering.</p>
472
+ <pre><code class="language-bash">unitup status api --verbose
473
+ unitup logs api --follow
474
+ unitup logs api --lines 50 --grep "ERROR"</code></pre>
412
475
  </div>
413
476
 
414
- <!-- remove -->
477
+ <!-- uninstall / remove -->
415
478
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
416
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup remove &lt;name|@group&gt; [--force]</code></h3>
479
+ <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-base">unitup uninstall / remove &lt;name|@group&gt; [--force]</code></h3>
417
480
  <p class="text-sm text-slate-600 dark:text-slate-400 mb-3">Stops, disables, and deletes a service or group. Active running services require <code class="text-xs">--force</code> / <code class="text-xs">-f</code> to prevent accidental deletion.</p>
418
- <pre><code class="language-bash">unitup remove worker
419
- unitup remove @backend --force</code></pre>
481
+ <pre><code class="language-bash">unitup uninstall api
482
+ unitup uninstall @backend --force</code></pre>
420
483
  </div>
421
484
  </div>
422
485
  </section>
423
486
 
424
487
  <!-- Section: Schedules -->
425
488
  <section id="schedules" class="doc-section mb-14">
426
- <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Systemd Timer Schedules</h2>
489
+ <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Systemd Timer Schedules (Linux)</h2>
427
490
  <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
428
- <strong class="text-slate-800 dark:text-slate-200">unitup</strong> supports native systemd timer scheduling without running continuous worker processes or cron daemons. Each schedule generates a paired oneshot service (<code class="text-cyan-700 dark:text-cyan-400">~/.config/systemd/user/unitup-&lt;name&gt;.service</code>) and timer unit (<code class="text-cyan-700 dark:text-cyan-400">~/.config/systemd/user/unitup-&lt;name&gt;.timer</code>).
491
+ <strong class="text-slate-800 dark:text-slate-200">unitup</strong> supports native systemd timer scheduling on Linux without running continuous worker processes or cron daemons.
429
492
  </p>
430
493
 
431
494
  <div class="space-y-6">
432
495
  <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
433
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2">CLI Schedule Commands</h3>
496
+ <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2">Schedule Commands</h3>
434
497
  <pre><code class="language-bash"># Create interval schedule (--every 30m)
435
498
  unitup schedule cleanup.js --every 30m --persistent --start
436
499
 
437
500
  # Create calendar schedule (--calendar daily with random delay jitter)
438
501
  unitup schedule backup.py --calendar daily --random-delay 10m --persistent --start
439
502
 
440
- # Specific calendar expression
441
- unitup schedule report.js --calendar "Mon..Fri 09:00" --start
442
-
443
503
  # List all schedule timers
444
504
  unitup schedules # or unitup timers
445
505
 
446
506
  # Detailed schedule status
447
- unitup schedule-status cleanup
448
-
449
- # Manually trigger schedule service unit once
450
- unitup schedule-run cleanup
451
-
452
- # Enable / Disable / Remove schedule
453
- unitup schedule-enable cleanup
454
- unitup schedule-disable cleanup
455
- unitup schedule-remove cleanup [--force]
456
-
457
- # Read schedule logs
458
- unitup schedule-logs cleanup</code></pre>
459
- </div>
460
-
461
- <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50">
462
- <h3 class="text-lg font-bold text-cyan-600 dark:text-cyan-400 mb-2">Schedule Options</h3>
463
- <ul class="list-disc list-inside space-y-1.5 text-sm text-slate-600 dark:text-slate-400">
464
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--every &lt;duration&gt;</code>: Execution interval (e.g., <code class="text-xs">30s</code>, <code class="text-xs">10m</code>, <code class="text-xs">2h</code>, <code class="text-xs">1d</code>). Sets <code class="text-xs">OnActiveSec</code> and <code class="text-xs">OnUnitActiveSec</code>.</li>
465
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--calendar &lt;expression&gt;</code>: Systemd calendar expression (e.g., <code class="text-xs">daily</code>, <code class="text-xs">"Mon..Fri 09:00"</code>). Validated via <code class="text-xs">systemd-analyze calendar</code>.</li>
466
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--on-boot &lt;duration&gt;</code>: Delay execution relative to system boot (e.g., <code class="text-xs">5m</code>).</li>
467
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--on-active &lt;duration&gt;</code>: Delay execution relative to timer activation.</li>
468
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--random-delay &lt;duration&gt;</code>: Adds randomized delay jitter (<code class="text-xs">RandomizedDelaySec</code>).</li>
469
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--persistent</code>: Sets <code class="text-xs">Persistent=true</code> to execute missed schedules immediately after system wake/boot.</li>
470
- <li><code class="text-xs font-bold text-slate-800 dark:text-slate-200">--start</code>: Enables and starts the timer unit immediately after creation.</li>
471
- </ul>
507
+ unitup schedule-status cleanup</code></pre>
472
508
  </div>
473
509
  </div>
474
510
  </section>
@@ -477,122 +513,40 @@ unitup schedule-logs cleanup</code></pre>
477
513
  <section id="api" class="doc-section mb-14">
478
514
  <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Programmatic API</h2>
479
515
  <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
480
- unitup exports full ESM and CommonJS interfaces with TypeScript declarations (<code class="text-cyan-600 dark:text-cyan-400">index.d.ts</code>).
516
+ unitup exports full ESM and CommonJS interfaces with complete TypeScript declarations (<code class="text-cyan-600 dark:text-cyan-400">index.d.ts</code>).
481
517
  </p>
482
518
 
483
519
  <div class="space-y-6">
484
520
  <div>
485
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">ESM / TypeScript Example</h3>
521
+ <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">Cross-Platform Service Manager</h3>
486
522
  <pre><code class="language-typescript">import {
523
+ ServiceManager,
524
+ getAdapter,
525
+ getPlatformCapabilities,
487
526
  createService,
488
- startService,
489
- stopService,
490
- restartService,
491
527
  getServiceStatus,
492
- listServices,
493
- isSystemdAvailable
528
+ listServices
494
529
  } from "unitup";
495
530
 
496
- import type {
497
- CreateServiceOptions,
498
- ServiceStatus
499
- } from "unitup";
500
-
501
- if (await isSystemdAvailable()) {
502
- // Add service with explicit command + args
503
- await createService({
504
- name: "worker",
505
- command: "/usr/bin/python3",
506
- args: ["/home/user/apps/worker.py"],
507
- cwd: "/home/user/apps",
508
- restart: "on-failure",
509
- start: true
510
- });
511
-
512
- const status: ServiceStatus = await getServiceStatus("worker");
513
- console.log(`PID: ${status.pid}, Status: ${status.status}`);
514
- }</code></pre>
515
- </div>
531
+ // High-level service manager (auto-resolves current OS adapter)
532
+ const manager = new ServiceManager();
516
533
 
517
- <div>
518
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">CommonJS Support</h3>
519
- <pre><code class="language-javascript">const {
520
- createService,
521
- startService,
522
- getServiceStatus
523
- } = require("unitup");
524
-
525
- await createService({
534
+ // Install and start service
535
+ await manager.install({
526
536
  name: "api",
527
537
  script: "./server.js",
528
- start: true
529
- });</code></pre>
530
- </div>
531
- </div>
532
- </section>
533
-
534
- <!-- Section: Declarative Roadmap -->
535
- <section id="declarative" class="doc-section mb-14">
536
- <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Declarative Stack Configuration (Roadmap Preview)</h2>
537
- <p class="text-slate-600 dark:text-slate-400 mb-6 leading-relaxed">
538
- Define your entire application stack declaratively using <code class="text-cyan-600 dark:text-cyan-400">unitup.yml</code> or <code class="text-cyan-600 dark:text-cyan-400">unitup.json</code>:
539
- </p>
540
-
541
- <div class="grid md:grid-cols-2 gap-6 mb-4">
542
- <div>
543
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2"><code class="text-xs">unitup.yml</code> Spec</h3>
544
- <pre><code class="language-yaml">apps:
545
- api:
546
- runtime: node
547
- script: ./server.js
548
- env:
549
- NODE_ENV: production
550
- PORT: 3000
551
- start: true
552
-
553
- worker:
554
- runtime: python
555
- script: ./worker.py
556
- env:
557
- APP_ENV: production
558
-
559
- native-service:
560
- runtime: native
561
- command: ./server</code></pre>
562
- </div>
538
+ env: { NODE_ENV: "production" }
539
+ }, { start: true });
563
540
 
564
- <div>
565
- <h3 class="text-sm font-semibold uppercase tracking-wider text-cyan-600 dark:text-cyan-400 mb-2">Planned Declarative Commands</h3>
566
- <pre><code class="language-bash"># Preview differences against active units
567
- unitup diff
541
+ // Check status
542
+ const status = await manager.status("api");
543
+ console.log(`State: ${status.state}, PID: ${status.pid}, Platform: ${status.platform}`);
568
544
 
569
- # Apply unitup.yml configuration
570
- unitup apply
571
-
572
- # Perform batch operations on group
573
- unitup restart @default</code></pre>
545
+ // Inspect capabilities
546
+ const caps = getPlatformCapabilities();
547
+ console.log(`Service Manager: ${caps.serviceManager}`);</code></pre>
574
548
  </div>
575
549
  </div>
576
-
577
- <p class="text-xs text-slate-500 dark:text-slate-500">
578
- *Note: Relative script, command, cwd, and env-file paths in <code class="text-xs">unitup.yml</code> are resolved relative to the configuration file.
579
- </p>
580
- </section>
581
-
582
- <!-- Section: Troubleshooting -->
583
- <section id="troubleshooting" class="doc-section mb-14">
584
- <h2 class="text-2xl font-bold text-slate-900 dark:text-white mb-4">Troubleshooting & User Lingering</h2>
585
-
586
- <div class="p-5 rounded-xl border border-slate-200 dark:border-slate-800 bg-white/70 dark:bg-slate-900/50 space-y-4">
587
- <h3 class="font-bold text-slate-900 dark:text-white">Enable User Lingering (Persistent Services)</h3>
588
- <p class="text-sm text-slate-600 dark:text-slate-400 leading-relaxed">
589
- 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:
590
- </p>
591
- <pre><code class="language-bash">loginctl enable-linger $USER</code></pre>
592
- <p class="text-xs text-slate-500 dark:text-slate-500">
593
- Verify lingering state anytime with <code class="text-xs">unitup doctor</code>. unitup will warn if lingering is disabled but will never prompt for sudo automatically.
594
- </p>
595
- </div>
596
550
  </section>
597
551
 
598
552
  <!-- Footer -->