feat: service-managed UI self-update (#1210)

* feat: add service-managed self-update

* chore: add temporary self-update test scripts

* chore: simplify temporary script markdown fences

* chore: run frontend in temporary self-update scripts

* fix: show self-update job progress after apply

* chore: add real npm self-update test script

* fix: isolate npm self-update prefix

* fix: detect npm service installs from bin shim

* chore: reset service before real npm update test

* chore: expand real npm status diagnostics

* fix: preserve service home during self-update

* fix(cli): tee self-update helper output to a log file

* fix(cli): avoid launchd bootstrap race when reloading the macOS service

* fix(backend): run macOS self-update helper once via transient launchd plist

* fix(web): show self-update progress and lock the apply button until the update lands

* fix(cli): reinstall via the kandev wrapper on Homebrew self-update

* chore: remove temp self-update test scripts

* fix(web): drop unused apply path from useUpdates hook

* fix(backend): snapshot install state once in apply preflight

* docs: align self-update docs with transient LaunchAgent flow

* chore(release): run cli bundle from apps workspace root

* fix(backend): guard against concurrent self-update applies

* fix(backend): check scheme and helper paths in self-update apply

* fix(backend): drop duplicate binary name from npx manual command

* fix(cli): allow --help for service self-update without --intent

* fix(cli): harden self-update dir perms and darwin uid resolution

* fix(web): set required POST fields last in applyUpdate

* docs: use JSON body notation for the apply endpoint

* fix(backend): expire self-update guard so a stuck helper cannot wedge apply

* refactor(cli): collapse redundant writeSync branch in self-update log
This commit is contained in:
José Almeida
2026-06-01 17:49:15 +01:00
committed by GitHub
parent 58dd2773a2
commit 041a19f060
44 changed files with 3630 additions and 136 deletions
+18 -5
View File
@@ -1,6 +1,6 @@
# Run Kandev as a Service
Install Kandev as an OS-managed service (systemd on Linux, launchd on macOS) so it auto-starts and stays running. Updates remain manual: `npm i -g kandev@latest` or `brew upgrade kandev`, then re-run `kandev service install`.
Install Kandev as an OS-managed service (systemd on Linux, launchd on macOS) so it auto-starts and stays running. User-mode services installed by `kandev service install` can self-update from the System → Updates page. Non-service installs and `--system` services still update manually: `npm i -g kandev@latest` or `brew upgrade kandev`, then re-run `kandev service install`.
This guide assumes you've already installed kandev via [Homebrew or npm](../apps/cli/README.md#quick-start) and that `kandev` works when run interactively.
@@ -65,9 +65,11 @@ kandev service config [--system]
## After an Upgrade
Both `npm` and Homebrew install kandev under a versioned directory (e.g. `node_modules/kandev/0.49.0/`, `Cellar/kandev/0.49.0/`). When you upgrade, the old version directory is removed and replaced — but the unit file you installed earlier still hard-codes the old absolute path.
If Kandev is running as a user-mode service installed by `kandev service install`, open **Settings → System → Updates** and use **Apply update** when it appears. The button is shown only when the backend can prove it is running from a kandev-managed service unit/plist with valid service metadata.
**Fix:** re-run install. It's idempotent.
Both `npm` and Homebrew install kandev under a versioned directory (e.g. `node_modules/kandev/0.49.0/`, `Cellar/kandev/0.49.0/`). Manual upgrades replace those paths, so the unit file must be refreshed afterward.
**Manual fix:** re-run install. It's idempotent.
```bash
npm i -g kandev@latest # or: brew upgrade kandev
@@ -76,6 +78,8 @@ kandev service install # rewrites the unit with the new paths
If you launch `kandev` interactively after an upgrade, it will detect a stale unit and print a one-line reminder. You can also check with `kandev service config` — the `cli entry:` and `node path:` lines tell you the paths that *would* be baked in by the next install.
System services (`kandev service install --system`) do not expose UI self-update. Update them from a privileged shell, then re-run `sudo kandev service install --system`.
## Linux Boot-Start (`loginctl enable-linger`)
Linux user services normally run only while you're logged in. To keep kandev running across reboots without an active SSH session, run **once**:
@@ -110,6 +114,11 @@ ExecStart=/usr/local/bin/node /usr/local/lib/node_modules/kandev/bin/cli.js --he
Environment=KANDEV_HOME_DIR=/home/alice/.kandev
Environment=KANDEV_LOG_LEVEL=info
Environment=PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin
Environment=KANDEV_RUNNING_AS_SERVICE=true
Environment=KANDEV_SERVICE_MODE=user
Environment=KANDEV_SERVICE_MANAGER=systemd
Environment=KANDEV_INSTALL_KIND=npm
Environment=KANDEV_SERVICE_METADATA=/home/alice/.kandev/service/install.json
Restart=on-failure
RestartSec=5s
KillMode=mixed
@@ -119,7 +128,7 @@ TimeoutStopSec=30s
WantedBy=default.target
```
The `--headless` flag tells the CLI not to open a browser (you'll connect to it remotely or via `localhost`).
The `--headless` flag tells the CLI not to open a browser (you'll connect to it remotely or via `localhost`). The `KANDEV_SERVICE_*` variables and `<home>/service/install.json` metadata let the backend verify that UI self-update is safe before it shows the Apply button.
## Troubleshooting
@@ -151,11 +160,15 @@ This happens with `--system` if `SUDO_USER` isn't set (e.g. you logged in as roo
### After upgrading, the service silently keeps running the old version
The OS service manager keeps running whatever `ExecStart` it has — it doesn't know about npm/brew upgrades. **Always re-run `kandev service install` after an upgrade** so the unit picks up the new paths, then `kandev service restart` to pick up new code.
The OS service manager keeps running whatever `ExecStart` it has — it doesn't know about npm/brew upgrades. For managed user services, use **Apply update** on the Updates page. Otherwise, **always re-run `kandev service install` after an upgrade** so the unit picks up the new paths, then `kandev service restart` to pick up new code.
## Updating: TL;DR
```bash
# Option A: managed user service
# Use Settings -> System -> Updates -> Apply update
# Option B: manual / system service
# 1. Update the binary
npm i -g kandev@latest # or: brew upgrade kandev