Repository navigation
Expand file tree
/
Copy pathDockerfile.api
More file actions
163 lines (158 loc) · 7.35 KB
/
Copy pathDockerfile.api
File metadata and controls
163 lines (158 loc) · 7.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
FROM mirror.gcr.io/library/node:22-bookworm-slim AS base
RUN corepack enable
WORKDIR /app
# --- dependency stage ---
# node-pty (used by the in-app CLI OAuth login modal) ships native bindings
# without prebuilt Linux binaries on most channels, so we install build tools
# here so `pnpm install` can compile it from source.
FROM base AS deps
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
python3 \
&& rm -rf /var/lib/apt/lists/*
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
COPY packages/db/package.json packages/db/
COPY packages/domain/package.json packages/domain/
COPY packages/agent/package.json packages/agent/
COPY packages/ai/package.json packages/ai/
COPY packages/ingestion/package.json packages/ingestion/
COPY packages/integrations/package.json packages/integrations/
COPY packages/vector/package.json packages/vector/
COPY packages/mcp-server/package.json packages/mcp-server/
COPY packages/vision/package.json packages/vision/
COPY apps/api/package.json apps/api/
COPY apps/worker/package.json apps/worker/
# Vendored AppKit tarballs. Some @braedonsaunders/appkit-* packages are not
# published yet, so package.json resolves them from here; the install fails
# without this copy.
RUN pnpm install --frozen-lockfile
# pnpm 10's approve-builds policy denies node-pty's `install` script
# (the one that runs `node-gyp rebuild`). node-pty ships prebuilds for
# darwin/win32 but NOT linux-x64, so the linux runtime needs that
# rebuild or the api crashes with "Failed to load native module:
# pty.node" at first require.
#
# We bypass pnpm by running node-gyp directly in the node-pty package
# dir. Installing node-gyp globally avoids the `.bin` discovery dance
# that pnpm's symlink layout makes awkward inside a package subdir.
# The trailing `test -f` makes a silent build failure fail the image
# build instead of crashing the api in prod.
RUN npm install -g node-gyp@^11
RUN set -eux \
&& PTY_DIR=$(find /app/node_modules -maxdepth 6 -type d -name "node-pty" 2>/dev/null | head -1) \
&& test -n "$PTY_DIR" \
&& cd "$PTY_DIR" \
&& node-gyp rebuild \
&& test -f build/Release/pty.node
# --- build stage ---
FROM base AS builder
COPY --from=deps /app ./
COPY . .
RUN pnpm --filter @bidwright/db db:generate
# Build workspace packages — their main now points at dist/index.js for
# Node ESM resolution. Without this build, seed scripts (db-migrate
# container) that import @bidwright/domain fail with "Cannot find
# package .../dist/index.js".
RUN pnpm -r --filter "./packages/*" build
RUN pnpm --filter @bidwright/api build
# Runtime images copy dependencies separately from app source so normal
# source edits do not force prod to pull a fresh node_modules-sized layer.
FROM builder AS app
RUN rm -rf node_modules apps/*/node_modules packages/*/node_modules
# --- LibreDWG builder stage ---
FROM mirror.gcr.io/library/debian:bookworm-slim AS libredwg-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
pkg-config \
python3 \
wget \
texinfo \
xz-utils \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN wget -q -O /tmp/libredwg.tar.gz "https://github.com/LibreDWG/libredwg/releases/download/0.13.4/libredwg-0.13.4.tar.gz" \
&& mkdir -p /tmp/libredwg-src \
&& tar xzf /tmp/libredwg.tar.gz -C /tmp/libredwg-src --strip-components=1 \
&& cd /tmp/libredwg-src \
&& ./configure --disable-bindings --disable-shared \
&& make -j"$(nproc)" \
&& make install \
&& rm -rf /tmp/libredwg.tar.gz /tmp/libredwg-src
# --- runtime stage ---
FROM mirror.gcr.io/library/node:22-bookworm-slim AS runner
RUN corepack enable
# bubblewrap is the per-tenant CLI sandbox primitive used by
# BubblewrappedHost whenever BIDWRIGHT_MODE=server.
# The Debian package installs /usr/bin/bwrap setuid-root by default. Production
# uses AppKit's launcherIdentity to invoke bubblewrap as an unprivileged UID;
# AppKit drops capabilities before the agent command starts. Re-assert the
# setuid bit defensively in case a future Debian build changes the default.
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
python3-venv \
python3-pip \
openjdk-17-jdk-headless \
poppler-utils \
tesseract-ocr \
libgl1 \
libglib2.0-0 \
libgomp1 \
git \
wget \
unzip \
ripgrep \
bubblewrap \
util-linux \
&& rm -rf /var/lib/apt/lists/* \
&& chmod u+s /usr/bin/bwrap \
&& /usr/bin/bwrap --version
COPY --from=libredwg-builder /usr/local/bin/dwg2dxf /usr/local/bin/dwg2dxf
COPY --from=libredwg-builder /usr/local/bin/dwgread /usr/local/bin/dwgread
RUN dwg2dxf --version && dwgread --version
RUN wget -q -O /tmp/mpxj.zip "https://downloads.sourceforge.net/project/mpxj/mpxj/Version%2016.1.0/mpxj-16.1.0.zip" \
&& mkdir -p /opt/mpxj-dist /opt/mpxj \
&& unzip -q /tmp/mpxj.zip -d /opt/mpxj-dist \
&& find /opt/mpxj-dist -mindepth 1 -maxdepth 1 -type d -exec cp -R {}/. /opt/mpxj/ \; \
&& rm -rf /tmp/mpxj.zip /opt/mpxj-dist
ENV VIRTUAL_ENV=/opt/vision-venv
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
ENV PYTHON_PATH="${VIRTUAL_ENV}/bin/python"
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
COPY packages/vision/python/requirements.txt /tmp/vision-requirements.txt
RUN python3 -m venv "${VIRTUAL_ENV}" \
&& "${VIRTUAL_ENV}/bin/pip" install --no-cache-dir --upgrade pip setuptools wheel \
&& "${VIRTUAL_ENV}/bin/pip" install --no-cache-dir -r /tmp/vision-requirements.txt
# Independent CAD environment: keep the manufacturing kernel version pinned
# without coupling it to OCR/vision Python dependencies.
COPY apps/api/src/services/build123d/requirements.txt /tmp/cad-requirements.txt
RUN python3 -m venv /opt/cad-venv \
&& /opt/cad-venv/bin/pip install --no-cache-dir -r /tmp/cad-requirements.txt \
&& /opt/cad-venv/bin/python -c "import build123d; assert build123d.__version__ == '0.13.0'"
ENV BIDWRIGHT_CAD_PYTHON=/opt/cad-venv/bin/python
# Codex App Server is still delivered by the Codex binary. Claude runs through
# the supported Agent SDK dependency bundled with the API instead of a global
# interactive Claude Code install.
# The agent sandbox points /proc/self/exe at /usr/local/bin/codex, so Codex
# looks for its helper binaries (codex-code-mode-host, ...) next to that path.
# Without the links, GPT models fail to route tools before any MCP call.
# Pinned: npm publishes the platform binaries as separate optional packages,
# sometimes minutes after the launcher. An unpinned install during that gap
# (0.161.0 on 2026-10-07) silently skips the linux binary.
ARG CODEX_VERSION=0.160.1
RUN npm install -g "@openai/codex@${CODEX_VERSION}" \
&& CODEX_VENDOR_BIN="$(dirname "$(find "$(npm root -g)/@openai/codex/node_modules/@openai" -path '*/vendor/*/bin/codex' -type f | head -1)")" \
&& test -x "${CODEX_VENDOR_BIN}/codex-code-mode-host" \
&& for helper in "${CODEX_VENDOR_BIN}"/*; do \
name="$(basename "${helper}")"; \
[ "${name}" = "codex" ] || ln -sf "${helper}" "/usr/local/bin/${name}"; \
done
RUN npm install -g playwright@1.58.2 \
&& playwright install --with-deps chromium \
&& npm uninstall -g playwright \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=deps /app ./
COPY --from=app /app ./
RUN javac -cp "/opt/mpxj/*:/opt/mpxj/lib/*" apps/api/src/services/schedule-import/mpxj-bridge/BidwrightMpxjJson.java
EXPOSE 3001
CMD ["pnpm", "--filter", "@bidwright/api", "exec", "tsx", "src/index.ts"]