FreeBSD auto-update (#1254): determineArch() now includes freebsd in its
OS switch, producing freebsd-amd64/arm64 instead of falling through to
a uname -m fallback that incorrectly returned linux-<arch>. FreeBSD agents
were downloading Linux ELF binaries and failing to exec them.
Docker rootless socket (#1200): buildRuntimeCandidates() now probes
/run/user/<uid>/docker.sock before the system-wide /var/run/docker.sock,
enabling auto-detection of Docker rootless installations.
Duplicate PVE/PBS hosts (#1245, #1252): handleSecureAutoRegister() now
deduplicates by host URL, updating the existing instance's token in-place
instead of appending a duplicate entry on each re-run of the setup script.
Fixes#1254Fixes#1200Fixes#1245Fixes#1252
(cherry picked from commit 0f1d9e9b9fea6c8b9e65872e8a78e25f93653eef)
When syscall.Exec() fails after the binary has already been atomically
replaced on disk, the old process would log an error and keep running
indefinitely with stale code. The next update check (1 hour later) sees
the on-disk version matches the server and skips the update — so the
restart is never retried.
Now the agent exits with code 1 when this happens, allowing systemd (or
any service manager) to restart it with the new binary. This fixes the
"temperature broken after each upgrade" reports where users had to
manually reinstall the agent after every Pulse server upgrade.
Fixes#1247
- Add persistent volume mounts for Go/npm caches (faster rebuilds)
- Add shell config with helpful aliases and custom prompt
- Add comprehensive devcontainer documentation
- Add pre-commit hooks for Go formatting and linting
- Use go-version-file in CI workflows instead of hardcoded versions
- Simplify docker compose commands with --wait flag
- Add gitignore entries for devcontainer auth files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
syscall.Exec is not supported on Windows, causing self-update to fail
with "failed to restart: not supported by windows".
Split restart logic into platform-specific files:
- restart_unix.go: Uses syscall.Exec for in-place process replacement
- restart_windows.go: Uses os.Exit(0) to let Windows SCM restart service
Related to #735
- Move normalizeVersion to utils.NormalizeVersion for single source of truth
- Update agentupdate and dockeragent packages to use shared function
- Add 14 test cases for version normalization
This prevents bugs like issue #773 where a fix applied to one copy
but not the other caused an update loop.
The agent's CurrentVersion includes the "v" prefix (e.g., "v4.33.1") but
the server's /api/agent/version endpoint returns versions without it
(e.g., "4.33.1"). This caused the comparison to always fail, triggering
an infinite self-update loop every 30 seconds.
Normalize both versions by stripping the "v" prefix before comparison.
Related to #740
When the agent binary is symlinked (e.g., from /opt/pulse/bin to
/usr/local/bin), the self-update would fail with "invalid cross-device
link" because os.Rename() doesn't work across filesystems.
Now resolves symlinks before update and creates the temp file in the
same directory as the real binary.
Related to #737
Implement self-update capability for the unified pulse-agent binary:
- Add internal/agentupdate package with cross-platform update logic
- Hourly version checks against /api/agent/version endpoint
- SHA256 checksum verification for downloaded binaries
- Atomic binary replacement with backup/rollback on failure
- Support for Linux, macOS, and Windows (10 platform/arch combinations)
Build and release changes:
- Dockerfile builds unified agent for all platforms
- build-release.sh includes unified agent in release artifacts
- validate-release.sh validates unified agent binaries
- Install scripts (install.sh, install.ps1) use correct URL format
Related to #727, #737