f09a4f382a
Validate / base-change-warning (push) Successful in 22s
Validate / docs-check (push) Successful in 44s
Validate / validate-base (push) Successful in 3m27s
Validate / validate-omos (push) Successful in 7m3s
Validate / validate-with-pi (push) Failing after 4m33s
Validate / validate-omos-with-pi (push) Failing after 8m29s
Item A — LAN access (base image): - New rootfs/usr/local/lib/opencode-devbox/setup-lan-access.sh, invoked non-fatally from entrypoint-user.sh. On VM-backed hosts (macOS OrbStack / Docker Desktop, detected via host.docker.internal) it generates a writable ~/.ssh-local/config that uses the host as an SSH jump to reach LAN peers; no-op on native Linux. Ships the mechanism (generic 'host' jump alias), not policy (targets stay in the user's bind-mounted ~/.ssh/config). - New env knobs: DEVBOX_LAN_ACCESS (auto|jump|off), HOST_SSH_USER, DEVBOX_HOST_ALIAS. dssh/dscp aliases in .bash_aliases (guarded). Item B — pi-fork (fork) + pi-observational-memory (recall) in pi variants: - Dockerfile.variant clones both elpapi42 repos to /opt and runs npm install there at build time (local-path 'pi install' does not npm-install, so deps must be present to load). New args PI_FORK_REPO/REF, PI_OBSMEM_REPO/REF. - entrypoint-user.sh registers them at runtime via 'pi install /opt/<pkg>' (instant, in-place, idempotent; tools bind on next pi start). - CI resolve-versions resolves each repo's master HEAD to a commit SHA and passes PI_FORK_REF/PI_OBSMEM_REF — same cache-hit guard as PI_VERSION. - smoke-test asserts /opt clones + node_modules + settings.json registration; size thresholds bumped (with-pi 2700->2900, omos-with-pi 3700->3900). Versions unchanged (opencode 1.15.13, pi 0.78.0 — both still latest). Docs: README LAN section + env table, .env.example, AGENTS.md, CHANGELOG. Plan recorded in docs/plan-lan-access-and-pi-extensions.md.
161 lines
8.2 KiB
Docker
161 lines
8.2 KiB
Docker
# opencode-devbox — variant image
|
|
#
|
|
# FROMs a base-<hash> image produced by Dockerfile.base and adds only
|
|
# the variant-specific tools (opencode, pi, oh-my-opencode-slim, Go).
|
|
#
|
|
# The four published variants are produced from THIS Dockerfile by
|
|
# varying build args:
|
|
#
|
|
# variant INSTALL_OPENCODE INSTALL_OMOS INSTALL_PI
|
|
# ───────────────── ──────────────── ──────────── ──────────
|
|
# base true false false
|
|
# omos true true false
|
|
# with-pi true false true
|
|
# omos-with-pi true true true
|
|
#
|
|
# Pass `--build-arg BASE_IMAGE=<repo>:base-<hash>` to select the base.
|
|
# The CI workflow 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
|
|
|
|
# ── Install opencode via npm ─────────────────────────────────────────
|
|
# OPENCODE_VERSION is intentionally pinned in this Dockerfile (not
|
|
# 'latest'). It drives the release tag and gets bumped via a source
|
|
# edit, so the cache-hit class of bug that bit pi-devbox v0.74.0..
|
|
# v0.75.5 cannot apply here.
|
|
ARG INSTALL_OPENCODE=true
|
|
ARG OPENCODE_VERSION=1.15.13
|
|
RUN if [ "${INSTALL_OPENCODE}" = "true" ]; then \
|
|
NPM_CONFIG_PREFIX=/usr npm install -g opencode-ai@${OPENCODE_VERSION} && \
|
|
opencode --version ; \
|
|
fi
|
|
|
|
# ── Optional: pi coding-agent ────────────────────────────────────────
|
|
# 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`,
|
|
# see .gitea/workflows/docker-publish-split.yml § resolve-versions).
|
|
# The default `latest` is for local dev convenience only — it has a
|
|
# known cache-hit footgun when used 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. Currently masked here because OPENCODE_VERSION (a
|
|
# parent layer) bumps every release; will manifest the moment a
|
|
# vN.N.Nb opencode-version-unchanged release ships. See pi-devbox
|
|
# v0.75.5b 2026-05-23 for the discovery + canonical fix.
|
|
ARG INSTALL_PI=false
|
|
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. Refs default to the tracked branch for local dev; CI resolves
|
|
# them to concrete commit SHAs (see resolve-versions in docker-publish-split.yml)
|
|
# so the build-arg string changes when upstream moves — same registry-buildcache
|
|
# cache-hit footgun the PI_VERSION/OMOS_VERSION pins guard against. The clone
|
|
# helper for these uses `git fetch <ref>` (not `--branch`) so it accepts both
|
|
# branch names and raw commit SHAs.
|
|
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 if [ "${INSTALL_PI}" = "true" ]; then \
|
|
set -e && \
|
|
git_clone_retry() { \
|
|
url="$1"; ref="$2"; dest="$3"; \
|
|
for i in 1 2 3 4 5; do \
|
|
if git clone --depth 1 --branch "$ref" "$url" "$dest"; then return 0; fi; \
|
|
rm -rf "$dest"; \
|
|
echo "git clone $url failed (attempt $i/5), retrying in $((i*5))s..."; \
|
|
sleep $((i*5)); \
|
|
done; \
|
|
return 1; \
|
|
} && \
|
|
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_clone_retry https://gitea.jordbo.se/joakimp/pi-toolkit.git "${PI_TOOLKIT_REF}" /opt/pi-toolkit && \
|
|
git_clone_retry 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)" ; \
|
|
fi
|
|
|
|
# ── Optional: Go ─────────────────────────────────────────────────────
|
|
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
|
|
|
|
# ── Optional: oh-my-opencode-slim (multi-agent orchestration) ────────
|
|
# Installs Bun runtime and the oh-my-opencode-slim npm package.
|
|
# OMOS_VERSION shares the same cache-hit footgun as PI_VERSION when
|
|
# left at the `latest` default in registry-cached CI builds. CI
|
|
# resolves it via `npm view oh-my-opencode-slim version` and passes
|
|
# the concrete value as a build-arg. See PI_VERSION block above.
|
|
ARG INSTALL_OMOS=false
|
|
ARG OMOS_VERSION=latest
|
|
RUN if [ "${INSTALL_OMOS}" = "true" ]; then \
|
|
ARCH=$(uname -m) && \
|
|
if [ "$ARCH" = "x86_64" ]; then \
|
|
BUN_ARCH="x64-baseline"; \
|
|
elif [ "$ARCH" = "aarch64" ]; then \
|
|
BUN_ARCH="aarch64"; \
|
|
fi && \
|
|
curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors "https://github.com/oven-sh/bun/releases/latest/download/bun-linux-${BUN_ARCH}.zip" -o /tmp/bun.zip && \
|
|
unzip -o /tmp/bun.zip -d /tmp/bun && \
|
|
mv /tmp/bun/bun-linux-${BUN_ARCH}/bun /usr/local/bin/bun && \
|
|
chmod +x /usr/local/bin/bun && \
|
|
ln -sf bun /usr/local/bin/bunx && \
|
|
rm -rf /tmp/bun /tmp/bun.zip && \
|
|
bun --version && \
|
|
test -L /usr/local/bin/bunx && \
|
|
NPM_CONFIG_PREFIX=/usr npm install -g oh-my-opencode-slim@${OMOS_VERSION}; \
|
|
fi
|
|
|
|
# WORKDIR / ENTRYPOINT / CMD inherited from base.
|