diff --git a/bin/disinto b/bin/disinto index 0f81b1b..8506511 100755 --- a/bin/disinto +++ b/bin/disinto @@ -664,6 +664,10 @@ p.write_text(text) preflight_check "$forge_repo" "$forge_url" # Determine repo root (for new projects) + # This host-side clone is operator-only convenience (#589): it enables + # `cd ~/project && $EDITOR .` but is NOT read by agents at runtime. + # Agents clone independently from FORGE_URL/FORGE_REPO into the + # project-repos named volume at /home/agent/repos/${project_name}. repo_root="${repo_root:-/home/${USER}/${project_name}}" # Clone or validate (try origin first for initial clone from upstream) diff --git a/docker/agents/entrypoint.sh b/docker/agents/entrypoint.sh index 02e674f..3b901c7 100644 --- a/docker/agents/entrypoint.sh +++ b/docker/agents/entrypoint.sh @@ -237,6 +237,32 @@ bootstrap_factory_repo() { fi } +# Ensure the project repo is cloned on first run (#589). +# The agents container uses a named volume (project-repos) at /home/agent/repos. +# On first startup, if the project repo is missing, clone it from FORGE_URL/FORGE_REPO. +# This makes the agents container self-healing and independent of init's host clone. +ensure_project_clone() { + # shellcheck disable=SC2153 + local repo_dir="/home/agent/repos/${PROJECT_NAME}" + if [ -d "${repo_dir}/.git" ]; then + log "Project repo present at ${repo_dir}" + return 0 + fi + if [ -z "${FORGE_REPO:-}" ] || [ -z "${FORGE_URL:-}" ]; then + log "Cannot clone project repo: FORGE_REPO or FORGE_URL unset" + return 1 + fi + log "Cloning ${FORGE_URL}/${FORGE_REPO}.git -> ${repo_dir} (first run)" + mkdir -p "$(dirname "$repo_dir")" + chown -R agent:agent "$(dirname "$repo_dir")" + if gosu agent git clone --quiet "${FORGE_URL}/${FORGE_REPO}.git" "$repo_dir"; then + log "Project repo cloned" + else + log "Project repo clone failed — agents may fail until manually fixed" + return 1 + 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() { @@ -253,6 +279,9 @@ pull_factory_repo() { _setup_git_creds configure_tea_login +# Clone project repo on first run (makes agents self-healing, #589) +ensure_project_clone + # Bootstrap ops repos from forgejo into container volumes (#586) bootstrap_ops_repos diff --git a/lib/generators.sh b/lib/generators.sh index 8cae400..aeed75d 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -116,6 +116,7 @@ _generate_local_model_services() { - \${HOME}/.ssh:/home/agent/.ssh:ro environment: FORGE_URL: http://forgejo:3000 + FORGE_REPO: ${FORGE_REPO:-disinto-admin/disinto} # Use llama-specific credentials if available, otherwise fall back to main FORGE_TOKEN FORGE_TOKEN: \${FORGE_TOKEN_LLAMA:-\${FORGE_TOKEN:-}} FORGE_PASS: \${FORGE_PASS_LLAMA:-\${FORGE_PASS:-}} @@ -132,6 +133,7 @@ _generate_local_model_services() { CLAUDE_CODE_ATTRIBUTION_HEADER: "0" CLAUDE_CODE_ENABLE_TELEMETRY: "0" DISINTO_CONTAINER: "1" + PROJECT_NAME: ${PROJECT_NAME:-project} PROJECT_REPO_ROOT: /home/agent/repos/${PROJECT_NAME:-project} WOODPECKER_DATA_DIR: /woodpecker-data WOODPECKER_REPO_ID: "${wp_repo_id}" @@ -327,6 +329,7 @@ services: - woodpecker-data:/woodpecker-data:ro environment: FORGE_URL: http://forgejo:3000 + FORGE_REPO: ${FORGE_REPO:-disinto-admin/disinto} FORGE_TOKEN: ${FORGE_TOKEN:-} FORGE_REVIEW_TOKEN: ${FORGE_REVIEW_TOKEN:-} FORGE_PLANNER_TOKEN: ${FORGE_PLANNER_TOKEN:-} @@ -344,6 +347,7 @@ services: FORGE_ADMIN_PASS: ${FORGE_ADMIN_PASS:-} FACTORY_REPO: ${FORGE_REPO:-disinto-admin/disinto} DISINTO_CONTAINER: "1" + PROJECT_NAME: ${PROJECT_NAME:-project} PROJECT_REPO_ROOT: /home/agent/repos/${PROJECT_NAME:-project} WOODPECKER_DATA_DIR: /woodpecker-data WOODPECKER_REPO_ID: "PLACEHOLDER_WP_REPO_ID"