c7dbaf2d9f
Two leftovers from the rebrand, done together because they touch the same docs and manifests. **Data directory.** `agent-dashboard` could not simply be renamed in the source: it names a real directory holding the live SQLite database. Startup now moves it once, via `migrateLegacyDataDir()` in `server/lib/claude-home.js` — a same-filesystem rename, so it is instant even at multiple gigabytes and cannot leave two divergent copies. `getDataDir()` stays PURE and resolves to the legacy path until the move happens; the first version of this put the rename inside the getter, which meant `npm run test:server` relocated the developer's real database as a side effect. The call sits behind `require.main === module` and ahead of the router requires, because those pull in db.js, which opens SQLite at module load. A failed rename is silent and the old directory keeps being used: an unfashionable directory name beats a blank database beside an unreachable one. Same treatment for the port-discovery file (`.agent-dashboard.json` → `.agenthub.json`, old one dropped on write). Not renamed on purpose: the Sagi localStorage keys (renaming silently resets everyone's prefs) and the PWA manifest `id` (changing it orphans an installed app). **MCP server.** 4 tool calls in 46 days across 577,132 events, against 4,556 lines of TypeScript, a 2 MB committed build artifact, and a pre-commit guard that had already blocked commits twice. Deleted: `mcp/`, the maintainer skills and `mcp-reviewer` agent, the build check, `plugins/agenthub/.mcp.json`, `docs/MCP.md`, 12 npm scripts, 5 Makefile targets, and every doc section describing it. Kept, because they are unrelated things sharing the name: the Config Explorer's MCP tab and its API, per-lane Playwright MCP, the agenthub-config plugin's MCP audit, and the historical `mcp__plugin_agenthub_*` events that analytics must keep attributing. Verified: server 1432/1432, client 459/459, tsc clean, prettier clean. Both directions of the migration proven — a sandbox-HOME test run leaves the legacy directory untouched, and a real boot moves it with its contents intact.
68 lines
3.2 KiB
Docker
68 lines
3.2 KiB
Docker
# Multi-stage Dockerfile for AgentHub - a Node.js server with a React client.
|
|
# This setup optimizes the final image size by separating the build and runtime stages.
|
|
# The first stage installs only the production dependencies for the server, while the second stage builds the React client.
|
|
# The final stage combines the necessary files and dependencies to run the application in production.
|
|
# Compatibility: This setup is compatible with both Podman and Docker. Runnable on any platform that supports Node.js and Alpine Linux.
|
|
#
|
|
# Author: Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
|
|
# ── Stage 1: Install server production deps ───────────────────────────
|
|
FROM node:22-alpine AS server-deps
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
# The root `postinstall` hook (scripts/postinstall.js) fires during `npm ci`, so
|
|
# the file must exist here or npm aborts with MODULE_NOT_FOUND before installing
|
|
# anything. It self-skips when client/ is absent (as it is in this stage), so
|
|
# copying just the one script keeps this deps-cache layer from busting on
|
|
# unrelated scripts/ edits. Do NOT use --ignore-scripts: that would also skip
|
|
# better-sqlite3's prebuild fetch and silently drop the native SQLite driver.
|
|
COPY scripts/postinstall.js ./scripts/postinstall.js
|
|
RUN npm ci --omit=dev
|
|
|
|
# ── Stage 2: Build React client ───────────────────────────────────────
|
|
FROM node:22-alpine AS client-build
|
|
WORKDIR /app/client
|
|
COPY client/package.json client/package-lock.json ./
|
|
RUN npm ci
|
|
COPY client/ ./
|
|
# vite.config.ts stamps the UI version from the repo-root package.json (one level
|
|
# up from the client dir). Provide it here so the built client shows the real
|
|
# release version; the config falls back gracefully if it is ever absent.
|
|
COPY package.json /app/package.json
|
|
RUN npm run build
|
|
|
|
# ── Stage 3: Production runtime ───────────────────────────────────────
|
|
FROM node:22-alpine
|
|
WORKDIR /app
|
|
|
|
# Runs Claude Code sessions inside a named tmux session per lane so both the
|
|
# dashboard (via node-pty attach) and a real terminal can share one live pane.
|
|
RUN apk add --no-cache tmux
|
|
|
|
COPY --from=server-deps /app/node_modules ./node_modules/
|
|
COPY package.json ./
|
|
COPY server/ ./server/
|
|
COPY scripts/ ./scripts/
|
|
COPY statusline/ ./statusline/
|
|
COPY --from=client-build /app/client/dist ./client/dist/
|
|
|
|
RUN mkdir -p data
|
|
|
|
EXPOSE 4820
|
|
|
|
ENV NODE_ENV=production
|
|
|
|
# In a container the app MUST bind all interfaces: the server binds loopback by
|
|
# default (GHSA-gr74-4xfh-6jw9), but a container's loopback is a separate
|
|
# namespace the published port cannot reach, so a loopback bind makes the port
|
|
# unreachable. Inside a container the trust boundary is the *host* port publish
|
|
# (keep it on 127.0.0.1 — see docker-compose.yml / INSTALL.md), not this bind.
|
|
ENV DASHBOARD_HOST=0.0.0.0
|
|
|
|
# The recommended ~/.claude bind mount is read-only, so the server cannot write
|
|
# its default data dir (~/.claude/agenthub). Persist to the mounted
|
|
# volume at /app/data instead.
|
|
ENV DASHBOARD_DATA_DIR=/app/data
|
|
|
|
CMD ["node", "server/index.js"]
|