Ctrl K
ComunidadGuías…

Dockerfile.opencode

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# =========================
# Stage 1 — Builder
# =========================
# Pinned to opencode's packageManager (root package.json: bun@1.3.14); the
# upstream build hard-fails on an older bun. Track after each fork sync.
FROM oven/bun:1.3.11 AS builder

WORKDIR /app

RUN apt-get update && apt-get install -y \
    git \
    python3 \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# Clone OpenCode
RUN git clone https://github.com/ASCIT31/opencode.git .

# Install deps
# Resilience: the synced opencode pulls ghostty-web from a GitHub tarball
# (github:anomalyco/ghostty-web). codeload.github.com rate-limits (HTTP 429) the
# self-hosted runner's shared IP, so retry the fetch with backoff.
RUN n=0; until bun install; do \
      n=$((n+1)); [ "$n" -ge 6 ] && { echo "install: giving up after $n attempts"; exit 1; }; \
      echo "bun install failed (attempt $n) — codeload 429 likely; backing off $((n*20))s"; \
      sleep $((n*20)); \
    done

# Darkmoon branding on the CURRENT upstream opencode layout (see Dark-Moon-Front-API
# for full rationale): upstream moved the TUI to @opencode-ai/tui and rewrote
# installation/index.ts + cli/ui.ts (Effect). The old full-file overrides are stale
# and break the build. Minimal, resilient footprint instead:
#   1) Logo    -> overwrite the single data module packages/opencode/src/cli/logo.ts.
#   2) Version -> OPENCODE_VERSION env (script resolver is env-first -> InstallationVersion).
COPY conf/tui/logo.ts \
     /app/packages/opencode/src/cli/logo.ts

ENV OPENCODE_VERSION=opencode-darkmoon-1.3.0

# No sed needed: cli/ui.ts (head-less banner) and cli/cmd/tui/component/logo.tsx
# (TUI) both import the single logo module we replaced above, so the DARK MOON
# art renders in both. The old sed on cli/ui.ts's "wordmark" loop is obsolete
# since the 2026-10 fork resync (upstream merged packages/tui into packages/opencode).
# Guarded by tools/opencode-branding-test.sh after each image build.

ENV BUN_INSTALL_CACHE_DIR=/tmp/bun-cache
RUN rm -rf ~/.bun /tmp/bun-cache
# Build OpenCode
# Same codeload/429 resilience for the build (build.ts resolves github: deps too).
RUN cd packages/opencode && n=0; until bun ./script/build.ts --single; do \
      n=$((n+1)); [ "$n" -ge 6 ] && { echo "opencode build: giving up after $n attempts"; exit 1; }; \
      echo "opencode build failed (attempt $n) — codeload 429 likely; backing off $((n*20))s"; \
      sleep $((n*20)); \
    done

# Extract binary
RUN cd packages/opencode && \
    find dist -type f -path "*/bin/opencode" -exec cp {} /opencode-bin \;

