#!/usr/bin/env bash set -euo pipefail workspace="$HOME/ai_workspace" app="opencode" env="" rebuild=false while [[ $# -gt 0 ]]; do case "$1" in -p|--path) workspace="$(readlink -f "$2")" shift 2 ;; -a|--app) app="$2" shift 2 ;; -e|--env) env="$2" shift 2 ;; --rebuild) rebuild=true shift ;; *) echo "Usage: $0 [-p /path/to/workspace] [-a claude|opencode|vibe] [-e rust] [--rebuild]" >&2 exit 1 ;; esac done case "$app" in claude) image_name="claude-code-local" install_pkg="RUN apt-get update && apt-get install -y npm && npm install -g @anthropic-ai/claude-code" cmd="claude" extra_volumes=( -v "$HOME/.claude:$HOME/.claude" -v "$HOME/.claude.json:$HOME/.claude.json" ) ;; vibe) image_name="vibe-local" install_pkg="RUN apt-get update && apt-get install -y curl && curl -LsSf https://mistral.ai/vibe/install.sh | bash" cmd="vibe" ;; opencode) image_name="opencode-local" install_pkg="RUN apt-get update && apt-get install -y npm && npm install -g opencode-ai" cmd="opencode" extra_volumes=( -v "$HOME/.config/opencode:$HOME/.config/opencode" -v "$HOME/.local/share/opencode:$HOME/.local/share/opencode" -v "$HOME/.local/state/opencode:$HOME/.local/state/opencode" -v "$HOME/.cache:$HOME/.cache" -v "$HOME/.config/meridian:$HOME/.config/meridian" -v "$HOME/.claude:$HOME/.claude" # allow access to claude config for hacked auth ) ;; *) echo "Unknown app '$app'. Choose 'claude' or 'opencode'." >&2 exit 1 ;; esac env_suffix="" env_layer="" case "$env" in "") ;; rust) env_suffix="-rust" env_layer='ENV RUSTUP_HOME=/opt/rust/rustup CARGO_HOME=/opt/rust/cargo PATH=/opt/rust/cargo/bin:${PATH} RUN curl --proto '"'"'=https'"'"' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path && chmod -R a+rwX /opt/rust' ;; rust-esp32) env_suffix="-rust-esp32" env_layer='ENV RUSTUP_HOME=/opt/rust/rustup CARGO_HOME=/opt/rust/cargo PATH=/opt/rust/cargo/bin:${PATH} RUN curl --proto '"'"'=https'"'"' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path RUN cargo install espup && espup install --export-file /opt/rust/export-esp.sh RUN chmod -R a+rwX /opt/rust RUN printf '"'"'#!/bin/bash\n. /opt/rust/export-esp.sh\nexec "$@"\n'"'"' > /entrypoint.sh && chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]' ;; *) echo "Unknown env '$env'. Supported: rust, rust-esp32" >&2 exit 1 ;; esac image_name="${image_name}${env_suffix}" if $rebuild || ! docker image inspect "$image_name" &>/dev/null; then echo "Building $image_name..." dockerfile="FROM debian:bookworm ENV PATH=/root/.local/bin/:$PATH ${env_layer} $install_pkg WORKDIR /workspace CMD [\"$cmd\"]" docker build --pull -t "$image_name" - <<< "$dockerfile" fi docker run -it --rm \ --name "${image_name}-container" \ --user "$(id -u):$(id -g)" \ -e HOME="$HOME" \ -v "$workspace:/workspace" \ "${extra_volumes[@]}" \ -w /workspace \ "$image_name"