diff --git a/README.md b/README.md index 8090f67..789eead 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,14 @@ You need **Docker Desktop** (macOS / Windows) or **Docker Engine + Compose v2** ```bash git clone https://github.com/Forgeweb-ai/Forgeweb.git cd Forgeweb +echo "FORGE_DATA_ROOT_HOST=$(pwd)/forge-data" > .env # creates the required .env AND pins the host data path docker compose up -d ``` +That one `echo` does two required things. It **creates `.env`** — compose declares `env_file: .env`, so a fresh clone won't start without the file (`Failed to load .env: no such file`). And it **pins `FORGE_DATA_ROOT_HOST`** to the absolute host path of `forge-data`. You need the explicit path: forge-server passes it to the Docker daemon to bind-mount each project's workspace into its preview container, and the daemon resolves that path on the host. The compose fallback (`${PWD}/forge-data`) breaks under `sudo` — `sudo` strips `$PWD`, so it resolves to a blank prefix (`/forge-data`, which doesn't exist on the host) and preview containers hang in `Created`. Capturing `$(pwd)` at install time avoids that whether or not you use `sudo`. + +Everything else has a safe default (`${VAR:-default}` throughout `docker-compose.yml`), so no other config is needed to boot. To customize secrets or domains later, see `.env.example` — but note it ships **production** domains (`app.forge.com`, `preview.forge.com`), so keep those out of a local `.env`. + Then open and sign up. First boot builds 4 images (~10 minutes on a clean machine); subsequent boots are seconds. The stack self-bootstraps: compose creates the `forge-net` network, Postgres comes up healthy, `forge-server`'s entrypoint waits for it, runs `alembic upgrade head`, builds the per-project `forge-runner` image if missing, then starts uvicorn. The default model is opencode zen's free DeepSeek V4 Flash, so a fresh sign-up can chat immediately without any API keys. diff --git a/forge-ui/Dockerfile b/forge-ui/Dockerfile index 49e484a..bfa2ae6 100644 --- a/forge-ui/Dockerfile +++ b/forge-ui/Dockerfile @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 # Forge UI — Vite/SolidJS chat interface. # ========================================== # Build context MUST be the repo root (not ./forge-ui), because forge-ui is a @@ -65,7 +66,13 @@ RUN sed -i '/minimumReleaseAge/d' opencode/bunfig.toml || true # proceed; if any of those packages are actually needed, the build step # below will fail with a clear "Cannot find module" pointing at the real # culprit instead of bun's misleading summary. -RUN cd opencode && bun install --no-save --linker=hoisted || true +# +# tmpfs cache mount: same fix as opencode/Dockerfile.forge — bun's patch-apply +# fails with `EINVAL` on filesystems it flags as "slow/network" (e.g. NAS +# volumes), so we give its install cache a RAM-backed tmpfs. Keeps the build +# filesystem-agnostic on any host. +RUN --mount=type=tmpfs,target=/root/.bun/install/cache \ + cd opencode && bun install --no-save --linker=hoisted || true # Verify what's present so the log gives us a clear before/after for the # packages bun complained about. diff --git a/opencode/Dockerfile.forge b/opencode/Dockerfile.forge index c963c42..36fd7f4 100644 --- a/opencode/Dockerfile.forge +++ b/opencode/Dockerfile.forge @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 # Forge build of the vendored opencode fork # =========================================== # Runs opencode from source under bun (the project's declared package @@ -71,11 +72,21 @@ RUN sed -i '/minimumReleaseAge/d' bunfig.toml || true # /opencode/packages/opencode/node_modules/X and ENOENTs. Isolated places # deps at the per-workspace-member path the runtime actually uses. # -# First pass with `|| true` populates bun's local cache despite the same -# "Failed to install N packages" cascade. Second pass is strict — if it -# still can't materialise the tree we fail the build with bun's own error. -RUN bun install --no-save || true -RUN bun install --no-save +# First pass populates bun's local cache despite the same "Failed to install +# N packages" cascade; the retry is strict — if it still can't materialise the +# tree we fail the build with bun's own error. +# +# tmpfs cache mount (filesystem-agnostic install): bun's install + patch-apply +# IO is sensitive to the underlying filesystem. On some Docker storage backends +# (notably Synology NAS volumes) bun prints "Slow filesystem detected … network +# drive" and then fails patch-apply with `EINVAL: Invalid argument (read())` on +# every patchedDependency. bun's own remediation is to put its install cache on +# a fast local folder — so we mount a RAM-backed tmpfs at the cache path for the +# install step. The build then runs identically on a laptop, a cloud VM, or a +# NAS with no host-side prep. Both passes share the one tmpfs RUN so the strict +# retry reuses the warmed cache. (Needs the documented build RAM headroom.) +RUN --mount=type=tmpfs,target=/root/.bun/install/cache \ + bun install --no-save || bun install --no-save # Bun's isolated linker doesn't fully materialise every transitive dep into # per-workspace-member node_modules — registry deps often end up only at