# Nucleic sandbox image — the agent's in-container toolchain.
#
# Built in CI and pushed to GHCR (see .github/workflows/sandbox-image.yml); the macOS app pulls +
# unpacks it at runtime via ContainerEngine (no on-device build, no user-installed tools). Keep the
# tag in sync with `ProjectSandbox.defaultImage` (Sources/NucleicCore/Project.swift) — bump the tag
# whenever this file changes so the app pulls the new image instead of a stale cache.
#
# A Node base with git, the GitHub CLI (`gh`), a cross-language build toolchain, and the Claude Code
# CLI preinstalled. The Swift/Xcode toolchain is deliberately ABSENT — Swift builds run on the host
# via host-exec, not in the sandbox — but agents still get the common build tools (make/gcc from
# build-essential, python3/pip, plus the base image's node/npm) to build and test most repos
# in-container. `gh` is installed from GitHub's official apt repository (authenticated in-sandbox via
# the injected GITHUB_TOKEN) so the agent can open PRs and call the GitHub API. `openssh-client`
# supplies `ssh-keygen`, which git invokes to sign commits when `gpg.format=ssh` is configured —
# without it signed commits fail.
FROM node:22-bookworm-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        git openssh-client ca-certificates curl iproute2 \
        build-essential make pkg-config \
        python3 python3-pip python3-venv \
    && mkdir -p -m 755 /etc/apt/keyrings \
    && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
        -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/*

RUN npm install -g @anthropic-ai/claude-code

# OpenAI Codex (npm resolves the arch binary; arm64 = codex-aarch64-unknown-linux-musl). It stores
# its login as a plain ~/.codex/auth.json (no Keychain), seeded per session host-side.
RUN npm install -g @openai/codex

# xAI Grok Build via its official installer. The installer drops the toolchain under /root/.grok and
# points /usr/local/bin/grok at /root/.grok/bin/grok — but /root is 0700, so the non-root agent uid
# can't reach it (and the installer's own /usr/local/bin/grok symlink can't simply be re-pointed at
# itself). Relocate the whole install to a world-traversable /opt and relink onto the global PATH so
# the agent can run it. `grok --version` fails the build loudly if the arm64 binary didn't land.
RUN curl -fsSL https://x.ai/cli/install.sh | bash \
    && rm -f /usr/local/bin/grok /usr/local/bin/agent \
    && mv /root/.grok /opt/grok \
    && chmod -R a+rX /opt/grok \
    && ln -s /opt/grok/bin/grok /usr/local/bin/grok \
    && ln -s /opt/grok/bin/agent /usr/local/bin/agent \
    && /opt/grok/bin/grok --version

# The in-container control bridge (loopback TCP -> the vsock-relayed host control socket). The
# container's root init launches it only when Nucleic relays a control socket in; it lets the agent
# + interceptor shims reach the host approval server with no IP listener (no macOS network prompts).
# See docs/VSOCK_CONTROL_PLANE.md. Runs on the base image's node.
COPY control-bridge.js /opt/nucleic/control-bridge.js

WORKDIR /workspace
