From 310127cf7a7ae10335c297d1457d83931d5a5a3a Mon Sep 17 00:00:00 2001 From: buenosair Date: Wed, 2 Sep 2026 11:51:47 +0000 Subject: [PATCH] fix(model selection): deploys from dotfiles-less machines no longer wipe the remote baked pi config (deploy.sh excludes docker/pi-agent); resync endpoint fixed for in-container runs (bash/rsync/python3/npm in daemon image, cross-device copy instead of rename) --- daemon/Dockerfile | 4 +++- daemon/pi-config.go | 9 +++++++-- deploy/deploy.sh | 9 +++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/daemon/Dockerfile b/daemon/Dockerfile index b9f0853..a90de12 100644 --- a/daemon/Dockerfile +++ b/daemon/Dockerfile @@ -10,7 +10,9 @@ COPY daemon/ ./ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/lvmh-daemon . FROM alpine:3.21 -RUN apk add --no-cache ca-certificates git +# bash + rsync: POST /api/pi-config/resync runs deploy/rsync-pi-agent.sh +# inside this container (alpine has neither by default) +RUN apk add --no-cache ca-certificates git bash rsync python3 nodejs npm WORKDIR /app COPY --from=build /out/lvmh-daemon /app/lvmh-daemon # Placeholder UI; replace via build (cp web/dist daemon/webdist) or mount at diff --git a/daemon/pi-config.go b/daemon/pi-config.go index bf1a87d..dd6fc46 100644 --- a/daemon/pi-config.go +++ b/daemon/pi-config.go @@ -100,10 +100,15 @@ func (s *Server) handlePiConfigResync(w http.ResponseWriter, r *http.Request) { writeError(w, http.StatusInternalServerError, "clear stale pi-agent: "+err.Error()) return } - if err := os.Rename(bakeDir, filepath.Join(bakeCtx, "docker", "pi-agent")); err != nil { - writeError(w, http.StatusInternalServerError, "move bake dir: "+err.Error()) + // copy, not rename: bakeDir (data volume) and bakeCtx (tmp) are + // different mounts — rename(2) fails with EXDEV + if err := copyTree(bakeDir, filepath.Join(bakeCtx, "docker", "pi-agent")); err != nil { + writeError(w, http.StatusInternalServerError, "copy bake dir: "+err.Error()) return } + if err := os.RemoveAll(bakeDir); err != nil { + log.Printf("pi-config: remove bake dir after copy: %v", err) + } if err := s.spawn.buildImage(ctx, bakeCtx, filepath.Join(bakeCtx, "docker", "worker.Dockerfile"), imageRefWorker); err != nil { writeError(w, http.StatusInternalServerError, "worker rebuild: "+err.Error()) diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 16af12d..3db3809 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -22,10 +22,19 @@ fi # Bake the user's pi config (dotfiles) into the worker image context. bash "$(dirname "$0")/rsync-pi-agent.sh" +# A dotfiles-less checkout must not wipe the remote's baked pi config +# (daemon catalog + worker image depend on it). +PIAGENT_EXCLUDE="" +if [ ! -f docker/pi-agent/settings.json ]; then + echo "no local pi config — preserving remote docker/pi-agent" + PIAGENT_EXCLUDE="--exclude /docker/pi-agent" +fi + rsync -az --delete \ --exclude /.git --exclude /node_modules --exclude /web/node_modules \ --exclude /.env --exclude /.scratch --exclude /.pi --exclude /coverage \ --exclude '*.db' --exclude /daemon/lvmh-daemon --exclude /.playwright-mcp \ + ${PIAGENT_EXCLUDE} \ ./ "$REMOTE:$REMOTE_DIR/" echo "building daemon image + worker image on $REMOTE..."