Monorepo for Aesthetic.Computer
aesthetic.computer
1# Rebuilt to run SmartPy on Python 3.11 and avoid 3.13 BrokenPipe
2FROM --platform=linux/amd64 fedora:latest
3
4# Preconfigure DNF to minimize footprint and avoid unnecessary optional deps
5RUN set -eux; \
6 echo 'fastestmirror=True' >> /etc/dnf/dnf.conf; \
7 echo 'max_parallel_downloads=5' >> /etc/dnf/dnf.conf; \
8 echo 'keepcache=0' >> /etc/dnf/dnf.conf; \
9 echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf; \
10 echo 'tsflags=nodocs' >> /etc/dnf/dnf.conf
11
12ENV NODE_OPTIONS=--max_old_space_size=8192
13ENV DENO_DIR=/home/me/.cache/deno
14ENV NETLIFY_DENO_VERSION=2.4.5
15# Prevent paging for LLM/agentic use
16ENV PAGER=cat
17ENV GIT_PAGER=cat
18ENV SYSTEMD_PAGER=cat
19ENV MANPAGER=cat
20
21# --- Base toolchain & deps ----------------------------------------------------
22RUN dnf clean all && rm -rf /var/cache/dnf && \
23 dnf update -y --refresh --setopt=zchunk=false && \
24 dnf install -y \
25 awk which tree procps-ng coreutils unzip jq bat ripgrep \
26 cpio lz4 bc perl mtools dosfstools xorriso ca-certificates \
27 git gh gcc gcc-c++ clang make cmake \
28 musl-gcc elfutils-libelf-devel \
29 python3.11 python3.11-devel python3-pip python3-devel \
30 emacs-nox fish util-linux-user util-linux-script sshpass \
31 openssl openssl-devel awscli redis \
32 dnf-plugins-core lolcat toilet iproute xclip nmap-ncat \
33 inotify-tools wget curl tar gzip bzip2 \
34 libsodium libsodium-devel libffi libffi-devel \
35 gmp gmp-devel \
36 protobuf-compiler protobuf-devel \
37 pkg-config autoconf automake libtool \
38 ocaml opam rsync m4 patch bubblewrap \
39 libX11 libxkbfile libsecret libxshmfence libXtst \
40 nss atk pango cups-libs libXcomposite libXcursor \
41 libXi libXdamage libXrandr alsa-lib gtk3 \
42 alsa-lib-devel libdrm-devel libpciaccess-devel \
43 flite-devel \
44 xorg-x11-server-Xvfb psmisc lsof chromium \
45 wpa_supplicant dhcp-client iw iwlwifi-mvm-firmware wireless-regdb \
46 sbcl zeromq-devel redhat-rpm-config \
47 poppler-utils \
48 texlive-xetex texlive-collection-fontsrecommended texlive-natbib \
49 texlive-booktabs texlive-titlesec texlive-fancyhdr texlive-draftwatermark \
50 texlive-microtype texlive-ragged2e texlive-listings texlive-enumitem \
51 texlive-collection-latexrecommended \
52 isync maildir-utils msmtp \
53 caddy \
54 texlive-scheme-basic texlive-xetex texlive-bibtex \
55 texlive-collection-fontsrecommended texlive-collection-latexrecommended \
56 texlive-natbib texlive-booktabs texlive-enumitem texlive-titlesec \
57 texlive-fancyhdr texlive-microtype texlive-listings texlive-ragged2e \
58 texlive-draftwatermark texlive-fontspec texlive-unicode-math \
59 texlive-collection-mathscience \
60 texlive-xecjk texlive-tcolorbox texlive-environ \
61 google-noto-sans-cjk-sc-fonts google-noto-sans-mono-cjk-sc-fonts \
62 && dnf clean all && rm -rf /var/cache/dnf
63
64# --- FFmpeg from RPM Fusion ---------------------------------------------------
65RUN dnf install -y --setopt=zchunk=false \
66 https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \
67 https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm \
68 && dnf install -y --allowerasing --skip-unavailable --setopt=zchunk=false ffmpeg ffmpeg-devel \
69 && dnf clean all && rm -rf /var/cache/dnf
70
71# --- Python 3.11 venv as default "python" -------------------------------------
72RUN /usr/bin/python3.11 -m venv /opt/py311 && \
73 /opt/py311/bin/pip install -U pip setuptools wheel && \
74 ln -s /opt/py311/bin/python /usr/local/bin/python && \
75 ln -s /opt/py311/bin/pip /usr/local/bin/pip
76ENV PATH="/opt/py311/bin:${PATH}"
77
78# --- SmartPy (pinned) + smoke test -------------------------------------------
79# Note: SmartPy doesn't support ARM64 architecture (Apple Silicon)
80RUN set -eux; \
81 if [ "$(uname -m)" = "x86_64" ]; then \
82 pip install "tezos-smartpy==0.22.0" "pytezos>=3.9.0,<4" requests && \
83 python -c "import smartpy as sp; print('SmartPy successfully imported')"; \
84 else \
85 echo "Skipping SmartPy on $(uname -m) architecture (not supported)"; \
86 pip install "pytezos>=3.9.0,<4" requests; \
87 fi
88
89# --- Octez (best-effort binary) ----------------------------------------------
90# Note: v20.3 doesn't support current Ghostnet protocol (PtSeouLouXkxhg39...)
91# Use Docker method instead: deploy-via-docker.py
92RUN set -eux; \
93 if curl -fsSL -o /usr/local/bin/octez-client \
94 https://github.com/serokell/tezos-packaging/releases/download/v20.3-1/octez-client && \
95 curl -fsSL -o /usr/local/bin/octez-node \
96 https://github.com/serokell/tezos-packaging/releases/download/v20.3-1/octez-node; then \
97 chmod +x /usr/local/bin/octez-*; \
98 else \
99 echo "Octez binaries unavailable, skipping"; \
100 fi
101
102# --- Docker CLI (for running latest Octez via Docker) ------------------------
103# This allows us to use tezos/tezos:master which supports current Ghostnet protocol
104RUN dnf install -y --setopt=zchunk=false docker && dnf clean all && rm -rf /var/cache/dnf
105
106# Pre-pull Tezos & SmartPy Docker images during build (saves time later)
107# Note: This requires BuildKit and may fail in some build environments
108# If it fails, the images will be pulled on first use instead
109RUN --mount=type=cache,target=/var/cache/buildkit \
110 docker pull tezos/tezos:master 2>/dev/null || echo "Octez image will be pulled on first use" && \
111 docker pull bakingbad/smartpy-cli:latest 2>/dev/null || echo "SmartPy image will be pulled on first use"
112
113# --- Stripe CLI (architecture-aware) -----------------------------------------
114RUN set -eux; \
115 case "$(uname -m)" in \
116 x86_64) ARCH=x86_64 ;; \
117 aarch64) ARCH=arm64 ;; \
118 *) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
119 esac && \
120 curl -fsSL "https://github.com/stripe/stripe-cli/releases/download/v1.30.0/stripe_1.30.0_linux_${ARCH}.tar.gz" \
121 | tar xz -C /usr/local/bin
122
123# --- redli (architecture-aware) ----------------------------------------------
124RUN set -eux; \
125 case "$(uname -m)" in \
126 x86_64) ARCH=amd64 ;; \
127 aarch64) ARCH=arm64 ;; \
128 *) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
129 esac && \
130 curl -fsSL "https://github.com/IBM-Cloud/redli/releases/download/v0.15.0/redli_0.15.0_linux_${ARCH}.tar.gz" \
131 | tar xz -C /usr/local/bin && mv "/usr/local/bin/redli_linux_${ARCH}" /usr/local/bin/redli
132
133# --- mkcert (pre-built binary from GitHub) -----------------------------------
134RUN set -eux; \
135 case "$(uname -m)" in \
136 x86_64) ARCH=amd64 ;; \
137 aarch64) ARCH=arm64 ;; \
138 *) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
139 esac && \
140 curl -fsSL "https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-${ARCH}" -o /usr/local/bin/mkcert && \
141 chmod +x /usr/local/bin/mkcert
142
143# --- ngrok (architecture-aware) ----------------------------------------------
144RUN set -eux; \
145 case "$(uname -m)" in \
146 x86_64) ARCH=amd64 ;; \
147 aarch64) ARCH=arm64 ;; \
148 *) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
149 esac && \
150 curl -fsSL "https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-${ARCH}.tgz" -o /tmp/ngrok.tgz && \
151 tar -xzf /tmp/ngrok.tgz -C /usr/local/bin && rm /tmp/ngrok.tgz
152
153# --- Ollama (architecture-aware) ---------------------------------------------
154# RUN set -eux; \
155# curl -fsSL https://ollama.com/install.sh | sh
156
157# --- doctl (DigitalOcean CLI, architecture-aware) ----------------------------
158RUN set -eux; \
159 case "$(uname -m)" in \
160 x86_64) ARCH=amd64 ;; \
161 aarch64) ARCH=arm64 ;; \
162 *) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
163 esac && \
164 DOCTL_VERSION=1.109.0 && \
165 curl -fsSL "https://github.com/digitalocean/doctl/releases/download/v${DOCTL_VERSION}/doctl-${DOCTL_VERSION}-linux-${ARCH}.tar.gz" -o /tmp/doctl.tar.gz && \
166 tar -xzf /tmp/doctl.tar.gz -C /usr/local/bin && rm /tmp/doctl.tar.gz && \
167 chmod +x /usr/local/bin/doctl
168
169# --- PowerShell (for running Windows scripts on Linux) -----------------------
170# Install from GitHub releases since Microsoft's repo doesn't have Fedora 43 packages yet
171RUN ARCH=$(uname -m) && \
172 if [ "$ARCH" = "x86_64" ]; then PS_ARCH="x64"; else PS_ARCH="arm64"; fi && \
173 PS_VERSION=$(curl -s https://api.github.com/repos/PowerShell/PowerShell/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/') && \
174 curl -sSL -o /tmp/powershell.tar.gz "https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/powershell-${PS_VERSION}-linux-${PS_ARCH}.tar.gz" && \
175 mkdir -p /opt/microsoft/powershell/7 && \
176 tar -xzf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 && \
177 chmod +x /opt/microsoft/powershell/7/pwsh && \
178 ln -s /opt/microsoft/powershell/7/pwsh /usr/local/bin/pwsh && \
179 ln -s /opt/microsoft/powershell/7/pwsh /usr/local/bin/powershell && \
180 rm /tmp/powershell.tar.gz
181
182# --- s3cmd (for DigitalOcean Spaces management) -------------------------------
183RUN dnf install -y --setopt=zchunk=false s3cmd && dnf clean all
184
185# --- AC Native OS build dependencies -----------------------------------------
186# cage: Wayland kiosk compositor for Firefox OAuth popup (tiny: 65KB)
187# qemu: for local QEMU testing of AC OS builds
188RUN dnf install -y --setopt=zchunk=false cage qemu-system-x86-core edk2-ovmf && dnf clean all
189
190# --- Cockpit (web-based system management UI) --------------------------------
191# Note: service/journal features require systemd; terminal + metrics work without it
192RUN dnf install -y --setopt=zchunk=false cockpit cockpit-ws cockpit-bridge cockpit-system cockpit-networkmanager && dnf clean all
193
194# --- Jupyter bits -------------------------------------------------------------
195RUN dnf install -y --setopt=zchunk=false python3-notebook python3-nbconvert && dnf clean all
196
197# --- gcloud SDK ---------------------------------------------------------------
198RUN curl -sSL https://sdk.cloud.google.com > /tmp/install_gcloud.sh && \
199 bash /tmp/install_gcloud.sh --disable-prompts --install-dir=/opt && \
200 ln -s /opt/google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud && \
201 ln -s /opt/google-cloud-sdk/bin/gsutil /usr/local/bin/gsutil && \
202 ln -s /opt/google-cloud-sdk/bin/bq /usr/local/bin/bq && \
203 rm /tmp/install_gcloud.sh
204
205# --- signal-cli (native binary, no JVM needed) --------------------------------
206RUN set -eux; \
207 SIGNAL_CLI_VERSION=0.14.1 && \
208 curl -fsSL "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux-native.tar.gz" \
209 | tar xz -C /usr/local/bin
210
211# --- User ---------------------------------------------------------------------
212RUN useradd -m me && echo "me ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && chsh -s /usr/bin/fish me
213
214# Fix fish path issue: Fedora installs to /usr/sbin but shebangs expect /usr/bin
215RUN if test ! -f /usr/bin/fish && test -f /usr/sbin/fish; then \
216 ln -s /usr/sbin/fish /usr/bin/fish; \
217 fi
218
219USER me
220WORKDIR /home/me
221
222# --- Claude Code native binary (for AC OS initramfs bundling) -----------------
223RUN curl -fsSL https://claude.ai/install.sh | bash
224
225# --- Rust + websocat (built from source) --------------------------------------
226RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \
227 . "$HOME/.cargo/env" && \
228 git clone https://github.com/vi/websocat.git && \
229 cd websocat && cargo build --release && sudo cp target/release/websocat /usr/local/bin/ && \
230 cd /home/me && cargo install --git https://github.com/boxdot/gurk-rs gurk && \
231 sudo cp /home/me/.cargo/bin/gurk /usr/local/bin/
232
233# --- fnm / Node toolchain (PART 1: Create directories with correct ownership FIRST) ---
234RUN mkdir -p /home/me/.config/fish/conf.d /home/me/.config/fish/functions && \
235 mkdir -p /home/me/.local/share/fish && \
236 chown -R me:me /home/me/.config && \
237 chown -R me:me /home/me/.local && \
238 chmod -R 755 /home/me/.config && \
239 chmod -R 755 /home/me/.local
240
241# --- fnm / Node toolchain (PART 2: Now install fnm and node) ------------------
242RUN curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "$HOME/.fnm" --skip-shell
243ENV PATH="/home/me/.fnm:${PATH}"
244RUN echo 'fnm env --use-on-cd --shell fish | source' > /home/me/.config/fish/conf.d/fnm.fish && \
245 export PATH="/home/me/.fnm:${PATH}" && \
246 eval "$(/home/me/.fnm/fnm env --use-on-cd)" && \
247 /home/me/.fnm/fnm install lts-jod && \
248 /home/me/.fnm/fnm install 20.5.0 && \
249 /home/me/.fnm/fnm default lts-jod && \
250 /home/me/.fnm/fnm use lts-jod && \
251 npm i -g prettier typescript typescript-language-server npm-check-updates @anthropic-ai/claude-code @openai/codex netlify-cli wrangler && \
252 echo 'fnm use lts-jod' >> /home/me/.config/fish/config.fish && \
253 chown -R me:me /home/me/.config/fish
254
255# --- ATProto dependencies for /at directory ------------------------------------
256# Note: These will be available globally for ATProto experiments
257# See /at directory for ATProto/Bluesky exploration tools
258RUN export PATH="/home/me/.fnm:${PATH}" && \
259 eval "$(/home/me/.fnm/fnm env --use-on-cd)" && \
260 npm i -g @atproto/api@^0.17.0 @atproto/xrpc@^0.6.5 @atproto/lexicon@^0.4.2 @atproto/identity@^0.4.3 @atproto/syntax@^0.3.1 dotenv@^16.4.5
261
262# --- SBCL / Quicklisp ---------------------------------------------------------
263RUN curl -fsSLO https://beta.quicklisp.org/quicklisp.lisp && \
264 sbcl --non-interactive \
265 --load quicklisp.lisp \
266 --eval '(quicklisp-quickstart:install)' \
267 --eval '(ql-util:without-prompting (ql:add-to-init-file))' \
268 --eval '(quit)'
269
270# --- OPS (nanos) --------------------------------------------------------------
271# RUN curl https://ops.city/get.sh -sSfL | bash || echo "OPS installation failed, skipping..."
272
273# --- uv (fast Python package manager for MCP servers) -------------------------
274# --- emacs-mcp-server (for VS Code Copilot <-> Emacs integration) -------------
275# Combined into single RUN to ensure uv is available immediately after install
276RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
277 export PATH="$HOME/.local/bin:$PATH" && \
278 uv --version && \
279 git clone https://github.com/vivekhaldar/emacs-mcp-server.git /home/me/emacs-mcp-server && \
280 cd /home/me/emacs-mcp-server && \
281 uv sync
282ENV PATH="/home/me/.local/bin:${PATH}"
283
284# --- Deno ---------------------------------------------------------------------
285RUN curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/home/me/.deno sh -s v2.4.5 && \
286 /home/me/.deno/bin/deno --version && \
287 /home/me/.deno/bin/deno cache https://v2-13-0--edge.netlify.com/bootstrap/index-combined.ts 2>/dev/null || true && \
288 /home/me/.deno/bin/deno cache https://v2-13-0--edge.netlify.com/bootstrap/handler.ts 2>/dev/null || true && \
289 /home/me/.deno/bin/deno cache https://v2-13-0--edge.netlify.com/bootstrap/server.ts 2>/dev/null || true
290
291# --- Fish config / entry ------------------------------------------------------
292# Directories were already created above during fnm setup, now just copy files
293COPY --chown=me:me config.fish /home/me/.config/fish/config.fish
294COPY --chown=me:me entry.fish /entry.fish
295
296# Ensure jupyter directory exists with correct permissions
297RUN mkdir -p /home/me/.jupyter && \
298 chmod -R u+rw /home/me/.jupyter
299
300# --- IPython preload ----------------------------------------------------------
301RUN mkdir -p /home/me/.ipython/profile_default/startup && \
302 echo "import sys; sys.path.append('/workspaces/aesthetic-computer/notebook'); import aesthetic" > /home/me/.ipython/profile_default/startup/00-aesthetic.py && \
303 sudo chown -R me:me /home/me/.ipython
304
305# --- GYP shim (legacy consumers) ---------------------------------------------
306RUN mkdir -p /home/me/.local/lib/python3.10/site-packages && \
307 git clone https://chromium.googlesource.com/external/gyp.git /home/me/.local/lib/python3.10/site-packages/gyp || true && \
308 chown -R me:me /home/me/.local
309
310# Optional: default shell session
311# ENTRYPOINT ["/usr/bin/fish", "/entry.fish"]