# syntax=docker/dockerfile:1.7 FROM node:22.23.4-trixie-slim@sha256:8eb619e402eaede1748a3c8173bffab391592812e85136452f781741c7242ddf AS build ARG TARGETARCH WORKDIR /app RUN apt-get update \ && apt-get install -y --no-install-recommends build-essential liblzma5 python3 pkg-config \ && rm -rf /var/lib/apt/lists/* COPY . . RUN npm ci --no-audit --no-fund \ && npm run build \ && npm prune --omit=dev \ && find node_modules -type f \( -name '*.js.map' -o -name '*.mjs.map' -o -name '*.cjs.map' -o -name '*.css.map' \) -delete \ && node scripts/prune-container-closures.mjs --targetarch "$TARGETARCH" --output-dir /app/closures FROM node:22.23.4-trixie-slim@sha256:8eb619e402eaede1748a3c8173bffab391592812e85136452f781741c7242ddf AS runtime-base ARG TARGETARCH ARG NPM_VERSION=11.18.0 ENV NODE_ENV=production \ LANG=C.UTF-8 \ LC_ALL=C.UTF-8 LABEL org.opencontainers.image.source=https://github.com/oll4com/spaceapp LABEL org.opencontainers.image.licenses=MIT RUN npm install --global --ignore-scripts --no-audit --no-fund "npm@${NPM_VERSION}" \ && install -d /tmp/npm-security-patches \ && npm pack --ignore-scripts --no-audit --no-fund --pack-destination /tmp/npm-security-patches \ brace-expansion@5.0.12 tar@7.5.21 ip-address@10.7.4 undici@6.29.1 postcss-selector-parser@7.1.6 \ && rm -rf \ /usr/local/lib/node_modules/npm/node_modules/brace-expansion \ /usr/local/lib/node_modules/npm/node_modules/tar \ /usr/local/lib/node_modules/npm/node_modules/ip-address \ /usr/local/lib/node_modules/npm/node_modules/undici \ /usr/local/lib/node_modules/npm/node_modules/postcss-selector-parser \ && install -d \ /usr/local/lib/node_modules/npm/node_modules/brace-expansion \ /usr/local/lib/node_modules/npm/node_modules/tar \ /usr/local/lib/node_modules/npm/node_modules/ip-address \ /usr/local/lib/node_modules/npm/node_modules/undici \ /usr/local/lib/node_modules/npm/node_modules/postcss-selector-parser \ && tar -xzf /tmp/npm-security-patches/brace-expansion-5.0.12.tgz \ -C /usr/local/lib/node_modules/npm/node_modules/brace-expansion --strip-components=1 \ && tar -xzf /tmp/npm-security-patches/tar-7.5.21.tgz \ -C /usr/local/lib/node_modules/npm/node_modules/tar --strip-components=1 \ && tar -xzf /tmp/npm-security-patches/ip-address-10.7.4.tgz \ -C /usr/local/lib/node_modules/npm/node_modules/ip-address --strip-components=1 \ && tar -xzf /tmp/npm-security-patches/undici-6.29.1.tgz \ -C /usr/local/lib/node_modules/npm/node_modules/undici --strip-components=1 \ && tar -xzf /tmp/npm-security-patches/postcss-selector-parser-7.1.6.tgz \ -C /usr/local/lib/node_modules/npm/node_modules/postcss-selector-parser --strip-components=1 \ && rm -rf /tmp/npm-security-patches \ && npm cache clean --force \ && apt-get update \ && apt-get install -y --no-install-recommends bash ca-certificates curl git gosu liblzma5 postgresql-client procps ripgrep sqlite3 \ && apt-get upgrade -y \ && rm -rf /var/lib/apt/lists/* \ && groupadd --gid 10001 spaceapp \ && useradd --uid 10001 --gid 10001 --create-home --home-dir /var/lib/spaceapp-cli --shell /bin/bash spaceapp WORKDIR /app COPY --from=build --chown=spaceapp:spaceapp /app/LICENSE /app/NOTICE /app/THIRD_PARTY_NOTICES.md ./ COPY --from=build --chown=spaceapp:spaceapp /app/THIRD_PARTY_LICENSES ./THIRD_PARTY_LICENSES COPY --chown=spaceapp:spaceapp deploy/docker ./deploy/docker RUN chmod 0755 deploy/docker/core-entrypoint.sh deploy/docker/browser-entrypoint.sh deploy/docker/cli-entrypoint.sh \ && install -m 0755 deploy/docker/public-cli-wrapper.sh /usr/local/bin/spaceapp-cli-wrapper \ && for name in codex claude gemini opencode qwen kimi grok deepseek autohand cursor copilot; do \ ln -s /usr/local/bin/spaceapp-cli-wrapper "/usr/local/bin/${name}-vscode-parity"; \ done FROM runtime-base AS core COPY --from=build --chown=spaceapp:spaceapp /app/closures/core ./ COPY --from=build --chown=spaceapp:spaceapp /app/scripts/reset-owner-password.mjs ./scripts/reset-owner-password.mjs COPY --from=build --chown=spaceapp:spaceapp /app/scripts/rotate-owner-setup-token.mjs ./scripts/rotate-owner-setup-token.mjs COPY --from=build --chown=spaceapp:spaceapp /app/scripts/portable-backup.mjs ./scripts/portable-backup.mjs COPY --from=build --chown=spaceapp:spaceapp /app/scripts/portable-restore.mjs ./scripts/portable-restore.mjs COPY --chown=spaceapp:spaceapp starter-memory /opt/spaceapp/starter-memory # The Databases tool's SQLite worker (apps/api/src/databases/sqlite-worker.py) needs Python 3.12+ with its sqlite3 module; # python3-minimal has no sqlite3 (1.1.7 review: SQLite could not run in public installations). RUN apt-get update \ && apt-get install -y --no-install-recommends python3 \ && rm -rf /var/lib/apt/lists/* \ && python3 -c 'import sqlite3, sys; assert sys.version_info >= (3, 12)' RUN install -d -o spaceapp -g spaceapp -m 0700 \ /var/lib/spaceapp \ /var/lib/spaceapp/artifacts \ /var/lib/spaceapp/memory \ /run/spaceapp-cli EXPOSE 4911 HEALTHCHECK --interval=15s --timeout=5s --start-period=45s --retries=5 \ CMD ["node", "-e", "fetch('http://127.0.0.1:4911/readyz').then(async r=>{const body=await r.json();if(!r.ok||body.ok !== true)process.exit(1)}).catch(()=>process.exit(1))"] ENTRYPOINT ["/app/deploy/docker/core-entrypoint.sh"] FROM runtime-base AS browser COPY --from=build --chown=spaceapp:spaceapp /app/closures/browser ./ RUN apt-get update \ && apt-get install -y --no-install-recommends chromium fonts-liberation liblzma5 \ && rm -rf /var/lib/apt/lists/* \ && install -d -o spaceapp -g spaceapp -m 0700 \ /var/lib/spaceapp \ /var/lib/spaceapp/artifacts \ /run/spaceapp-browser ENV SPACE_BROWSER_CHROME_PATH=/usr/bin/chromium \ SPACE_BROWSER_SESSIONS_CHROME_PATH=/usr/bin/chromium ENTRYPOINT ["/app/deploy/docker/browser-entrypoint.sh"] FROM runtime-base AS cli COPY --from=build --chown=spaceapp:spaceapp /app/closures/cli ./ COPY --chown=root:root starter-memory/AGENTS.md /etc/AGENTS.md COPY --chown=root:root starter-memory/installation-guide.md /etc/spaceapp-installation-guide.md RUN chmod 0644 /etc/AGENTS.md ARG TARGETARCH # python3-minimal (about 13 MB): agents often check their work with a short python3 script (pilot F18). # OpenCode 2 (@opencode/cli): its postinstall picks the native binary for the image's platform. RUN apt-get update \ && apt-get install -y --no-install-recommends python3-minimal \ && rm -rf /var/lib/apt/lists/* \ && npm install --global --no-audit --no-fund @opencode/cli@2.0.32 \ && install -d -o spaceapp -g spaceapp -m 0700 /var/lib/spaceapp-cli/vendor \ && npm cache clean --force \ && install -d -o spaceapp -g spaceapp -m 0700 \ /var/lib/spaceapp-cli \ /var/lib/spaceapp-cli/providers \ /var/lib/spaceapp-cli/imported-credentials \ /var/lib/spaceapp/memory \ /workspaces \ /run/spaceapp-cli \ && printf '%s\n' "$TARGETARCH" > /usr/local/share/spaceapp-cli-architecture RUN ln -s /etc /opt/spaceapp ENTRYPOINT ["/app/deploy/docker/cli-entrypoint.sh"]