Some checks failed
The audio work was three parts and I shipped two. The transcode-fidelity method and the pinned 5.1 downmix landed; the null sink -- the only one that answers "what does the GAME play" -- I deferred to "the next natural rebuild window" and then rebuilt both images four times without doing it. pulseaudio-utils is now in both, with tools/audio-capture wrapping it: a null sink is a real device as far as an application is concerned, so Canary and Godot open it normally and parec records what they emit. This unblocks the decoder's Q8. The cue-to-event bindings are currently a name match against the authors' own identifiers -- a plausible guess, not a measurement -- and capturing what the game plays on a menu move converts them. `audio-capture run` reports the peak level and warns when the capture is silent, because silence is the failure that looks like success: a WAV of exactly the right duration, full of zeroes, because the application opened a different sink. A duration check alone passes it, which is how a confident wrong number gets made.
108 lines
5.5 KiB
Docker
108 lines
5.5 KiB
Docker
# Autonomous port agent for the Sylpheed Godot menu shell.
|
|
#
|
|
# DELIBERATELY SMALL. The reverse-engineering container next door is 4.36 GB
|
|
# because it builds Xenia Canary and drives it under a software Vulkan stack.
|
|
# This agent has no emulator, no oracle and no C++ build: it converts already-
|
|
# decoded assets and drives Godot. Keeping it light is what lets both containers
|
|
# run on one 12-core / 15 GB box without the memory pressure that has crashed it.
|
|
#
|
|
# What it needs, and nothing else: Rust (the exporter), Godot 4 (the runtime),
|
|
# ffmpeg (the transcode), and a headless display to screenshot Godot for
|
|
# comparison against the reference renderer.
|
|
|
|
FROM ubuntu:24.04
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive \
|
|
LANG=C.UTF-8 \
|
|
TZ=Etc/UTC
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
# toolchain for the exporter and for building sylpheed-cli from /reborn
|
|
build-essential pkg-config git curl ca-certificates \
|
|
libssl-dev \
|
|
# Godot 4 needs these even headless; the windowed run needs the X libs
|
|
libx11-6 libxcursor1 libxinerama1 libxrandr2 libxi6 libgl1 \
|
|
libasound2t64 libpulse0 libfontconfig1 \
|
|
# the transcode target (libtheora + libvorbis ship in Ubuntu's ffmpeg)
|
|
ffmpeg \
|
|
# headless display + the screenshot path, for diffing Godot's output
|
|
# against `sylpheed-cli screen render`
|
|
xvfb x11-utils openbox imagemagick \
|
|
# everyday
|
|
python3 jq ripgrep unzip file less nano tini sudo procps \
|
|
# expect drives Claude Code's one-time interactive gates
|
|
expect \
|
|
# PulseAudio, for capturing audio without a sound card. `module-null-sink`
|
|
# is a real device as far as any application is concerned, so the emulator
|
|
# and Godot open it normally and `parec` records what they play. Without
|
|
# it, "does this actually sound right" is unanswerable in a container --
|
|
# and the cue-to-event bindings stay a name match rather than a
|
|
# measurement. See docs/port/AUDIO-VERIFICATION.md.
|
|
pulseaudio pulseaudio-utils \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# ── Godot 4 ──────────────────────────────────────────────────────────────────
|
|
# Pinned. An engine version bump changes rendering, and this project compares
|
|
# screenshots against a reference renderer — so an upgrade must be a deliberate,
|
|
# stated act rather than a silent drift.
|
|
ARG GODOT_VERSION=4.7.2
|
|
RUN cd /tmp \
|
|
&& curl -fsSLO "https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
|
|
&& unzip -q "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \
|
|
&& mv "Godot_v${GODOT_VERSION}-stable_linux.x86_64" /usr/local/bin/godot \
|
|
&& chmod +x /usr/local/bin/godot \
|
|
&& printf '#!/bin/sh\nexec /usr/local/bin/godot --headless "$@"\n' > /usr/local/bin/godot-headless \
|
|
&& chmod +x /usr/local/bin/godot-headless \
|
|
&& rm -f "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip"
|
|
|
|
# ── Node + Claude Code ───────────────────────────────────────────────────────
|
|
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
&& apt-get install -y --no-install-recommends nodejs \
|
|
&& npm install -g @anthropic-ai/claude-code \
|
|
&& npm cache clean --force \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# ── The agent user ───────────────────────────────────────────────────────────
|
|
# NOT root: Claude Code refuses --dangerously-skip-permissions with root
|
|
# privileges. Ubuntu 24.04 ships its own `ubuntu` account at uid 1000, so the
|
|
# common case — matching a host user who is also 1000 — collides with it.
|
|
ARG AGENT_UID=1000
|
|
ARG AGENT_GID=1000
|
|
RUN if getent passwd "${AGENT_UID}" >/dev/null; then \
|
|
userdel -r "$(getent passwd "${AGENT_UID}" | cut -d: -f1)" 2>/dev/null || true; \
|
|
fi; \
|
|
if getent group "${AGENT_GID}" >/dev/null; then \
|
|
groupdel "$(getent group "${AGENT_GID}" | cut -d: -f1)" 2>/dev/null || true; \
|
|
fi; \
|
|
groupadd -g "${AGENT_GID}" agent \
|
|
&& useradd -m -u "${AGENT_UID}" -g "${AGENT_GID}" -s /bin/bash -d /sylph-home/port agent \
|
|
&& mkdir -p /sylph-home/port /work /exchange /reborn \
|
|
&& chown -R "${AGENT_UID}:${AGENT_GID}" /sylph-home /work /exchange \
|
|
&& echo 'agent ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/agent
|
|
|
|
COPY bin/ /usr/local/bin/
|
|
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
RUN chmod +x /usr/local/bin/* /usr/local/bin/entrypoint.sh
|
|
|
|
USER agent
|
|
WORKDIR /work
|
|
|
|
# CARGO_TARGET_DIR points OUTSIDE the bind-mounted repo so the host and the
|
|
# container do not invalidate each other's incremental state on every switch.
|
|
ENV RUSTUP_HOME=/sylph-home/port/.rustup \
|
|
CARGO_HOME=/sylph-home/port/.cargo \
|
|
CARGO_TARGET_DIR=/sylph-home/port/target-container \
|
|
PATH=/work/tools:/sylph-home/port/.cargo/bin:/usr/local/bin:/usr/bin:/bin
|
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
|
| sh -s -- -y --default-toolchain stable --profile minimal --component clippy --component rustfmt
|
|
|
|
RUN mkdir -p /sylph-home/port/target-container /sylph-home/port/.claude
|
|
|
|
ENV HOME=/sylph-home/port \
|
|
DISPLAY=:97 \
|
|
SCREEN_GEOMETRY=1280x720x24 \
|
|
PROJECT_DIR=/work
|
|
|
|
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"]
|
|
CMD ["bash"]
|