FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive ARG AI_UID=1000 ARG AI_GID=1000 ARG CODEX_VERSION=latest ARG CLAUDE_VERSION=latest ARG CODEBUDDY_VERSION=latest ARG KIMI_VERSION=latest ARG OPENCODE_VERSION=latest ARG QWEN_VERSION=latest ARG DSH_VERSION=latest ARG CC_SWITCH_VERSION=v5.10.2 ARG CC_SWITCH_SHA256_AMD64=8065c5bae9eda270747c1766cefbb2091d9625655dbf409ad7764eb47c0a8635 ARG CC_SWITCH_SHA256_ARM64=b25c77f7eebbe3968c53022e1b5e703e324203e94e5c6379320bcd1bbe268e63 ARG MULTICA_VERSION=v0.1.53 ARG MULTICA_SHA256_AMD64=cfe60ff5cfee07e8147eb64fbaca46dac28162d84d03f1e07e4f87858d0fabb6 ARG MULTICA_SHA256_ARM64=afb77e15d585c1d60a67a9583c20b5ff1ef4a1bacdcdd73c8e318fc9d254ad02 ARG TARGETARCH SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN apt-get update \ && apt-get install -y --no-install-recommends \ bash-completion \ build-essential \ ca-certificates \ curl \ git \ gnupg \ jq \ less \ locales \ nano \ openssh-client \ pipx \ procps \ python3 \ python3-pip \ python3-venv \ ripgrep \ rsync \ supervisor \ tini \ unzip \ vim \ wget \ zip \ && rm -rf /var/lib/apt/lists/* # Kimi Code requires Node.js 22.19.0 or later. NodeSource 22.x supplies it. RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ && apt-get update \ && apt-get install -y --no-install-recommends nodejs \ && rm -rf /var/lib/apt/lists/* \ && node -e 'const [major, minor] = process.versions.node.split(".").map(Number); if (major < 22 || (major === 22 && minor < 19)) process.exit(1)' RUN npm config set update-notifier false \ && npm install --global \ "@openai/codex@${CODEX_VERSION}" \ "@anthropic-ai/claude-code@${CLAUDE_VERSION}" \ "@tencent-ai/codebuddy-code@${CODEBUDDY_VERSION}" \ "@moonshot-ai/kimi-code@${KIMI_VERSION}" \ "opencode-ai@${OPENCODE_VERSION}" \ "@qwen-code/qwen-code@${QWEN_VERSION}" \ "@deepseek-ai/dsh@${DSH_VERSION}" \ && npm cache clean --force RUN set -eux; \ case "${TARGETARCH:-amd64}" in \ amd64) cc_arch=x64; multica_arch=amd64; cc_sha="${CC_SWITCH_SHA256_AMD64}"; multica_sha="${MULTICA_SHA256_AMD64}" ;; \ arm64) cc_arch=arm64; multica_arch=arm64; cc_sha="${CC_SWITCH_SHA256_ARM64}"; multica_sha="${MULTICA_SHA256_ARM64}" ;; \ *) echo "Unsupported target architecture: ${TARGETARCH}" >&2; exit 1 ;; \ esac; \ cc_archive="/tmp/cc-switch.tar.gz"; \ multica_archive="/tmp/multica.tar.gz"; \ curl -fsSL -o "${cc_archive}" "https://github.com/SaladDay/cc-switch-cli/releases/download/${CC_SWITCH_VERSION}/cc-switch-cli-linux-${cc_arch}-musl.tar.gz"; \ echo "${cc_sha} ${cc_archive}" | sha256sum -c -; \ tar -xzf "${cc_archive}" -C /tmp cc-switch; \ install -m 0755 /tmp/cc-switch /usr/local/bin/cc-switch; \ curl -fsSL -o "${multica_archive}" "https://github.com/zimplemedia/multica-cli/releases/download/${MULTICA_VERSION}/multica_linux_${multica_arch}.tar.gz"; \ echo "${multica_sha} ${multica_archive}" | sha256sum -c -; \ tar -xzf "${multica_archive}" -C /tmp multica; \ install -m 0755 /tmp/multica /usr/local/bin/multica; \ rm -f "${cc_archive}" "${multica_archive}" /tmp/cc-switch /tmp/multica COPY runner/package.json runner/package-lock.json /opt/runner/ RUN cd /opt/runner \ && npm ci --omit=dev \ && npm cache clean --force COPY runner/*.js /opt/runner/ RUN existing_group="$(getent group "${AI_GID}" 2>/dev/null | cut -d: -f1 || true)" \ && if [ -z "${existing_group}" ]; then groupadd --gid "${AI_GID}" ai; existing_group=ai; fi \ && existing_user="$(getent passwd "${AI_UID}" 2>/dev/null | cut -d: -f1 || true)" \ && if [ -n "${existing_user}" ]; then \ usermod --login ai --home /home/ai --move-home --gid "${existing_group}" --shell /bin/bash "${existing_user}"; \ else \ useradd --uid "${AI_UID}" --gid "${existing_group}" --create-home --home-dir /home/ai --shell /bin/bash ai; \ fi \ && mkdir -p /workspace /home/ai/.ai-console/sessions \ && chown -R "${AI_UID}:${AI_GID}" /workspace /home/ai /opt/runner COPY --chmod=755 scripts/container-check.sh /usr/local/bin/ai-tools-check COPY --chmod=755 scripts/multica-runtime.sh /usr/local/bin/multica-runtime COPY --chmod=755 scripts/multica-setup.sh /usr/local/bin/multica-setup COPY scripts/supervisord.conf /etc/supervisor/conf.d/ai-runtime.conf ENV HOME=/home/ai \ USER=ai \ LANG=C.UTF-8 \ LC_ALL=C.UTF-8 \ PATH=/home/ai/.local/bin:/home/ai/bin:${PATH} \ PIPX_HOME=/home/ai/.local/pipx \ PIPX_BIN_DIR=/home/ai/.local/bin USER ai WORKDIR /workspace EXPOSE 4174 ENTRYPOINT ["/usr/bin/tini", "--"] CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/ai-runtime.conf"]