FROM ubuntu:22.04 SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV DEBIAN_FRONTEND=noninteractive \ TZ=Asia/Shanghai \ LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \ PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 \ HOME=/root \ ZSH=/root/.oh-my-zsh \ PORT=7860 # ------------------------------------------------------------ # 1) 安装系统基础依赖与 Playwright 运行环境 # ------------------------------------------------------------ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ wget \ git \ git-lfs \ sudo \ zsh \ locales \ tzdata \ gnupg \ vim \ nano \ jq \ tree \ htop \ tmux \ zip \ unzip \ tar \ xz-utils \ build-essential \ python3 \ python3-pip \ python3-dev \ python-is-python3 \ libasound2 \ libatk-bridge2.0-0 \ libatk1.0-0 \ libc6 \ libcairo2 \ libcups2 \ libdbus-1-3 \ libdrm2 \ libexpat1 \ libgbm1 \ libgcc-s1 \ libglib2.0-0 \ libgtk-3-0 \ libnspr4 \ libnss3 \ libpango-1.0-0 \ libpangocairo-1.0-0 \ libstdc++6 \ libx11-6 \ libx11-xcb1 \ libxcb1 \ libxcomposite1 \ libxcursor1 \ libxdamage1 \ libxext6 \ libxfixes3 \ libxi6 \ libxkbcommon0 \ libxrandr2 \ libxrender1 \ libxshmfence1 \ libxss1 \ libxtst6 \ libatspi2.0-0 \ libwayland-client0 \ libwayland-cursor0 \ libwayland-egl1 \ && locale-gen en_US.UTF-8 \ && update-locale LANG=en_US.UTF-8 \ && rm -rf /var/lib/apt/lists/* # ------------------------------------------------------------ # 2) 安装最新 Node.js 25 / pnpm / npm / Claude Code # ------------------------------------------------------------ RUN curl -fsSL https://deb.nodesource.com/setup_25.x | bash - \ && apt-get update \ && apt-get install -y --no-install-recommends nodejs \ && npm install -g npm@latest pnpm@latest @anthropic-ai/claude-code \ && npm cache clean --force \ && rm -rf /var/lib/apt/lists/* # ------------------------------------------------------------ # 3) 安装 GitHub CLI (gh) # ------------------------------------------------------------ RUN mkdir -p -m 755 /etc/apt/keyrings \ && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ | gpg --dearmor -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ > /etc/apt/sources.list.d/github-cli.list \ && apt-get update \ && apt-get install -y --no-install-recommends gh \ && rm -rf /var/lib/apt/lists/* # ------------------------------------------------------------ # 4) 安装 code-server & Playwright # ------------------------------------------------------------ RUN curl -fsSL https://code-server.dev/install.sh | sh \ && python3 -m pip install --no-cache-dir --upgrade pip setuptools wheel \ && python3 -m pip install --no-cache-dir playwright \ && python3 -m playwright install chromium \ && rm -rf /root/.cache/pip # ------------------------------------------------------------ # 5) Zsh 极简主题配置 (去框、去除主机名、仅显示 user:path) # ------------------------------------------------------------ RUN git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "${ZSH}" \ && git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "${ZSH}/custom/plugins/zsh-autosuggestions" \ && git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "${ZSH}/custom/plugins/zsh-syntax-highlighting" RUN mkdir -p "${ZSH}/custom/themes" \ && echo 'PROMPT="%F{green}%n%f:%F{cyan}%~%f > "' > "${ZSH}/custom/themes/minimal.zsh-theme" \ && echo 'RPROMPT="%F{240}[%*]%f"' >> "${ZSH}/custom/themes/minimal.zsh-theme" RUN cat > /root/.zshrc <<'EOF' export ZSH="$HOME/.oh-my-zsh" zstyle ':omz:update' mode disabled ZSH_THEME="minimal" plugins=(git zsh-autosuggestions zsh-syntax-highlighting) source $ZSH/oh-my-zsh.sh alias ll='ls -alF --color=auto' alias c='clear' alias backup='python3 /root/persistence.py --backup' alias restore='python3 /root/persistence.py --restore' bindkey '^ ' autosuggest-accept EOF # ------------------------------------------------------------ # 6) 数据持久化脚本 (智能排除依赖库) # ------------------------------------------------------------ RUN cat > /root/persistence.py <<'EOF' import os, sys, tarfile BACKUP_NAME = "space_source_backup.tar.gz" EXCLUDE_DIRS = { "node_modules", ".npm", ".pnpm-store", ".cache", "__pycache__", "venv", ".venv", ".pytest_cache", "CachedExtensionVSIXs", "workspaceStorage", "logs" } def filter_function(tarinfo): name = os.path.basename(tarinfo.name) if name in EXCLUDE_DIRS: print(f" -> Skipping: {tarinfo.name}") return None return tarinfo def backup(): print("[*] 正在执行智能备份 (已排除 node_modules/venv 等依赖)...") with tarfile.open(BACKUP_NAME, "w:gz") as tar: for item in os.listdir("/root"): if item != BACKUP_NAME: tar.add(os.path.join("/root", item), arcname=item, filter=filter_function) size_mb = os.path.getsize(BACKUP_NAME) / (1024 * 1024) print(f"[+] 备份成功!体积:{size_mb:.2f} MB") print(f"[!] 请在侧边栏右键点击 {BACKUP_NAME} 选择 'Download' 下载。") print("[提示] 下次还原后,只需重新执行 npm/pnpm install 或 pip install 即可。") def restore(): if not os.path.exists(BACKUP_NAME): print(f"[!] 错误:找不到备份文件 {BACKUP_NAME}。请先上传。") return print("[*] 正在还原源代码和配置...") with tarfile.open(BACKUP_NAME, "r:gz") as tar: tar.extractall(path="/root") print("[+] 还原成功!请重新安装项目依赖。") if __name__ == "__main__": if "--backup" in sys.argv: backup() elif "--restore" in sys.argv: restore() EOF # ------------------------------------------------------------ # 7) code-server 设置 # ------------------------------------------------------------ RUN mkdir -p /root/.config/code-server /root/.local/share/code-server/User RUN cat > /root/.config/code-server/config.yaml <<'EOF' bind-addr: 0.0.0.0:7860 auth: none EOF RUN cat > /root/.local/share/code-server/User/settings.json <<'EOF' { "workbench.startupEditor": "none", "telemetry.telemetryLevel": "off", "terminal.integrated.defaultProfile.linux": "zsh", "security.workspace.trust.enabled": false, "workbench.colorTheme": "Default Dark+" } EOF # ------------------------------------------------------------ # 8) 最终配置 # ------------------------------------------------------------ WORKDIR /root EXPOSE 7860 RUN chsh -s "$(which zsh)" root ENTRYPOINT ["code-server", "--bind-addr", "0.0.0.0:7860", "--auth", "none", "/root"]