From dedd29045b40c458b872ec74afdcbecb691ce0d5 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Apr 2026 16:03:29 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20bug:=20agents=20container=20has=20two=20?= =?UTF-8?q?diverging=20copies=20of=20disinto=20code=20=E2=80=94=20entrypoi?= =?UTF-8?q?nt=20runs=20baked-in=20stale=20version=20while=20dev-agent=20wo?= =?UTF-8?q?rks=20in=20fresh=20git=20checkout=20(#593)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/agents/entrypoint.sh | 71 ++++++++++++++++++++++++++++++++++++- lib/generators.sh | 2 ++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/docker/agents/entrypoint.sh b/docker/agents/entrypoint.sh index 4736328..bc6891f 100644 --- a/docker/agents/entrypoint.sh +++ b/docker/agents/entrypoint.sh @@ -16,7 +16,9 @@ set -euo pipefail # - planner: every 12 hours (144 iterations * 5 min) # - predictor: every 24 hours (288 iterations * 5 min) -DISINTO_DIR="/home/agent/disinto" +DISINTO_BAKED="/home/agent/disinto" +DISINTO_LIVE="/home/agent/repos/_factory" +DISINTO_DIR="$DISINTO_BAKED" # start with baked copy; switched to live checkout after bootstrap LOGFILE="/home/agent/data/agent-entrypoint.log" # Create all expected log subdirectories and set ownership as root before dropping to agent. @@ -208,6 +210,67 @@ print(cfg.get('primary_branch', 'main')) done } +# Bootstrap the factory (disinto) repo from Forgejo into the project-repos +# volume so the entrypoint runs from a live git checkout that receives +# updates via `git pull`, not the stale baked copy from `COPY .` (#593). +bootstrap_factory_repo() { + local repo="${FACTORY_REPO:-}" + if [ -z "$repo" ]; then + log "Factory bootstrap: FACTORY_REPO not set — running from baked copy" + return 0 + fi + + local remote_url="${FORGE_URL}/${repo}.git" + local primary_branch="${PRIMARY_BRANCH:-main}" + + if [ ! -d "${DISINTO_LIVE}/.git" ]; then + log "Factory bootstrap: cloning ${repo} -> ${DISINTO_LIVE}" + if gosu agent git clone --quiet --branch "$primary_branch" "$remote_url" "$DISINTO_LIVE" 2>&1; then + log "Factory bootstrap: cloned successfully" + else + log "Factory bootstrap: clone failed — running from baked copy" + return 0 + fi + else + log "Factory bootstrap: pulling latest ${repo}" + gosu agent bash -c " + cd '${DISINTO_LIVE}' && \ + git fetch origin '${primary_branch}' --quiet 2>/dev/null && \ + git reset --hard 'origin/${primary_branch}' --quiet 2>/dev/null + " || log "Factory bootstrap: pull failed — using existing checkout" + fi + + # Copy project TOMLs from baked dir — they are gitignored AND docker-ignored, + # so neither the image nor the clone normally contains them. If the baked + # copy has any (e.g. operator manually placed them), propagate them. + if compgen -G "${DISINTO_BAKED}/projects/*.toml" >/dev/null 2>&1; then + mkdir -p "${DISINTO_LIVE}/projects" + cp "${DISINTO_BAKED}"/projects/*.toml "${DISINTO_LIVE}/projects/" + chown -R agent:agent "${DISINTO_LIVE}/projects" + log "Factory bootstrap: copied project TOMLs to live checkout" + fi + + # Verify the live checkout has the expected structure + if [ -f "${DISINTO_LIVE}/lib/env.sh" ]; then + DISINTO_DIR="$DISINTO_LIVE" + log "Factory bootstrap: DISINTO_DIR switched to live checkout at ${DISINTO_LIVE}" + else + log "Factory bootstrap: live checkout missing expected files — falling back to baked copy" + fi +} + +# Pull latest factory code at the start of each poll iteration (#593). +# Runs as the agent user; failures are non-fatal (stale code still works). +pull_factory_repo() { + [ "$DISINTO_DIR" = "$DISINTO_LIVE" ] || return 0 + local primary_branch="${PRIMARY_BRANCH:-main}" + gosu agent bash -c " + cd '${DISINTO_LIVE}' && \ + git fetch origin '${primary_branch}' --quiet 2>/dev/null && \ + git reset --hard 'origin/${primary_branch}' --quiet 2>/dev/null + " || log "Factory pull failed — continuing with current checkout" +} + # Configure git and tea once at startup (as root, then drop to agent) configure_git_creds configure_tea_login @@ -215,6 +278,9 @@ configure_tea_login # Bootstrap ops repos from forgejo into container volumes (#586) bootstrap_ops_repos +# Bootstrap factory repo — switch DISINTO_DIR to live checkout (#593) +bootstrap_factory_repo + # Initialize state directory for check_active guards init_state_dir @@ -234,6 +300,9 @@ while true; do iteration=$((iteration + 1)) now=$(date +%s) + # Pull latest factory code so poll scripts stay current (#593) + pull_factory_repo + # Stale .sid cleanup — needed for agents that don't support --resume # Run this as the agent user gosu agent bash -c "rm -f /tmp/dev-session-*.sid /tmp/review-session-*.sid 2>/dev/null || true" diff --git a/lib/generators.sh b/lib/generators.sh index 58c7dbf..4185753 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -337,7 +337,9 @@ services: CLAUDE_TIMEOUT: ${CLAUDE_TIMEOUT:-7200} CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: ${CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:-1} ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + FORGE_PASS: ${FORGE_PASS:-} FORGE_ADMIN_PASS: ${FORGE_ADMIN_PASS:-} + FACTORY_REPO: ${FORGE_REPO:-disinto-admin/disinto} DISINTO_CONTAINER: "1" PROJECT_REPO_ROOT: /home/agent/repos/${PROJECT_NAME:-project} WOODPECKER_DATA_DIR: /woodpecker-data