FROM node:20 ARG TZ ENV TZ="$TZ" ARG CLAUDE_CODE_VERSION=latest # Install basic development tools and iptables/ipset RUN apt-get update && apt-get install -y --no-install-recommends \ less \ git \ procps \ sudo \ fzf \ zsh \ man-db \ unzip \ gnupg2 \ gh \ iptables \ ipset \ iproute2 \ dnsutils \ aggregate \ jq \ nano \ vim \ ca-certificates \ curl \ wget \ && apt-get clean && rm -rf /var/lib/apt/lists/* # ----------------------------------------------------------------------------- # Chessistics: headless Godot + .NET SDK # ----------------------------------------------------------------------------- # 1. Xvfb + Mesa software GL + X/audio runtime deps for Godot's GL-compatibility renderer RUN apt-get update && apt-get install -y --no-install-recommends \ xvfb \ xauth \ x11-utils \ libx11-6 \ libxcursor1 \ libxinerama1 \ libxrandr2 \ libxi6 \ libxext6 \ libxrender1 \ libxfixes3 \ libxss1 \ libxkbcommon0 \ libxkbcommon-x11-0 \ libgl1 \ libglx-mesa0 \ libgl1-mesa-dri \ libglu1-mesa \ libegl1 \ libgles2 \ libasound2 \ libpulse0 \ libfontconfig1 \ libfreetype6 \ libdbus-1-3 \ libudev1 \ fonts-dejavu-core \ python3 \ python3-pip \ && apt-get clean && rm -rf /var/lib/apt/lists/* # 2. .NET SDK 9.0 via the upstream install script (arch-agnostic, no apt repo needed) RUN curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \ && bash /tmp/dotnet-install.sh --channel 9.0 --install-dir /usr/local/dotnet \ && ln -s /usr/local/dotnet/dotnet /usr/local/bin/dotnet \ && rm /tmp/dotnet-install.sh ENV DOTNET_ROOT=/usr/local/dotnet ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 ENV DOTNET_NOLOGO=1 # 3. Godot 4.6.2-stable Mono for Linux x86_64 # The zip contains a directory like "Godot_v..._mono_linux_x86_64/" with # an executable whose exact filename has varied across releases # ("Godot_v..._mono_linux.x86_64" on 4.x). Locate it dynamically. ARG GODOT_VERSION=4.6.2-stable RUN mkdir -p /opt/godot \ && cd /tmp \ && wget -q "https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}/Godot_v${GODOT_VERSION}_mono_linux_x86_64.zip" \ && unzip -q "Godot_v${GODOT_VERSION}_mono_linux_x86_64.zip" -d /opt/godot \ && GODOT_EXE="$(find /opt/godot -maxdepth 3 -type f \( -name 'Godot_v*mono_linux*x86_64' -o -name 'Godot_v*mono_linux*x86_64' \) | head -1)" \ && if [ -z "$GODOT_EXE" ]; then echo "Godot executable not found in zip" && ls -R /opt/godot && exit 1; fi \ && chmod +x "$GODOT_EXE" \ && ln -sf "$GODOT_EXE" /opt/godot/godot \ && rm "Godot_v${GODOT_VERSION}_mono_linux_x86_64.zip" ENV GODOT_BIN=/opt/godot/godot ENV PATH=$PATH:/opt/godot:/usr/local/dotnet # 4. xvfb wrapper — any Godot invocation gets its own virtual 1280x720x24 display. # Usage: `godot-xvfb --path /workspace ...` or let tools/automation/harness.py # invoke it automatically on Linux. COPY godot-xvfb.sh /usr/local/bin/godot-xvfb RUN chmod +x /usr/local/bin/godot-xvfb # Ensure default node user has access to /usr/local/share RUN mkdir -p /usr/local/share/npm-global && \ chown -R node:node /usr/local/share ARG USERNAME=node # Persist bash history. RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ && mkdir /commandhistory \ && touch /commandhistory/.bash_history \ && chown -R $USERNAME /commandhistory # Set `DEVCONTAINER` environment variable to help with orientation ENV DEVCONTAINER=true # Create workspace and config directories and set permissions RUN mkdir -p /workspace /home/node/.claude && \ chown -R node:node /workspace /home/node/.claude WORKDIR /workspace ARG GIT_DELTA_VERSION=0.18.2 RUN ARCH=$(dpkg --print-architecture) && \ wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" # Set up non-root user USER node # Install global packages ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global ENV PATH=$PATH:/usr/local/share/npm-global/bin # Set the default shell to zsh rather than sh ENV SHELL=/bin/zsh # Set the default editor and visual ENV EDITOR=nano ENV VISUAL=nano # Default powerline10k theme ARG ZSH_IN_DOCKER_VERSION=1.2.0 RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \ -p git \ -p fzf \ -a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \ -a "source /usr/share/doc/fzf/examples/completion.zsh" \ -a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ -x # Install Claude RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} # Copy and set up firewall script COPY init-firewall.sh /usr/local/bin/ USER root RUN chmod +x /usr/local/bin/init-firewall.sh && \ echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \ chmod 0440 /etc/sudoers.d/node-firewall USER node