-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathContainerfile
More file actions
240 lines (222 loc) · 8.15 KB
/
Containerfile
File metadata and controls
240 lines (222 loc) · 8.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
FROM alpine:edge
# Alpine uses musl libc - we use system Chromium with Playwright API
# This gives us excellent package coverage AND browser automation
# Skip Playwright's bundled browser - use system Chromium instead
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium-browser
RUN apk update && apk add --no-cache \
autoconf \
automake \
bash \
bat \
build-base \
bind-tools \
chromium \
cmake \
coreutils \
curl \
dbus \
diffutils \
emacs-gtk3-nativecomp \
aspell-en \
enchant2 \
enchant2-dev \
entr \
eza \
fd \
fontconfig \
fzf \
fzf-zsh-plugin \
gettext-envsubst \
git \
github-cli \
gnupg \
elixir \
erlang-dev \
inotify-tools \
go \
golangci-lint \
gstreamer \
gum \
hunspell \
hunspell-en-us \
jq \
just \
kitty-kitten \
chafa \
vips-tools \
libwebp-tools \
libavif-apps \
libsixel \
libsixel-tools \
mesa \
ncurses \
ncurses-terminfo \
ncurses-terminfo-base \
neovim \
nodejs \
openssh-client \
parallel \
pinentry \
pkgconf \
podman \
procps \
python3 \
py3-pip \
grep \
ripgrep \
ruby \
cargo \
rust \
rust-analyzer \
rustfmt \
shellcheck \
socat \
sqlite \
sudo \
tmux \
uv \
wget \
wl-clipboard \
yadm \
yamllint \
util-linux-misc \
yq \
poppler-utils \
zoxide \
zsh \
gopls \
postgresql \
postgresql-client \
postgresql-contrib \
postgresql-pgvector \
# Tools that were manually installed in Wolfi
ansible-lint \
mise \
musl-locales \
musl-locales-lang \
pnpm \
typescript \
# build files for codex-acp
libcap-dev \
openssl-dev \
# Chromium dependencies for headless operation
nss \
freetype \
iproute2 \
iproute2-ss \
harfbuzz \
yazi \
ttf-freefont \
ttf-dejavu \
wayland-libs-client \
wayland-libs-cursor \
ca-certificates
# User setup
ARG USERNAME=tsb
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG USER_PASSWORD=dev123
RUN addgroup -g $GROUP_ID $USERNAME && \
adduser -D -h /home/$USERNAME -s /bin/zsh -u $USER_ID -G $USERNAME $USERNAME && \
echo "$USERNAME:$USER_PASSWORD" | chpasswd && \
echo "$USERNAME ALL=(ALL) ALL" > /etc/sudoers.d/$USERNAME && \
chmod 0440 /etc/sudoers.d/$USERNAME && \
mkdir -p /tmp/container-runtime && \
chown $USERNAME:$USERNAME /tmp/container-runtime && \
chmod 700 /tmp/container-runtime
# tmux system config (must be written as root)
RUN echo 'set -g allow-passthrough on' > /etc/tmux.conf && \
echo 'set -s set-clipboard on' >> /etc/tmux.conf && \
echo 'set -as terminal-features ",*:clipboard:sixel:extkeys"' >> /etc/tmux.conf
# Root-level setup (no script COPYs here — those go after heavy layers to avoid cache busting)
COPY container/browser-check.js /usr/local/lib/browser-check.js
RUN ln -s /usr/share/zsh/plugins/fzf/completion.zsh /usr/share/fzf/completion.zsh && \
wget -qO /usr/local/bin/hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64 && \
chmod +x /usr/local/bin/hadolint && \
mkdir -p /workspaces /opt/pre-commit-cache && \
chown $USERNAME:$USERNAME /workspaces /opt/pre-commit-cache
USER $USERNAME
ENV HOME=/home/$USERNAME
WORKDIR $HOME
# Pre-commit cache primed at build time to avoid first-commit delays
ENV PRE_COMMIT_HOME=/opt/pre-commit-cache
# pnpm for all Node.js global packages
ENV PNPM_HOME=$HOME/.local/share/pnpm
ENV PATH="$PNPM_HOME:$HOME/.bun/bin:/usr/local/go/bin:$HOME/go/bin:$HOME/.local/bin:$PATH"
# All Node.js global packages in one pnpm install
RUN pnpm add -g \
@biomejs/biome \
playwright \
@playwright/cli \
typescript-language-server \
vscode-langservers-extracted \
bash-language-server \
yaml-language-server \
dockerfile-language-server-nodejs \
pyright \
@ansible/ansible-language-server \
@openai/codex \
@google/gemini-cli \
@mariozechner/pi-coding-agent \
pi-acp \
@agentclientprotocol/claude-agent-acp@latest \
@zed-industries/codex-acp@latest \
markdownlint-cli \
pa11y
RUN cargo install --locked --root $HOME/.local bacon squawk
# Downloads and installs (parallel — cached layer, rarely changes)
RUN mkdir -p $HOME/.local/bin && \
gem install --user-install --bindir "$HOME/.local/bin" tmuxinator && \
pids="" && \
(curl -fsSL -o $HOME/.local/bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64-musl && chmod +x $HOME/.local/bin/tailwindcss) & pids="$pids $!" && \
(go install github.com/air-verse/air@latest) & pids="$pids $!" && \
(go install github.com/zricethezav/gitleaks/v8@latest) & pids="$pids $!" && \
(go install github.com/a-h/templ/cmd/templ@latest) & pids="$pids $!" && \
(curl -fsSL https://bun.sh/install | bash) & pids="$pids $!" && \
(curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash) & pids="$pids $!" && \
(uv tool install ruff) & pids="$pids $!" && \
(uv tool install ty) & pids="$pids $!" && \
(uv tool install pre-commit) & pids="$pids $!" && \
(uv tool install open-terminal) & pids="$pids $!" && \
for p in $pids; do wait "$p" || exit 1; done && \
curl -fsSL https://claude.ai/install.sh | bash && \
command -v claude >/dev/null && \
# browser-check wrapper (resolve pnpm global node_modules at build time)
printf '#!/bin/sh\nNODE_PATH=%s exec node /usr/local/lib/browser-check.js "$@"\n' "$(pnpm root -g)" > $HOME/.local/bin/browser-check && \
chmod +x $HOME/.local/bin/browser-check
COPY --chown=$USERNAME:$USERNAME container/pre-commit-hooks.yaml /tmp/pre-commit-hooks.yaml
RUN git config --global init.defaultBranch main
RUN cd /tmp && git init pre-commit-repo && cd pre-commit-repo && \
pre-commit install-hooks -c /tmp/pre-commit-hooks.yaml && \
cd / && rm -rf /tmp/pre-commit-repo /tmp/pre-commit-hooks.yaml
# Config (changes often — keep on its own layer)
RUN mkdir -p $HOME/.config/emacs $HOME/.claude $HOME/.gemini $HOME/.codex $HOME/.pi && \
mkdir -p $HOME/.gnupg && chmod 700 $HOME/.gnupg && \
echo "allow-loopback-pinentry" > $HOME/.gnupg/gpg-agent.conf && \
echo 'set -s set-clipboard on' > $HOME/.tmux.conf && \
echo 'set -s copy-command "wl-copy"' >> $HOME/.tmux.conf && \
echo 'set -g base-index 1' >> $HOME/.tmux.conf && \
echo 'alias claude="env -u ANTHROPIC_API_KEY claude --dangerously-skip-permissions"' >> $HOME/.zshrc.container && \
echo 'alias gemini="gemini --yolo --no-sandbox"' >> $HOME/.zshrc.container && \
echo 'alias codex="codex --dangerously-bypass-approvals-and-sandbox"' >> $HOME/.zshrc.container && \
echo 'alias vi=nvim' >> $HOME/.zshrc.container && \
echo 'alias vim=nvim' >> $HOME/.zshrc.container && \
echo "alias icat='kitten icat'" >> $HOME/.zshrc.container && \
echo 'export EDITOR=nvim' >> $HOME/.zshrc.container && \
echo 'eval "$(mise activate zsh)"' >> $HOME/.zshrc.container && \
echo 'export HISTFILE=$HOME/.zsh-state/.histfile' >> $HOME/.zshrc.container && \
echo '[ "$(tmux display-message -p "#{window_name}" 2>/dev/null)" = "shell" ] && motd 2>/dev/null' >> $HOME/.zshrc.container
ENV EMACS_CONTAINER=1
ENV LANG=en_US.UTF-8
# Container scripts (late layer — changes here don't bust pnpm/cargo cache)
COPY --chmod=755 container/e container/wt container/motd container/notify container/db container/npm container/npx container/pnpmx container/share /usr/local/bin/
COPY --chown=$USERNAME:$USERNAME container/entrypoint.sh container/tmux-layout.sh $HOME/
RUN mkdir -p $HOME/.config/tmuxinator
COPY --chown=$USERNAME:$USERNAME container/dev.yml $HOME/.config/tmuxinator/dev.yml
COPY --chown=$USERNAME:$USERNAME container/zimrc $HOME/.zimrc
RUN chmod +x $HOME/entrypoint.sh $HOME/tmux-layout.sh && \
curl -fsSL -o $HOME/.zim/zimfw.zsh --create-dirs \
https://github.com/zimfw/zimfw/releases/latest/download/zimfw.zsh && \
zsh -c "ZIM_HOME=$HOME/.zim source $HOME/.zim/zimfw.zsh init -q"
ENTRYPOINT ["sh", "-c", "exec \"$HOME/entrypoint.sh\" \"$@\"", "--"]