# syntax=docker/dockerfile:1

# knotless-serve and the web pages it hands on to, in one image, with
# knotless-run, knotless-triage, knotless-agent, knotless-mcp and the knotless CLI: the
# compose file in deploy/ runs it once as each of serve, the pages and, if
# asked, the runner, the triager and the reviewer.
#
#   docker build -t knotless:current .

FROM rust:1-bookworm AS serve
WORKDIR /src
COPY . .
# The cache mounts keep the registry and the build between builds on the
# same machine, so a change rebuilds the crates it touches and not the rest.
# The deploy profile (Cargo.toml) is release's, built for the build's time.
# KNOTLESS_COMMIT, from deploy.sh, is the commit serve and the runner log
# that they run: only their main.rs reads it, so it rebuilds nothing else.
ARG KNOTLESS_COMMIT
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/src/target \
    cargo build --profile deploy --locked \
        -p knotless-serve --bin knotless-serve \
        -p knotless-run --bin knotless-run \
        -p knotless-triage --bin knotless-triage \
        -p knotless-agent --bin knotless-agent \
        -p knotless-mcp --bin knotless-mcp \
        -p knotless --bin knotless \
    && cp target/deploy/knotless-serve target/deploy/knotless-run target/deploy/knotless-triage \
        target/deploy/knotless-agent target/deploy/knotless-mcp target/deploy/knotless /

# The docs, as a Starlight site the pages serve at /docs: docs-site/ reads
# docs/, the lexicons and the pages' tokens from beside it.
FROM node:24-bookworm-slim AS docs
WORKDIR /site/docs-site
COPY docs-site/package.json docs-site/package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY docs-site/ ./
COPY docs/ /site/docs/
COPY lexicons/ /site/lexicons/
COPY web/src/tokens.css /site/web/src/tokens.css
RUN npm run build

FROM node:24-bookworm-slim AS pages
WORKDIR /web
COPY web/package.json web/package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY web/ ./
COPY lexicons/ /lexicons/
# Into static/ before the build: adapter-node serves only the files it
# found there as it built.
COPY --from=docs /site/docs-site/dist static/docs/
RUN npm run build

# adapter-node bundles what the pages import, so the build needs no
# node_modules beside it.
FROM node:24-bookworm-slim
RUN apt-get update \
    && apt-get install -y --no-install-recommends git ca-certificates tini \
    && rm -rf /var/lib/apt/lists/*
# Claude Code, which knotless-claude-review has review pulls for
# knotless-agent, reading them through knotless-mcp.
RUN npm install -g --no-audit --no-fund @anthropic-ai/claude-code@2.1.314 \
    && npm cache clean --force
COPY --from=serve /knotless-serve /knotless-run /knotless-triage /knotless-agent /knotless-mcp \
    /knotless /usr/local/bin/
COPY crates/knotless-agent/claude-review /usr/local/bin/knotless-claude-review
# The docker client, for knotless-run's steps: they run on the host's
# daemon, through its socket.
COPY --from=docker:28-cli /usr/local/bin/docker /usr/local/bin/docker
COPY --from=pages /web/build /app/build
COPY --from=pages /web/package.json /app/package.json
USER node
ENTRYPOINT ["tini", "--"]
CMD ["knotless-serve", "--listen", "0.0.0.0:2590"]
