Initial commit: pi-devbox v0.74.0
pi coding-agent container built on opencode-devbox:base-latest. Includes Dockerfile, docker-compose, CI workflow, smoke-test, README, CHANGELOG, AGENTS.md.
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
# pi-devbox environment configuration
|
||||||
|
# Copy this file to .env and fill in your values:
|
||||||
|
# cp .env.example .env
|
||||||
|
|
||||||
|
# ── Workspace ────────────────────────────────────────────────────────
|
||||||
|
# Path on host to mount as /workspace in the container
|
||||||
|
WORKSPACE_PATH=~/projects
|
||||||
|
|
||||||
|
# Path to SSH keys on host
|
||||||
|
SSH_KEY_PATH=~/.ssh
|
||||||
|
|
||||||
|
# ── Git Configuration ────────────────────────────────────────────────
|
||||||
|
GIT_USER_NAME=
|
||||||
|
GIT_USER_EMAIL=
|
||||||
|
|
||||||
|
# ── Gitea (for gitea-mcp MCP server) ────────────────────────────────
|
||||||
|
# GITEA_ACCESS_TOKEN=
|
||||||
|
# GITEA_HOST=https://gitea.example.com
|
||||||
|
|
||||||
|
# ── GitHub (optional, for GitHub MCP / git operations) ───────────────
|
||||||
|
# GITHUB_PERSONAL_ACCESS_TOKEN=
|
||||||
|
|
||||||
|
# ── AWS (optional, for AWS CLI / Bedrock) ────────────────────────────
|
||||||
|
# AWS_REGION=eu-west-1
|
||||||
|
# AWS_PROFILE=default
|
||||||
|
# AWS_ACCESS_KEY_ID=
|
||||||
|
# AWS_SECRET_ACCESS_KEY=
|
||||||
|
|
||||||
|
# ── Skillset (agent skills and instructions) ─────────────────────────
|
||||||
|
# If you have a skillset repo, the entrypoint auto-deploys skills and
|
||||||
|
# instructions on container start using relative symlinks.
|
||||||
|
# Detection is automatic if the skillset lives at WORKSPACE_PATH/skillset.
|
||||||
|
# SKILLSET_CONTAINER_PATH=
|
||||||
|
|
||||||
|
# ── Locale ───────────────────────────────────────────────────────────
|
||||||
|
# LANG=sv_SE.UTF-8
|
||||||
|
# LANGUAGE=sv_SE:sv
|
||||||
|
# LC_ALL=sv_SE.UTF-8
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
name: Publish Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILDKIT_PROGRESS: plain
|
||||||
|
IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/pi-devbox
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
smoke:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf
|
||||||
|
- run: |
|
||||||
|
rm -rf /opt/hostedtoolcache /opt/microsoft /opt/az /opt/ghc \
|
||||||
|
/usr/local/.ghcup /usr/share/dotnet /usr/share/swift \
|
||||||
|
/usr/local/lib/android /usr/local/share/powershell \
|
||||||
|
/usr/local/share/chromium /usr/local/share/boost \
|
||||||
|
/usr/lib/jvm 2>/dev/null || true
|
||||||
|
docker system prune -af --volumes || true
|
||||||
|
docker builder prune -af || true
|
||||||
|
|
||||||
|
- uses: docker/setup-buildx-action@v4
|
||||||
|
with: {driver-opts: network=host}
|
||||||
|
|
||||||
|
- name: Build (amd64, load to local daemon)
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: pi-devbox:smoke
|
||||||
|
|
||||||
|
- name: Smoke test
|
||||||
|
run: bash scripts/smoke-test.sh pi-devbox:smoke
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs: smoke
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf
|
||||||
|
- run: |
|
||||||
|
rm -rf /opt/hostedtoolcache /opt/microsoft /opt/az /opt/ghc \
|
||||||
|
/usr/local/.ghcup /usr/share/dotnet /usr/share/swift \
|
||||||
|
/usr/local/lib/android /usr/local/share/powershell \
|
||||||
|
/usr/local/share/chromium /usr/local/share/boost \
|
||||||
|
/usr/lib/jvm 2>/dev/null || true
|
||||||
|
docker system prune -af --volumes || true
|
||||||
|
docker builder prune -af || true
|
||||||
|
|
||||||
|
- uses: docker/setup-qemu-action@v3
|
||||||
|
with: {platforms: arm64}
|
||||||
|
- uses: docker/setup-buildx-action@v4
|
||||||
|
with: {driver-opts: network=host}
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Compute tags
|
||||||
|
id: tags
|
||||||
|
run: |
|
||||||
|
VERSION="${{ github.ref_name }}"
|
||||||
|
{ echo "tags<<EOF"
|
||||||
|
echo "${IMAGE}:${VERSION}"
|
||||||
|
echo "${IMAGE}:latest"
|
||||||
|
echo "EOF"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Build and push (amd64 + arm64)
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.tags.outputs.tags }}
|
||||||
|
cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache
|
||||||
|
cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max
|
||||||
|
|
||||||
|
update-description:
|
||||||
|
needs: publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Update Docker Hub description
|
||||||
|
run: |
|
||||||
|
PAYLOAD=$(jq -n --rawfile desc DOCKER_HUB.md '{"full_description": $desc}')
|
||||||
|
TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/auth/token" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"username\":\"${{ vars.DOCKERHUB_USERNAME }}\",\"password\":\"${{ secrets.DOCKERHUB_TOKEN }}\"}" \
|
||||||
|
| jq -r '.token')
|
||||||
|
curl -s -X PATCH "https://hub.docker.com/v2/repositories/${{ vars.DOCKERHUB_USERNAME }}/pi-devbox/" \
|
||||||
|
-H "Authorization: Bearer ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "${PAYLOAD}" | jq -r '.full_description | if . then "✅ description updated (\(. | length) chars)" else "❌ update failed" end'
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# AGENTS.md — pi-devbox
|
||||||
|
|
||||||
|
Container image that adds pi coding-agent on top of the opencode-devbox base image.
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
|
|
||||||
|
- `Dockerfile` — single-stage build, `FROM opencode-devbox:base-latest`, installs pi + companion repos
|
||||||
|
- `docker-compose.yml` — compose file for local use
|
||||||
|
- `.env.example` — environment variable template
|
||||||
|
- `scripts/smoke-test.sh` — sanity checks run by CI before pushing to Docker Hub
|
||||||
|
- `.gitea/workflows/docker-publish.yml` — CI pipeline: smoke amd64 → multi-arch push → update Hub description
|
||||||
|
|
||||||
|
## Versioning scheme
|
||||||
|
|
||||||
|
- Tags follow the pi npm version: `v{pi_version}[letter]`
|
||||||
|
- Bump `PI_VERSION` build-arg default in `Dockerfile` when cutting a new release
|
||||||
|
- Docker Hub: `joakimp/pi-devbox:vX.Y.Z` + `joakimp/pi-devbox:latest`
|
||||||
|
|
||||||
|
## Release-day checklist
|
||||||
|
|
||||||
|
1. Bump `PI_VERSION` in `Dockerfile` (or leave as `latest` to pick up current)
|
||||||
|
2. Update `CHANGELOG.md`: promote `Unreleased` → `vX.Y.Z — YYYY-MM-DD`
|
||||||
|
3. Add fresh `## Unreleased` section
|
||||||
|
4. Commit, tag `vX.Y.Z`, push tag → CI fires automatically
|
||||||
|
|
||||||
|
## Key facts
|
||||||
|
|
||||||
|
- **Base image**: `joakimp/opencode-devbox:base-latest` — rebuilt whenever opencode-devbox cuts a new base
|
||||||
|
- **pi binary**: baked at `/usr/bin/pi` (system npm prefix); `NPM_CONFIG_PREFIX=/home/developer/.pi/npm-global` at runtime so user-installed pi/packages land on the named volume
|
||||||
|
- **Companion repos**: pi-toolkit and pi-extensions cloned to `/opt/` at build time; `entrypoint-user.sh` (inherited from base) deploys symlinks to `~/.pi/agent/` on container start
|
||||||
|
- **MemPalace**: fully operational — inherited from base image; bridge extension deployed by entrypoint
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Do NOT call `mempalace-toolkit/install.sh` in the Dockerfile — the base entrypoint handles it
|
||||||
|
- `NPM_CONFIG_PREFIX=/usr` must be set per-RUN for any build-time `npm install -g` to keep baked binaries off the volume-shadowed path
|
||||||
|
- The smoke test threshold is 2200 MB — update if the image legitimately grows past it
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to the pi-devbox container image.
|
||||||
|
|
||||||
|
Tags follow the pi npm version: `v{pi_version}[letter]` — bare tag for the first build on a new pi release, letter suffix (`b`, `c`, …) for container-level rebuilds on the same version.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## v0.74.0 — 2026-05-14
|
||||||
|
|
||||||
|
Initial release.
|
||||||
|
|
||||||
|
- pi `@earendil-works/pi-coding-agent@0.74.0` baked at `/usr/bin/pi`
|
||||||
|
- pi-toolkit and pi-extensions cloned at build time; deployed to `~/.pi/agent/` by entrypoint on container start
|
||||||
|
- mempalace bridge (`mempalace.ts`) symlinked from `/opt/mempalace-toolkit/`
|
||||||
|
- Built on `joakimp/opencode-devbox:base-latest`
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pi coding-agent container — built on opencode-devbox base. Includes pi, pi-toolkit, pi-extensions, mempalace, AWS CLI, neovim, and full dev toolchain. See https://gitea.jordbo.se/joakimp/pi-devbox for full docs.
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
# pi-devbox — pi coding-agent container
|
||||||
|
#
|
||||||
|
# Builds on top of the opencode-devbox base image, which provides:
|
||||||
|
# Debian trixie, Node.js, AWS CLI, mempalace + MCP server, gitea-mcp,
|
||||||
|
# dev tools (neovim, tmux, bat, eza, fzf, zoxide, ripgrep, uv, rustup),
|
||||||
|
# user setup (developer/gosu), entrypoints, chromadb prewarm.
|
||||||
|
#
|
||||||
|
# This image adds only pi itself and its companion repos.
|
||||||
|
#
|
||||||
|
# Build args:
|
||||||
|
# BASE_IMAGE — base image to build from (default: base-latest)
|
||||||
|
# PI_VERSION — pi npm version: "latest" or a pinned version e.g. "0.74.0"
|
||||||
|
# PI_TOOLKIT_REF — git ref for pi-toolkit (default: main)
|
||||||
|
# PI_EXTENSIONS_REF — git ref for pi-extensions (default: main)
|
||||||
|
|
||||||
|
ARG BASE_IMAGE=joakimp/opencode-devbox:base-latest
|
||||||
|
FROM ${BASE_IMAGE}
|
||||||
|
|
||||||
|
ARG PI_VERSION=latest
|
||||||
|
ARG PI_TOOLKIT_REF=main
|
||||||
|
ARG PI_EXTENSIONS_REF=main
|
||||||
|
|
||||||
|
# Install pi and clone companion repos.
|
||||||
|
# NPM_CONFIG_PREFIX is overridden to /usr so the baked binary lands at the
|
||||||
|
# system prefix — same pattern as opencode-devbox's variant Dockerfile.
|
||||||
|
# At runtime, NPM_CONFIG_PREFIX is reset to /home/developer/.pi/npm-global
|
||||||
|
# (inherited from base ENV) so user-installed packages land on the named
|
||||||
|
# volume and survive container recreate.
|
||||||
|
RUN 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 --depth 1 --branch "${PI_TOOLKIT_REF}" \
|
||||||
|
https://gitea.jordbo.se/joakimp/pi-toolkit.git /opt/pi-toolkit && \
|
||||||
|
git clone --depth 1 --branch "${PI_EXTENSIONS_REF}" \
|
||||||
|
https://gitea.jordbo.se/joakimp/pi-extensions.git /opt/pi-extensions && \
|
||||||
|
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)"
|
||||||
|
|
||||||
|
# WORKDIR / ENTRYPOINT / CMD inherited from base.
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# pi-devbox
|
||||||
|
|
||||||
|
A Docker container image with [pi coding-agent](https://github.com/earendil-works/pi) pre-installed, built on the [opencode-devbox](https://gitea.jordbo.se/joakimp/opencode-devbox) base image.
|
||||||
|
|
||||||
|
## What's inside
|
||||||
|
|
||||||
|
Built on `opencode-devbox:base-latest`, which provides:
|
||||||
|
|
||||||
|
- **Debian trixie** (stable base)
|
||||||
|
- **Node.js** (LTS), **uv** (Python), **rustup** (Rust on-demand)
|
||||||
|
- **AWS CLI** v2
|
||||||
|
- **MemPalace** + MCP server (persistent agent memory across sessions)
|
||||||
|
- **Gitea MCP** server
|
||||||
|
- **Dev tools**: neovim (LazyVim), tmux, bat, eza, fzf, zoxide, ripgrep, git-lfs, make
|
||||||
|
- **Shell**: bash with history tuning, prefix-search, fzf/zoxide integration
|
||||||
|
|
||||||
|
This image adds:
|
||||||
|
|
||||||
|
- **pi** (`@earendil-works/pi-coding-agent`) — baked at `/usr/bin/pi`
|
||||||
|
- **pi-toolkit** — keybindings, env loader, settings template (cloned to `/opt/pi-toolkit`)
|
||||||
|
- **pi-extensions** — ext-toggle, todo, ssh-controlmaster, notify, git-checkpoint, mcp-loader, confirm-destructive (cloned to `/opt/pi-extensions`)
|
||||||
|
- **mempalace bridge** — `mempalace.ts` extension symlinked from `/opt/mempalace-toolkit`
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# edit .env — set WORKSPACE_PATH, GIT_USER_NAME, GIT_USER_EMAIL
|
||||||
|
docker compose run --rm devbox
|
||||||
|
# inside the container:
|
||||||
|
pi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Tags follow the pi npm version: `v0.74.0`, `v0.75.0`, etc.
|
||||||
|
`latest` always points at the most recent release.
|
||||||
|
|
||||||
|
## Persistence
|
||||||
|
|
||||||
|
| Volume | What it holds |
|
||||||
|
|--------|---------------|
|
||||||
|
| `devbox-pi-config` | pi settings, extensions toggle state, sessions (`~/.pi/`) |
|
||||||
|
| `devbox-shell-history` | bash history |
|
||||||
|
| `devbox-zoxide` | zoxide directory jump history |
|
||||||
|
| `devbox-nvim-data` | neovim plugins, Mason packages |
|
||||||
|
| `devbox-uv` | uv Python installs and tool cache |
|
||||||
|
|
||||||
|
## User-installed pi packages
|
||||||
|
|
||||||
|
`NPM_CONFIG_PREFIX` is set to `/home/developer/.pi/npm-global`, so any `pi install npm:...` or `npm install -g` as the `developer` user lands on the `devbox-pi-config` volume and survives container recreation and image rebuilds. A user-installed pi wins over the baked binary via `PATH` order.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- [pi-devbox](https://gitea.jordbo.se/joakimp/pi-devbox) — this repo
|
||||||
|
- [opencode-devbox](https://gitea.jordbo.se/joakimp/opencode-devbox) — base image source
|
||||||
|
- [pi-toolkit](https://gitea.jordbo.se/joakimp/pi-toolkit)
|
||||||
|
- [pi-extensions](https://gitea.jordbo.se/joakimp/pi-extensions)
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# pi-devbox docker-compose
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# cp .env.example .env # configure your keys
|
||||||
|
# docker compose up -d
|
||||||
|
# docker compose exec -u developer devbox pi
|
||||||
|
#
|
||||||
|
# Or for interactive one-shot:
|
||||||
|
# docker compose run --rm devbox
|
||||||
|
|
||||||
|
name: pi-devbox
|
||||||
|
|
||||||
|
services:
|
||||||
|
devbox:
|
||||||
|
image: joakimp/pi-devbox:latest
|
||||||
|
# To build from source instead of pulling from Docker Hub:
|
||||||
|
# build:
|
||||||
|
# context: .
|
||||||
|
# args:
|
||||||
|
# PI_VERSION: "latest"
|
||||||
|
container_name: pi-devbox
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- TERM=xterm-256color
|
||||||
|
- GITEA_ACCESS_TOKEN=${GITEA_ACCESS_TOKEN:-}
|
||||||
|
- GITEA_HOST=${GITEA_HOST:-}
|
||||||
|
- GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_PERSONAL_ACCESS_TOKEN:-}
|
||||||
|
volumes:
|
||||||
|
# Host workspace — mount your project here
|
||||||
|
- ${WORKSPACE_PATH:-.}:/workspace
|
||||||
|
|
||||||
|
# SSH keys (read-only) — for git push/pull
|
||||||
|
- ${SSH_KEY_PATH:-~/.ssh}:/home/developer/.ssh:ro
|
||||||
|
|
||||||
|
# Optional: mount skillset repo for automatic skill/instruction deployment.
|
||||||
|
# - ${SKILLSET_PATH}:/home/developer/skillset
|
||||||
|
|
||||||
|
# Persist pi config (settings.json, extensions, sessions, auth)
|
||||||
|
- devbox-pi-config:/home/developer/.pi
|
||||||
|
|
||||||
|
# Persist bash history across container recreations
|
||||||
|
- devbox-shell-history:/home/developer/.cache/bash
|
||||||
|
|
||||||
|
# Persist zoxide directory history
|
||||||
|
- devbox-zoxide:/home/developer/.local/share/zoxide
|
||||||
|
|
||||||
|
# Persist neovim plugin/Mason data
|
||||||
|
- devbox-nvim-data:/home/developer/.local/share/nvim
|
||||||
|
|
||||||
|
# Persist uv data (Python installs, tool installs)
|
||||||
|
- devbox-uv:/home/developer/.local/share/uv
|
||||||
|
|
||||||
|
# Optional: persist MemPalace data (conversation memory, knowledge graph)
|
||||||
|
# - devbox-palace:/home/developer/.mempalace
|
||||||
|
|
||||||
|
# Optional: persist ChromaDB embedding model cache (~79 MB)
|
||||||
|
# - devbox-chroma-cache:/home/developer/.cache/chroma
|
||||||
|
|
||||||
|
# Optional: AWS credentials/SSO config
|
||||||
|
# - ~/.aws:/home/developer/.aws
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
devbox-pi-config:
|
||||||
|
devbox-shell-history:
|
||||||
|
devbox-zoxide:
|
||||||
|
devbox-nvim-data:
|
||||||
|
devbox-uv:
|
||||||
|
# devbox-palace:
|
||||||
|
# devbox-chroma-cache:
|
||||||
Executable
+92
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# smoke-test.sh — basic sanity checks for the pi-devbox image
|
||||||
|
#
|
||||||
|
# Usage: ./scripts/smoke-test.sh <image>
|
||||||
|
#
|
||||||
|
# Verifies:
|
||||||
|
# - pi binary present and returns a version
|
||||||
|
# - pi-toolkit cloned at /opt/pi-toolkit
|
||||||
|
# - pi-extensions cloned at /opt/pi-extensions
|
||||||
|
# - entrypoint deploys pi-toolkit keybindings symlink
|
||||||
|
# - entrypoint deploys ≥4 extensions
|
||||||
|
# - mempalace bridge symlink present
|
||||||
|
# - settings.json bootstrapped
|
||||||
|
# - image size within threshold
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
IMAGE="${1:?usage: $0 <image>}"
|
||||||
|
PASS=0; FAIL=0
|
||||||
|
SIZE_THRESHOLD_MB=2200
|
||||||
|
|
||||||
|
run() {
|
||||||
|
local label="$1"; local cmd="$2"
|
||||||
|
if docker run --rm --entrypoint="" "$IMAGE" sh -c "$cmd" >/dev/null 2>&1; then
|
||||||
|
printf " ✅ %s\n" "$label"; ((PASS++))
|
||||||
|
else
|
||||||
|
printf " ❌ %s\n" "$label"; ((FAIL++))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== pi-devbox smoke test: $IMAGE ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ── Basic binary checks ───────────────────────────────────────────────
|
||||||
|
echo "── Binaries ──"
|
||||||
|
run "pi" "pi --version"
|
||||||
|
run "node" "node --version"
|
||||||
|
run "git" "git --version"
|
||||||
|
run "aws" "aws --version"
|
||||||
|
run "uv" "uv --version"
|
||||||
|
run "nvim" "nvim --version"
|
||||||
|
run "mempalace-mcp" "mempalace-mcp --help"
|
||||||
|
|
||||||
|
# ── Repo clones ───────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "── Repo clones ──"
|
||||||
|
run "pi-toolkit clone" "test -d /opt/pi-toolkit && git -C /opt/pi-toolkit rev-parse --short HEAD"
|
||||||
|
run "pi-extensions clone" "test -d /opt/pi-extensions && git -C /opt/pi-extensions rev-parse --short HEAD"
|
||||||
|
|
||||||
|
# ── Runtime deployment (needs entrypoint to run) ──────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "── Runtime deployment ──"
|
||||||
|
CID=$(docker run -d --entrypoint="" "$IMAGE" sleep 60)
|
||||||
|
cleanup() { docker rm -f "$CID" >/dev/null 2>&1 || true; }
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Wait for entrypoint-user.sh to finish deploying pi-toolkit + extensions
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if docker exec "$CID" test -L /home/developer/.pi/agent/keybindings.json 2>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
exec_test() {
|
||||||
|
local label="$1"; local cmd="$2"
|
||||||
|
if docker exec "$CID" sh -c "$cmd" >/dev/null 2>&1; then
|
||||||
|
printf " ✅ %s\n" "$label"; ((PASS++))
|
||||||
|
else
|
||||||
|
printf " ❌ %s\n" "$label"; ((FAIL++))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_test "keybindings.json (pi-toolkit)" 'test -L $HOME/.pi/agent/keybindings.json && echo ok'
|
||||||
|
exec_test "extensions ≥ 4 (pi-extensions)" 'count=$(ls -1 $HOME/.pi/agent/extensions/*.ts 2>/dev/null | wc -l); [ $count -ge 4 ] && echo "$count extensions"'
|
||||||
|
exec_test "mempalace.ts bridge" 'test -L $HOME/.pi/agent/extensions/mempalace.ts && echo ok'
|
||||||
|
exec_test "settings.json bootstrapped" 'test -f $HOME/.pi/agent/settings.json && echo ok'
|
||||||
|
|
||||||
|
# ── Image size ────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "── Image size ──"
|
||||||
|
SIZE_MB=$(docker image inspect "$IMAGE" --format='{{.Size}}' | awk '{printf "%d", $1/1048576}')
|
||||||
|
if [ "$SIZE_MB" -le "$SIZE_THRESHOLD_MB" ]; then
|
||||||
|
printf " ✅ size: %d MB (threshold %d MB)\n" "$SIZE_MB" "$SIZE_THRESHOLD_MB"; ((PASS++))
|
||||||
|
else
|
||||||
|
printf " ❌ size: %d MB exceeds threshold %d MB\n" "$SIZE_MB" "$SIZE_THRESHOLD_MB"; ((FAIL++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Summary ───────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "=== Results: ${PASS} passed, ${FAIL} failed ==="
|
||||||
|
[ "$FAIL" -eq 0 ]
|
||||||
Reference in New Issue
Block a user