mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-04 10:14:47 +08:00
c5d0ef8b4f
Container side: - agent-runner switches to Bun. Drops better-sqlite3 (native compile gone), drops tsc build step in-image AND the tsc-on-every-session-wake in the entrypoint — bun runs src/index.ts directly. bun:sqlite replaces better-sqlite3; cross-mount DB invariants (journal_mode=DELETE, busy_timeout) preserved. Named params converted from @name to $name because bun:sqlite does not auto-strip the prefix the way better-sqlite3 does. - Tests ported from vitest to bun:test (only describe/it/expect/before/afterEach used, API-compatible). vitest.config.ts excludes container/agent-runner/. - bun.lock replaces pnpm-lock.yaml + pnpm-workspace.yaml under container/agent-runner/. Host pnpm workspace does NOT include this tree. Dockerfile improvements (independent of Bun but bundled while touching the file): - tini as PID 1 for correct SIGTERM propagation (prevents half-written outbound.db on shutdown). - Extracted entrypoint.sh — readable and diffable vs the old inline printf. - BuildKit cache mounts for apt + bun install + pnpm install. - --no-install-recommends on apt, pinned CLAUDE_CODE_VERSION, AGENT_BROWSER, VERCEL, BUN_VERSION. - CJK fonts (~200MB) behind ARG INSTALL_CJK_FONTS=false; build.sh reads from .env; setup/container.ts reads the same .env so /setup and manual rebuild stay in sync. - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 in case any postinstall tries to pull a redundant Chromium. - /home/node 755 (was 777). Host side: - src/container-runner.ts dynamic spawn command collapses from `pnpm exec tsc --outDir /tmp/dist … && node /tmp/dist/index.js` to `exec bun run /app/src/index.ts` — cold start ~200-500ms faster per wake. CI: - oven-sh/setup-bun@v2 alongside Node/pnpm. Adds explicit container typecheck (was documented in CLAUDE.md, not enforced) and `bun test` for agent-runner tests.
114 lines
4.3 KiB
Docker
114 lines
4.3 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
# NanoClaw Agent Container
|
|
# Runs Claude Agent SDK in isolated Linux VM with browser automation.
|
|
#
|
|
# Runtime split:
|
|
# - agent-runner (our TypeScript code): Bun
|
|
# - globally-installed Node CLIs (claude-code, agent-browser, vercel): pnpm + Node
|
|
|
|
FROM node:22-slim
|
|
|
|
# ---- Build-time arguments ----------------------------------------------------
|
|
# CJK fonts add ~200MB. Opt in only if you render Chinese/Japanese/Korean text.
|
|
ARG INSTALL_CJK_FONTS=false
|
|
|
|
# Pin CLI versions for reproducibility. Bump deliberately — unpinned installs
|
|
# mean every rebuild silently picks up the latest and can break in lockstep
|
|
# across all users.
|
|
ARG CLAUDE_CODE_VERSION=2.1.112
|
|
ARG AGENT_BROWSER_VERSION=latest
|
|
ARG VERCEL_VERSION=latest
|
|
ARG BUN_VERSION=1.3.12
|
|
|
|
# ---- System dependencies -----------------------------------------------------
|
|
# tini: correct PID 1 / signal forwarding so outbound.db writes finalize on
|
|
# SIGTERM instead of being orphaned by the shell entrypoint.
|
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
|
apt-get update && apt-get install -y --no-install-recommends \
|
|
chromium \
|
|
fonts-liberation \
|
|
fonts-noto-color-emoji \
|
|
libgbm1 \
|
|
libnss3 \
|
|
libatk-bridge2.0-0 \
|
|
libgtk-3-0 \
|
|
libx11-xcb1 \
|
|
libxcomposite1 \
|
|
libxdamage1 \
|
|
libxrandr2 \
|
|
libasound2 \
|
|
libpangocairo-1.0-0 \
|
|
libcups2 \
|
|
libdrm2 \
|
|
libxshmfence1 \
|
|
ca-certificates \
|
|
curl \
|
|
git \
|
|
tini \
|
|
unzip \
|
|
&& if [ "$INSTALL_CJK_FONTS" = "true" ]; then \
|
|
apt-get install -y --no-install-recommends fonts-noto-cjk; \
|
|
fi \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Chromium path for agent-browser / Playwright consumers
|
|
ENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
|
|
# Belt-and-braces: prevent Playwright's postinstall from downloading its own
|
|
# ~300MB Chromium. We've already installed the system one above.
|
|
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
|
|
|
# ---- Bun runtime -------------------------------------------------------------
|
|
# Install via the official script (handles multi-arch detection), then move
|
|
# the binary to /usr/local/bin so the non-root `node` user can execute it.
|
|
RUN curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" && \
|
|
install -m 0755 /root/.bun/bin/bun /usr/local/bin/bun && \
|
|
rm -rf /root/.bun
|
|
|
|
# ---- pnpm + global Node CLIs -------------------------------------------------
|
|
ENV PNPM_HOME="/pnpm"
|
|
ENV PATH="$PNPM_HOME:$PATH"
|
|
RUN corepack enable
|
|
|
|
# agent-browser has a postinstall build script — pnpm skips these by default.
|
|
# Allowlist it via .npmrc so the install doesn't silently produce a broken
|
|
# package. Pinned versions so every rebuild is reproducible.
|
|
RUN --mount=type=cache,target=/root/.cache/pnpm \
|
|
echo "only-built-dependencies[]=agent-browser" > /root/.npmrc && \
|
|
pnpm install -g \
|
|
"@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" \
|
|
"agent-browser@${AGENT_BROWSER_VERSION}" \
|
|
"vercel@${VERCEL_VERSION}"
|
|
|
|
# ---- agent-runner ------------------------------------------------------------
|
|
WORKDIR /app
|
|
|
|
# Copy manifest + lockfile first so the install layer caches independently of
|
|
# source edits.
|
|
COPY agent-runner/package.json agent-runner/bun.lock ./
|
|
|
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
bun install --frozen-lockfile
|
|
|
|
# Source. Bun runs TS directly — no tsc build step. The host remounts this
|
|
# path at runtime via `src/container-runner.ts` so source edits on the host
|
|
# take effect without rebuilding the image; the baked copy is the fallback.
|
|
COPY agent-runner/ ./
|
|
|
|
# ---- Entrypoint --------------------------------------------------------------
|
|
COPY entrypoint.sh /app/entrypoint.sh
|
|
RUN chmod +x /app/entrypoint.sh
|
|
|
|
# ---- Workspace + permissions -------------------------------------------------
|
|
RUN mkdir -p /workspace/group /workspace/global /workspace/extra && \
|
|
chown -R node:node /workspace && \
|
|
chmod 755 /home/node
|
|
|
|
USER node
|
|
WORKDIR /workspace/group
|
|
|
|
# tini is PID 1, reaps zombies, forwards signals cleanly. entrypoint.sh does
|
|
# `exec bun ...` so bun runs as tini's direct child.
|
|
ENTRYPOINT ["/usr/bin/tini", "--", "/app/entrypoint.sh"]
|