diff --git a/.devcontainer/build/Dockerfile b/.devcontainer/build/Dockerfile index f8de6235..ca1ee5b5 100644 --- a/.devcontainer/build/Dockerfile +++ b/.devcontainer/build/Dockerfile @@ -1,50 +1,15 @@ -FROM node:22-bookworm - -# [1] System dependencies -RUN apt-get update && apt-get install -y --no-install-recommends \ - curl git build-essential netcat-openbsd \ - zsh wget unzip \ - vim less jq tree htop \ - openssh-client openssh-server ca-certificates \ - iputils-ping iproute2 net-tools dnsutils \ - lsof strace procps psmisc \ - rsync socat pv \ - locales gettext-base \ - && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen \ - && rm -rf /var/lib/apt/lists/* -ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 - -# [2] Oh-my-zsh + plugins -RUN sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended \ - && git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions /root/.oh-my-zsh/custom/plugins/zsh-autosuggestions \ - && git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting /root/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting \ - && sed -i 's/ZSH_THEME="robbyrussell"/ZSH_THEME="agnoster"/' /root/.zshrc \ - && sed -i 's/plugins=(git)/plugins=(git z colored-man-pages zsh-autosuggestions zsh-syntax-highlighting)/' /root/.zshrc \ - && chsh -s /bin/zsh -ENV SHELL=/bin/zsh - -# [3] pnpm + shfmt -ENV PNPM_HOME="/root/.local/share/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -RUN npm install -g pnpm -RUN curl -sSL https://github.com/mvdan/sh/releases/latest/download/shfmt_$(curl -sSL https://api.github.com/repos/mvdan/sh/releases/latest | grep '"tag_name"' | cut -d'"' -f4)_linux_amd64 -o /usr/local/bin/shfmt \ - && chmod +x /usr/local/bin/shfmt - -# [4] SSH server -RUN mkdir -p /run/sshd \ - && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \ - && sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config - -# [5] GitHub CLI -RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ - && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list \ - && apt-get update && apt-get install -y gh \ - && rm -rf /var/lib/apt/lists/* - -# [6] AI CLI tools -RUN pnpm add -g @openai/codex -RUN npm install -g @anthropic-ai/claude-code -RUN npm install -g droid +FROM node-tarpit-base + +# [8] Node.js 22 via nvm + make binaries available globally +RUN . "$NVM_DIR/nvm.sh" \ + && nvm install 22 \ + && nvm alias default 22 \ + && nvm cache clear +RUN ln -s "$NVM_DIR/versions/node/$(. $NVM_DIR/nvm.sh && nvm current)/bin/node" /usr/local/bin/node \ + && ln -s "$NVM_DIR/versions/node/$(. $NVM_DIR/nvm.sh && nvm current)/bin/npm" /usr/local/bin/npm \ + && ln -s "$NVM_DIR/versions/node/$(. $NVM_DIR/nvm.sh && nvm current)/bin/npx" /usr/local/bin/npx + +# [9] pnpm + AI CLI tools: Claude Code, OpenAI Codex, Factory Droid +RUN npm install -g pnpm @anthropic-ai/claude-code @openai/codex droid WORKDIR /workspace/node-tarpit diff --git a/.devcontainer/build/Dockerfile.base b/.devcontainer/build/Dockerfile.base new file mode 100644 index 00000000..cb5ceed0 --- /dev/null +++ b/.devcontainer/build/Dockerfile.base @@ -0,0 +1,51 @@ +# ============================================================================= +# BASE IMAGE — system tools, SSH, zsh, uv, nvm, shfmt, gh CLI +# Used by: node-tarpit, megaquant +# ============================================================================= +FROM debian:bookworm-slim + +# [1] System deps +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl git build-essential netcat-openbsd \ + zsh wget unzip \ + vim less jq tree htop \ + openssh-client openssh-server ca-certificates gnupg \ + iputils-ping iproute2 net-tools dnsutils \ + lsof strace procps psmisc \ + rsync socat pv \ + locales gettext-base \ + && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen \ + && rm -rf /var/lib/apt/lists/* +ENV LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 + +# [2] SSH server config +RUN mkdir -p /run/sshd \ + && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \ + && sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config + +# [3] Oh-my-zsh + plugins +RUN sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended \ + && git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions /root/.oh-my-zsh/custom/plugins/zsh-autosuggestions \ + && git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting /root/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting \ + && sed -i 's/ZSH_THEME="robbyrussell"/ZSH_THEME="agnoster"/' /root/.zshrc \ + && sed -i 's/plugins=(git)/plugins=(git z colored-man-pages zsh-autosuggestions zsh-syntax-highlighting)/' /root/.zshrc \ + && chsh -s /bin/zsh +ENV SHELL=/bin/zsh + +# [4] uv +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/ + +# [5] nvm +ENV NVM_DIR=/root/.nvm +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash + +# [6] shfmt +RUN curl -sSL https://github.com/mvdan/sh/releases/latest/download/shfmt_$(curl -sSL https://api.github.com/repos/mvdan/sh/releases/latest | grep '"tag_name"' | cut -d'"' -f4)_linux_amd64 -o /usr/local/bin/shfmt \ + && chmod +x /usr/local/bin/shfmt + +# [7] GitHub CLI +RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list \ + && apt-get update && apt-get install -y gh \ + && rm -rf /var/lib/apt/lists/* diff --git a/.devcontainer/build/build.sh b/.devcontainer/build/build.sh index c70f3014..a5baeb72 100755 --- a/.devcontainer/build/build.sh +++ b/.devcontainer/build/build.sh @@ -1,7 +1,34 @@ #!/bin/bash set -e + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +BASE_IMAGE="node-tarpit-base" IMAGE_NAME="node-tarpit-dev" -echo "Building $IMAGE_NAME..." -docker build -t "$IMAGE_NAME" -f "$SCRIPT_DIR/Dockerfile" "$SCRIPT_DIR" -echo "Done: $IMAGE_NAME" + +FORCE=false +BASE_ONLY=false +while [[ $# -gt 0 ]]; do + case $1 in + -f|--force) FORCE=true; shift ;; + --base-only) BASE_ONLY=true; shift ;; + *) echo "Usage: $0 [-f|--force] [--base-only]"; exit 1 ;; + esac +done + +BUILD_ARGS="" +if [ "$FORCE" = true ]; then + echo ">>> Force rebuild (no cache)" + BUILD_ARGS="--no-cache" +fi + +echo ">>> Building base image: $BASE_IMAGE" +docker build $BUILD_ARGS -t "$BASE_IMAGE" -f "$SCRIPT_DIR/Dockerfile.base" "$SCRIPT_DIR" + +if [ "$BASE_ONLY" = true ]; then + echo ">>> Done: $BASE_IMAGE" + exit 0 +fi + +echo ">>> Building image: $IMAGE_NAME" +docker build $BUILD_ARGS -t "$IMAGE_NAME" -f "$SCRIPT_DIR/Dockerfile" "$SCRIPT_DIR" +echo ">>> Done: $IMAGE_NAME"