Files
pi-devbox/Dockerfile.variant
T
pi 8b69b3625b fix: use git_fetch_ref for pi-toolkit and pi-extensions clones
The previous clone helper for these two repos (git_clone_retry) used
`git clone --branch <ref>`, which only accepts branch names or tags,
NOT commit SHAs. Run 374 (the workflow_dispatch retry of v1.0.0)
failed at smoke because the workflow's resolve-versions step had been
extended to resolve PI_TOOLKIT_REF and PI_EXTENSIONS_REF to commit
SHAs (commit b55b44e), and `git clone --branch <40-char-SHA>` fails
with 'Remote branch not found'.

Switching all four clones to git_fetch_ref (`git fetch + checkout
FETCH_HEAD`) makes the build accept both branch names AND SHAs
uniformly. Both Gitea and GitHub allow fetching arbitrary commits by
default (uploadpack.allowReachableSHA1InWant).

The unused git_clone_retry helper is removed; comment explaining the
choice and the historical context is in its place.

Image was published successfully on run 373; this only affects the
v1.0.0-rerun path (description fix). Image bytes unchanged because the
SHAs being passed match what run 373 cloned by branch name.
2026-06-10 12:28:09 +02:00

110 lines
5.8 KiB
Docker

# pi-devbox — variant image
#
# FROMs a base-<hash> image produced by Dockerfile.base and adds only
# the variant-specific tools — currently just the pi install. Kept as a
# separate file (rather than collapsed into Dockerfile.base) so future
# variants (e.g. studio, studio-tex) can FROM the variant or extend
# this Dockerfile with additional build args without rebuilding the
# base on every pi version bump.
#
# Pass `--build-arg BASE_IMAGE=<repo>:base-<hash>` to select the base.
# CI computes the base hash from Dockerfile.base + rootfs/ +
# entrypoint*.sh and feeds it in.
#
# IMPORTANT: the base image sets NPM_CONFIG_PREFIX to
# /home/developer/.pi/npm-global so runtime `pi install npm:...` and
# `npm install -g` by the developer user lands on the named volume.
# At BUILD time we want the baked binaries on /usr so they survive the
# volume mount. Each `npm install -g` below therefore prefixes the
# command with `NPM_CONFIG_PREFIX=/usr`.
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ARG TARGETARCH
ARG USER_NAME=developer
# ── pi coding-agent + companions ─────────────────────────────────────
# pi-toolkit and pi-extensions are cloned into /opt/. entrypoint-user.sh
# runs each repo's install.sh on container start so symlinks land under
# ~/.pi/agent/ on the named volume.
#
# PI_VERSION should be passed explicitly by CI as a concrete version
# (resolved from `npm view @earendil-works/pi-coding-agent version`).
# The default `latest` is for local dev convenience only — it has a
# known cache-hit footgun in registry-cached CI builds: the resulting
# build-arg string is byte-identical across builds, the layer-hash is
# identical, and the registry buildcache silently reuses the layer
# from whatever pi version was current when the cache was first
# populated. CI MUST pass a resolved concrete version. See pi-devbox
# v0.75.5b 2026-05-23 for the discovery + canonical fix.
ARG PI_VERSION=latest
ARG PI_TOOLKIT_REF=main
ARG PI_EXTENSIONS_REF=main
# pi-fork (fork tool) + pi-observational-memory (recall tool) live on GitHub
# under elpapi42. CI resolves these to commit SHAs to defeat the same
# cache-hit footgun that affects PI_VERSION.
ARG PI_FORK_REPO=https://github.com/elpapi42/pi-fork.git
ARG PI_FORK_REF=master
ARG PI_OBSMEM_REPO=https://github.com/elpapi42/pi-observational-memory.git
ARG PI_OBSMEM_REF=master
RUN set -e && \
# git_fetch_ref: clone-equivalent helper that accepts EITHER a branch name
# OR a commit SHA as $ref. Uses `git fetch <ref> + checkout FETCH_HEAD`
# which (a) works with both name and SHA forms uniformly, and (b) defeats
# the registry-buildcache footgun when CI passes a resolved SHA. The
# earlier helper `git_clone_retry` (using `git clone --branch`) only
# worked with branch names — a SHA-resolved build-arg made `git clone
# --branch <40-char-SHA>` fail with "Remote branch not found". Surfaced
# in pi-devbox v1.0.0-rerun (run 374) 2026-06-10 and fixed by switching
# all four clones to git_fetch_ref. Both Gitea and GitHub allow fetching
# arbitrary commits by default (uploadpack.allowReachableSHA1InWant).
git_fetch_ref() { \
url="$1"; ref="$2"; dest="$3"; \
rm -rf "$dest"; mkdir -p "$dest"; \
git -C "$dest" init -q && git -C "$dest" remote add origin "$url" && \
for i in 1 2 3 4 5; do \
if git -C "$dest" fetch --depth 1 origin "$ref" && git -C "$dest" checkout -q FETCH_HEAD; then return 0; fi; \
echo "git fetch $url@$ref failed (attempt $i/5), retrying in $((i*5))s..."; \
sleep $((i*5)); \
done; \
return 1; \
} && \
if [ "${PI_VERSION}" = "latest" ]; then \
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent ; \
else \
NPM_CONFIG_PREFIX=/usr npm install -g @earendil-works/pi-coding-agent@${PI_VERSION} ; \
fi && \
pi --version && \
git_fetch_ref "https://gitea.jordbo.se/joakimp/pi-toolkit.git" "${PI_TOOLKIT_REF}" /opt/pi-toolkit && \
git_fetch_ref "https://gitea.jordbo.se/joakimp/pi-extensions.git" "${PI_EXTENSIONS_REF}" /opt/pi-extensions && \
git_fetch_ref "${PI_FORK_REPO}" "${PI_FORK_REF}" /opt/pi-fork && \
git_fetch_ref "${PI_OBSMEM_REPO}" "${PI_OBSMEM_REF}" /opt/pi-observational-memory && \
(cd /opt/pi-fork && npm install --omit=dev --no-audit --no-fund) && \
(cd /opt/pi-observational-memory && npm install --omit=dev --no-audit --no-fund) && \
echo "pi-toolkit at $(cd /opt/pi-toolkit && git rev-parse --short HEAD)" && \
echo "pi-extensions at $(cd /opt/pi-extensions && git rev-parse --short HEAD)" && \
echo "pi-fork at $(cd /opt/pi-fork && git rev-parse --short HEAD)" && \
echo "pi-observational-memory at $(cd /opt/pi-observational-memory && git rev-parse --short HEAD)"
# ── Optional: Go toolchain ───────────────────────────────────────────
# Off by default; opt in for users who run Go tools inside the devbox.
ARG INSTALL_GO=false
ARG GO_VERSION=latest
RUN if [ "${INSTALL_GO}" = "true" ]; then \
GOARCH=$(case "${TARGETARCH}" in amd64) echo "amd64" ;; arm64) echo "arm64" ;; *) echo "amd64" ;; esac) && \
V="${GO_VERSION}" && \
if [ "$V" = "latest" ]; then \
V=$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://go.dev/dl/?mode=json" | \
awk -F'"' '/"version":/ { sub(/^go/,"",$4); print $4; exit }'); \
fi && \
[ -n "$V" ] && \
echo "Installing Go ${V}" && \
curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://go.dev/dl/go${V}.linux-${GOARCH}.tar.gz" | tar -C /usr/local -xz && \
ln -s /usr/local/go/bin/go /usr/local/bin/go && \
ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt; \
fi
# WORKDIR / ENTRYPOINT / CMD inherited from base.