#!/usr/bin/env bash # setup-devcontainer.sh # # Adds the PMOCrazyCoder devcontainer environment to any project. # Usage: bash setup-devcontainer.sh [project-dir] # # Example (run from the project root): # bash setup-devcontainer.sh # # Or download and run directly: # curl -fsSL https://gargoton.petite-maison-orange.fr/eric/PMOCrazycoder/raw/branch/main/setup-devcontainer.sh | bash set -euo pipefail PROJECT_DIR="${1:-$(pwd)}" DEVCONTAINER_DIR="$PROJECT_DIR/.devcontainer" LOCAL_LLM_API="${LOCAL_LLM_API:-http://host.docker.internal:1248/v1}" GIT_RAW="https://gargoton.petite-maison-orange.fr/eric/PMOCrazycoder/raw/branch/main" # --- Colors --- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RESET='\033[0m' info() { echo -e "${GREEN}[setup]${RESET} $*"; } warning() { echo -e "${YELLOW}[setup]${RESET} $*"; } error() { echo -e "${RED}[setup]${RESET} $*" >&2; exit 1; } fetch() { local src="$1" dst="$2" curl -fsSL "$GIT_RAW/$src" -o "$dst" \ || error "Failed to fetch $src from $GIT_RAW" } # --- Checks --- [[ -d "$PROJECT_DIR" ]] || error "Directory not found: $PROJECT_DIR" command -v curl >/dev/null || error "curl is required" # --- .devcontainer/ --- info "Creating .devcontainer structure in $PROJECT_DIR" mkdir -p "$DEVCONTAINER_DIR/config/claude" mkdir -p "$DEVCONTAINER_DIR/config/opencode" mkdir -p "$DEVCONTAINER_DIR/config/aichat" mkdir -p "$DEVCONTAINER_DIR/config/ai_index" mkdir -p "$DEVCONTAINER_DIR/config/cargo-registry" mkdir -p "$DEVCONTAINER_DIR/config/cargo-git" mkdir -p "$DEVCONTAINER_DIR/config/cargo-bin" mkdir -p "$DEVCONTAINER_DIR/config/go-cache" mkdir -p "$DEVCONTAINER_DIR/config/go-bin" mkdir -p "$DEVCONTAINER_DIR/config/python-local" mkdir -p "$DEVCONTAINER_DIR/config/zed" mkdir -p "$DEVCONTAINER_DIR/config/npm-cache" mkdir -p "$DEVCONTAINER_DIR/config/r-libs" # --- devcontainer.json --- DEVCONTAINER_JSON="$DEVCONTAINER_DIR/devcontainer.json" if [[ -f "$DEVCONTAINER_JSON" ]]; then warning "devcontainer.json already exists, skipping" else fetch ".devcontainer/devcontainer.json" "$DEVCONTAINER_JSON" PROJECT_NAME="$(basename "$PROJECT_DIR")" SERVICE_NAME="crazycoder-${PROJECT_NAME}" # Patch display name and service reference sed -i.bak \ -e "s/\"name\": \"PMOCrazyCoder\"/\"name\": \"${PROJECT_NAME}\"/" \ -e "s/\"service\": \"pmocrazycoder\"/\"service\": \"${SERVICE_NAME}\"/" \ "$DEVCONTAINER_JSON" rm -f "$DEVCONTAINER_JSON.bak" info "Created devcontainer.json" fi # --- docker-compose.yml --- COMPOSE_FILE="$DEVCONTAINER_DIR/docker-compose.yml" if [[ -f "$COMPOSE_FILE" ]]; then warning "docker-compose.yml already exists, skipping" else fetch ".devcontainer/docker-compose.yml" "$COMPOSE_FILE" PROJECT_NAME="$(basename "$PROJECT_DIR")" SERVICE_NAME="crazycoder-${PROJECT_NAME}" # Rename the service to avoid collision with project's own Docker services sed -i.bak "s/^ pmocrazycoder:/ ${SERVICE_NAME}:/" "$COMPOSE_FILE" # Patch LOCAL_LLM_API if overridden if [[ "$LOCAL_LLM_API" != "http://host.docker.internal:1248/v1" ]]; then sed -i.bak "s|http://host.docker.internal:1248/v1|${LOCAL_LLM_API}|g" "$COMPOSE_FILE" fi rm -f "$COMPOSE_FILE.bak" info "Created docker-compose.yml" fi # --- .env --- ENV_FILE="$DEVCONTAINER_DIR/.env" if [[ -f "$ENV_FILE" ]]; then warning ".env already exists, skipping" else # Détecter la forge depuis l'origin git du projet DETECTED_GITEA_URL="" IS_GITHUB=false if command -v git >/dev/null && git -C "$PROJECT_DIR" rev-parse --git-dir &>/dev/null; then ORIGIN_URL=$(git -C "$PROJECT_DIR" remote get-url origin 2>/dev/null || true) if [[ -n "$ORIGIN_URL" ]]; then # Extraire scheme + host (supporte https://host/... et git@host:...) if [[ "$ORIGIN_URL" =~ ^(https?://[^/]+) ]]; then ORIGIN_HOST="${BASH_REMATCH[1]}" elif [[ "$ORIGIN_URL" =~ ^git@([^:]+): ]]; then ORIGIN_HOST="https://${BASH_REMATCH[1]}" fi if [[ "${ORIGIN_HOST:-}" == *"github.com"* ]]; then IS_GITHUB=true info "Forge détectée : GitHub" elif [[ -n "${ORIGIN_HOST:-}" ]]; then # Tester si c'est un Gitea/Forgejo via son API if curl -fsSL --max-time 5 "${ORIGIN_HOST}/api/v1/version" 2>/dev/null | grep -q '"version"'; then DETECTED_GITEA_URL="$ORIGIN_HOST" info "Forge détectée : Gitea/Forgejo ($DETECTED_GITEA_URL)" else warning "Forge non reconnue pour $ORIGIN_HOST (ni GitHub ni Gitea/Forgejo)" fi fi fi fi { echo "# Secrets du devcontainer — ne pas committer" echo "" if $IS_GITHUB; then echo "# GitHub" echo "GITHUB_TOKEN=" else echo "# GitHub (non détecté pour ce projet)" echo "# GITHUB_TOKEN=" fi echo "" if [[ -n "$DETECTED_GITEA_URL" ]]; then echo "# Gitea" echo "GITEA_URL=${DETECTED_GITEA_URL}" echo "GITEA_TOKEN=" else echo "# Gitea (non détecté pour ce projet)" echo "# GITEA_URL=" echo "# GITEA_TOKEN=" fi } > "$ENV_FILE" info "Created .env" fi # --- .gitignore --- GITIGNORE="$PROJECT_DIR/.gitignore" if [[ -f "$GITIGNORE" ]]; then if grep -q "\.devcontainer/config/" "$GITIGNORE"; then warning ".gitignore already contains .devcontainer/config/, skipping" else printf '\n# PMOCrazyCoder devcontainer runtime config\n.devcontainer/config/\n.devcontainer/.env\n' >> "$GITIGNORE" info "Updated .gitignore" fi else printf '# PMOCrazyCoder devcontainer runtime config\n.devcontainer/config/\n.devcontainer/.env\n' > "$GITIGNORE" info "Created .gitignore" fi echo info "Done. Next steps:" echo " 1. Renseigner les tokens dans .devcontainer/.env" echo " 2. Open the project in VS Code / Zed / Cursor" echo " 3. Reopen in container (the image will be pulled from the registry)" echo " 4. Run /login in the Claude Agent panel to authenticate" echo info "To use a different local LLM API endpoint:" echo " LOCAL_LLM_API=http://myserver:1248/v1 bash setup-devcontainer.sh"