# =========================
# Stage 2 — Runtime
# =========================
FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y \
    ca-certificates \
    bash \
    docker.io \
    inotify-tools \
 && rm -rf /var/lib/apt/lists/*

# ------------------------------------------------------------
# OpenCode Agents (Darkmoon) - ensuite c'est l'entrypoint qui copie-collera dans /root/.opencode/agents
# ------------------------------------------------------------

# Agents par défaut (dans l'image)
RUN mkdir -p /opt/darkmoon/default-agents
COPY conf/agents/ /opt/darkmoon/default-agents/

# Darkmoon privacy plugin (issue #40, section 3): pre-model prompt tokenization.
# A stable file:// opencode plugin (uses only the public `chat.message` hook +
# Bun fetch to the MCP's local unix socket) — no opencode core patching, so an
# opencode fork sync cannot break it. Registered in opencode.json by apply-settings.sh.
COPY conf/plugins/ /opt/darkmoon/plugins/

# ------------------------------------------------------------
# Darkmoon MCP Server (embedded, CLEAN)
# ------------------------------------------------------------

ENV DM_MCP_HOME=/opt/darkmoon/mcp

# Dépendances runtime strictement nécessaires au MCP
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 \
    python3-venv \
    python3-pip \
    bc \
 && rm -rf /var/lib/apt/lists/*

# Copie du serveur MCP Darkmoon
COPY mcp ${DM_MCP_HOME}/server

# Copie des workflow vers default-workflow qui seront ensuite copié vers le volume partagé pour éviter des écraser
RUN mkdir -p /opt/darkmoon/default-workflows
COPY mcp/src/tools/workflows /opt/darkmoon/default-workflows

# Installation MCP (EXTRACTION PROPRE de install.sh)
RUN cd ${DM_MCP_HOME}/server \
 && python3 -m venv .venv \
 && . .venv/bin/activate \
 && pip install --upgrade pip \
 && pip install -r requirements.txt

# Entrypoint MCP local
RUN printf '%s\n' \
  '#!/usr/bin/env bash' \
  'set -euo pipefail' \
  'cd /opt/darkmoon/mcp/server' \
  'source .venv/bin/activate' \
  'exec python -m src.server' \
  > /usr/local/bin/darkmoon-mcp \
 && chmod +x /usr/local/bin/darkmoon-mcp

# ------------------------------------------------------------
# Darkmoon CLI (Interactive Monitoring)
# ------------------------------------------------------------

# Install prompt_toolkit inside MCP venv
RUN cd ${DM_MCP_HOME}/server \
 && . .venv/bin/activate \
 && pip install prompt_toolkit

# Expose CLI as system binary
RUN printf '%s\n' \
  '#!/usr/bin/env bash' \
  'cd /opt/darkmoon/mcp/server' \
  'source .venv/bin/activate' \
  'exec python -m src.mcp_monitoring' \
  > /usr/local/bin/darkmoon-cli \
 && chmod +x /usr/local/bin/darkmoon-cli

COPY --from=builder /opencode-bin /usr/local/bin/opencode
RUN chmod +x /usr/local/bin/opencode

ENV TERM=xterm-256color
ENV LANG=C.UTF-8

RUN mkdir -p /root/.local/share/opencode/sessions \
 && mkdir -p /root/.local/share/opencode/reports \
 && cat >> /root/.bashrc <<'EOF'

# ============================
# Darkmoon environment
# ============================

export opencode_PROMPT_DIR="$HOME/.local/share/opencode/sessions"
export opencode_REPORTS_DIR="$HOME/.local/share/opencode/reports"
export PYTHONUNBUFFERED=1

# ============================
# 🔥 Universal PTY wrapper
# ============================

_darkmoon_exec() {
  local BIN="/usr/local/bin/opencode"

  # Resolve -f <file>
  if [[ "$1" == "-f" && -n "$2" ]]; then
    local f="$2"
    if [[ ! -f "$f" && -f "$opencode_PROMPT_DIR/$f" ]]; then
      shift 2
      set -- -f "$opencode_PROMPT_DIR/$f" "$@"
    fi
  fi

  # ============================
  # 🧠 MODE TUI PUR (NE PAS exec)
  # ============================
  if [[ $# -eq 0 ]]; then
    "$BIN"
    return $?
  fi

  # ============================
  # 📄 MODE TEXTE / CLI / LOG
  # ============================
  exec script -q -c "$BIN $*" /dev/null < /dev/tty \
    | sed 's/\bopencode\b/darkmoon/g'
}

darkmoon() {
  _darkmoon_exec "$@"
}

opencode() {
  _darkmoon_exec "$@"
}
EOF


COPY conf/apply-settings.sh /root/conf/apply-settings.sh
RUN sed -i 's/\r$//' /root/conf/apply-settings.sh \
 && chmod +x /root/conf/apply-settings.sh

COPY conf/entrypoint-opencode.sh /entrypoint-opencode.sh
RUN sed -i 's/\r$//' /entrypoint-opencode.sh \
 && chmod +x /entrypoint-opencode.sh

# 🔒 Normalisation LF (CRLF Windows safe)
RUN sed -i 's/\r$//' /root/.bashrc

ENTRYPOINT ["/entrypoint-opencode.sh"]
CMD ["bash"]