feat(power): keep the machine awake while Codeman runs, lid close included

A laptop that suspends freezes every agent session until it wakes. The new
opt-in setting (App Settings > System > Power, off by default, "Only on AC
power" on by default) makes the server hold an OS sleep lock for exactly as
long as it runs:

- Linux: a logind block lock on handle-lid-switch:sleep:idle through
  systemd-inhibit. The lid needs the low-level handle-lid-switch lock
  (LidSwitchIgnoreInhibited=yes ignores a plain sleep lock), and polkit grants
  it only while someone is logged in to the desktop, so a refusal is reported
  as "denied" and retried every minute.
- macOS: caffeinate -i -s -w <pid>. Lid close needs pmset disablesleep, which
  an optional root helper (scripts/keep-awake-macos.sh, a LaunchDaemon run
  from a root-owned copy) applies while the server keeps a fresh request
  file, undoing only a disablesleep it set itself.

The lock dies with the server: systemd-inhibit runs cat on a stdin pipe, so
any exit (SIGKILL included, and under the unit's KillMode=process) releases
it; caffeinate exits with the pid it watches.

The installer asks on laptops (default no, never under --yes), and
`install.sh keep-awake` turns it on for an existing install. Status is at
GET /api/system/keep-awake; a non-admin's value is dropped in multi-user mode.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-10-10 07:21:57 +02:00
parent 3d59e59e37
commit 233f85b170
19 changed files with 1960 additions and 31 deletions
+6
View File
@@ -57,6 +57,11 @@ unattended. You can leave while it builds. What it asks you:
4. **Whether to run Codeman in the background.** Enter installs a systemd user service or a
macOS LaunchAgent that starts on boot; answering no offers to start it in this terminal
instead, or not at all.
5. **On a laptop only: keep it awake while Codeman runs?** Closing the lid suspends the
machine, and every agent session freezes until it wakes. Yes turns on App Settings >
System > **Power** (only while plugged in). On a Mac it also offers a small root helper,
because macOS sleeps on lid close whatever an app asks; it needs your admin password
once. The default is no, and `--yes` never turns it on.
It ends on a screen with the URL (your tailnet, your network, or this machine), a QR code to
scan with your phone, and the two commands you need to manage the service.
@@ -75,6 +80,7 @@ install.sh uninstall # remove (offers to undo a rename it performed)
install.sh tailscale # retrofit Tailscale access onto an existing install
install.sh name [<n>] # rename this machine on your tailnet (default codeman-<hostname>)
install.sh cloudflared # install cloudflared for the in-app Cloudflare tunnel
install.sh keep-awake # keep this machine awake while Codeman runs (macOS: adds the lid helper)
```
**Flags** answer the questions from the command line and pipe through `bash -s --`: