diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8f646da --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +.git +.github +.vscode +.idea +node_modules +**/node_modules +dist +**/dist +.scratch +.opencode +forge-data +forge-llm-proxy-logs +forge-opencode-config-local +.venv +**/venv +__pycache__ +**/__pycache__ +*.log +.env +.env.* +!.env.example diff --git a/forge-llm-proxy/.dockerignore b/forge-llm-proxy/.dockerignore new file mode 100644 index 0000000..d0806e6 --- /dev/null +++ b/forge-llm-proxy/.dockerignore @@ -0,0 +1,9 @@ +.git +.github +.vscode +.idea +__pycache__ +**/__pycache__ +.venv +**/venv +*.log diff --git a/forge-server/.dockerignore b/forge-server/.dockerignore new file mode 100644 index 0000000..d0806e6 --- /dev/null +++ b/forge-server/.dockerignore @@ -0,0 +1,9 @@ +.git +.github +.vscode +.idea +__pycache__ +**/__pycache__ +.venv +**/venv +*.log diff --git a/forge-server/forge_server/api/runtime_errors_routes.py b/forge-server/forge_server/api/runtime_errors_routes.py index a72e970..f0c6e51 100644 --- a/forge-server/forge_server/api/runtime_errors_routes.py +++ b/forge-server/forge_server/api/runtime_errors_routes.py @@ -122,7 +122,8 @@ def _normalize_project_id(raw: str) -> str: if _UUID_RE.match(raw): return raw try: - decoded = base64.b64decode(raw, validate=False).decode("utf-8", errors="ignore") + padded = raw + "=" * (-len(raw) % 4) + decoded = base64.b64decode(padded, validate=False).decode("utf-8", errors="ignore") except Exception: # Fall through — the UUID lookup will produce the original 422/500 # surface, which is still better than masking with a 404. diff --git a/forge-ui/Dockerfile b/forge-ui/Dockerfile index bfa2ae6..7d1d0b0 100644 --- a/forge-ui/Dockerfile +++ b/forge-ui/Dockerfile @@ -21,15 +21,11 @@ # - Better default caching headers + gzip out of the box. # ── 1. Builder ─────────────────────────────────────────────────────────────── -FROM oven/bun:1.3.14-alpine AS builder +FROM oven/bun:1.3.14 AS builder # Build deps: forge-ui shares the opencode workspace tree, which pulls tree- # sitter-* and other native modules compiled by node-gyp at install time. -# `make g++` alone is not enough — node-gyp also needs libc-dev, binutils, -# pkgconfig, etc. Alpine's `build-base` meta-package bundles all of them. -# Without this, bun reports "Failed to install N packages" and a cascade of -# FileNotFound errors that are symptoms, not causes. -RUN apk add --no-cache build-base python3 git +RUN apt-get update && apt-get install -y --no-install-recommends build-essential python3 git && rm -rf /var/lib/apt/lists/* WORKDIR /build @@ -45,11 +41,9 @@ COPY opencode/packages ./opencode/packages COPY opencode/patches ./opencode/patches COPY forge-ui/package.json ./forge-ui/ -# Drop packages/desktop — its @forge/ui dep would resolve here (forge-ui is -# in context), but desktop also depends on @lydell/node-pty + Electron native -# bits we don't want in a static UI build. Same reasoning as in -# opencode/Dockerfile.forge. -RUN rm -rf opencode/packages/desktop +# Drop unused workspace packages (desktop, console, storybook, docs, web) so +# bun install only downloads dependencies actually needed for forge-ui. +RUN rm -rf opencode/packages/desktop opencode/packages/console opencode/packages/storybook opencode/packages/docs opencode/packages/web # Strip bunfig.toml's minimumReleaseAge before install. See # opencode/Dockerfile.forge for the full reasoning: the 3-day supply-chain @@ -76,18 +70,30 @@ RUN --mount=type=tmpfs,target=/root/.bun/install/cache \ # Verify what's present so the log gives us a clear before/after for the # packages bun complained about. -RUN cd opencode && for pkg in @ai-sdk/anthropic @smithy/eventstream-codec @shikijs/transformers minimatch; do if [ -d "node_modules/$pkg" ]; then echo "PRESENT $pkg"; else echo "MISSING $pkg"; fi; done +RUN cd opencode && for pkg in @ai-sdk/anthropic @smithy/eventstream-codec @shikijs/transformers minimatch; do \ + if [ -d "node_modules/$pkg" ]; then \ + echo "PRESENT $pkg"; \ + else \ + echo "MISSING $pkg"; \ + fi; \ + done # Now copy forge-ui sources for the actual build step. COPY forge-ui ./forge-ui +# Symlink opencode/node_modules into forge-ui and export bin path so vite and dependencies are found +RUN ln -s /build/opencode/node_modules /build/forge-ui/node_modules +ENV PATH="/build/opencode/node_modules/.bin:${PATH}" + # Vite reads VITE_* from the environment at BUILD time and inlines them into # the static bundle. Pass them as build args so docker compose can override # the dev defaults baked into forge-ui/.env. ARG VITE_API_URL=http://api.forge.localhost ARG VITE_PREVIEW_DOMAIN=preview.lvh.me ARG VITE_OPENCODE_URL=http://opencode:7777 -ENV VITE_API_URL=${VITE_API_URL} VITE_PREVIEW_DOMAIN=${VITE_PREVIEW_DOMAIN} VITE_OPENCODE_URL=${VITE_OPENCODE_URL} +ENV VITE_API_URL=${VITE_API_URL} \ + VITE_PREVIEW_DOMAIN=${VITE_PREVIEW_DOMAIN} \ + VITE_OPENCODE_URL=${VITE_OPENCODE_URL} # Build. Vite reads index.html and ./src/, emits ./dist/. RUN cd forge-ui && bun run build diff --git a/opencode/.dockerignore b/opencode/.dockerignore new file mode 100644 index 0000000..b67445c --- /dev/null +++ b/opencode/.dockerignore @@ -0,0 +1,11 @@ +.git +.github +.vscode +.idea +node_modules +**/node_modules +dist +**/dist +.scratch +.opencode +*.log diff --git a/opencode/Dockerfile.forge b/opencode/Dockerfile.forge index 36fd7f4..24f3206 100644 --- a/opencode/Dockerfile.forge +++ b/opencode/Dockerfile.forge @@ -17,17 +17,18 @@ # that produces a single bundled file and ship that instead — same patch # code, smaller runtime. -FROM oven/bun:1.3.14-alpine +FROM oven/bun:1.3.14 # Match the runtime tooling the upstream Dockerfile assumes plus python3 # (the ui-ux-pro-max skill's reasoning engine needs it for the design- # system generator's scripts/search.py). # -# build-base = gcc + g++ + make + libc-dev + binutils — required because +# build-essential = gcc + g++ + make + libc6-dev — required because # tree-sitter-* packages ship native bindings compiled by node-gyp during -# `bun install`. Without it the install fails with: -# gyp ERR! stack Error: not found: make -RUN apk add --no-cache build-base python3 py3-pip ripgrep libgcc libstdc++ git curl jq +# `bun install`. +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential python3 python3-pip ripgrep git curl jq \ + && rm -rf /var/lib/apt/lists/* WORKDIR /opencode @@ -37,7 +38,7 @@ COPY package.json bun.lock bunfig.toml turbo.json tsconfig.json ./ COPY packages ./packages # patches/ holds bun patchedDependencies referenced in package.json. # bun install reads them by the relative paths in patchedDependencies -# (e.g. patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch); missing files +# (e.g. patches/@silvia-odwyer-photon-node@0.3.4.patch); missing files # fail the install. Copy them in BEFORE bun install. COPY patches ./patches @@ -48,8 +49,7 @@ COPY patches ./patches # (workspace:*) which we don't ship here, so bun install fails resolving # that dep — even after stripping ../forge-ui from the root workspaces. # Strip both before install. Build-time only; source on disk is untouched. -RUN apk add --no-cache jq \ - && jq '.workspaces.packages |= map(select(. != "../forge-ui"))' package.json > package.tmp.json \ +RUN jq '.workspaces.packages |= map(select(. != "../forge-ui"))' package.json > package.tmp.json \ && mv package.tmp.json package.json \ && rm -rf packages/desktop diff --git a/opencode/package.json b/opencode/package.json index cded4ef..3cfefe2 100644 --- a/opencode/package.json +++ b/opencode/package.json @@ -137,10 +137,10 @@ "@types/node": "catalog:" }, "patchedDependencies": { - "@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch", - "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch", - "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", + "@npmcli/agent@4.0.0": "patches/@npmcli-agent@4.0.0.patch", + "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer-photon-node@0.3.4.patch", + "@standard-community/standard-openapi@0.2.9": "patches/@standard-community-standard-openapi@0.2.9.patch", "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", - "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch" + "@ai-sdk/xai@3.0.82": "patches/@ai-sdk-xai@3.0.82.patch" } } diff --git a/opencode/patches/@ai-sdk%2Fxai@3.0.82.patch b/opencode/patches/@ai-sdk-xai@3.0.82.patch similarity index 100% rename from opencode/patches/@ai-sdk%2Fxai@3.0.82.patch rename to opencode/patches/@ai-sdk-xai@3.0.82.patch diff --git a/opencode/patches/@npmcli%2Fagent@4.0.0.patch b/opencode/patches/@npmcli-agent@4.0.0.patch similarity index 100% rename from opencode/patches/@npmcli%2Fagent@4.0.0.patch rename to opencode/patches/@npmcli-agent@4.0.0.patch diff --git a/opencode/patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch b/opencode/patches/@silvia-odwyer-photon-node@0.3.4.patch similarity index 100% rename from opencode/patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch rename to opencode/patches/@silvia-odwyer-photon-node@0.3.4.patch diff --git a/opencode/patches/@standard-community%2Fstandard-openapi@0.2.9.patch b/opencode/patches/@standard-community-standard-openapi@0.2.9.patch similarity index 100% rename from opencode/patches/@standard-community%2Fstandard-openapi@0.2.9.patch rename to opencode/patches/@standard-community-standard-openapi@0.2.9.patch