feat(mcpd+deploy): serve web UI at /ui + smoke tests + docs (Stage 6)
Some checks failed
CI/CD / lint (pull_request) Successful in 54s
CI/CD / test (pull_request) Failing after 1m8s
CI/CD / typecheck (pull_request) Successful in 2m35s
CI/CD / smoke (pull_request) Has been skipped
CI/CD / build (pull_request) Has been skipped
CI/CD / publish (pull_request) Has been skipped

The closing stage. mcpd now hosts the Stage 5 SPA, the Docker image
bundles the build artifact, a smoke test exercises the personality
HTTP surface end-to-end, and the user-facing docs spell out the
mental model.

mcpd:
- Add @fastify/static dep.
- New routes/web-ui.ts: registers /ui/* against a static bundle. Looks
  for the bundle at $MCPD_WEB_ROOT, then /usr/share/mcpd/web (the
  Docker image path), then a dev-tree fallback. Logs and skips
  cleanly if missing — API-only deploys keep working.
- SPA fallback: any /ui/<path> that doesn't match a file falls through
  to index.html so direct hits to react-router URLs work.
- /ui/* falls through to `kind: skip` in mapUrlToPermission, so the
  static assets are served unauthenticated. Each API call from the
  SPA still carries the bearer token.

Deploy:
- Dockerfile.mcpd builds the @mcpctl/web bundle in the same builder
  stage and copies dist/ to /usr/share/mcpd/web in the runtime image.

Smoke (personality.smoke.test.ts):
- Live mcpd flow: create secret/llm/agent/personality, attach an
  agent-direct prompt, verify the binding listing, reject double-
  attach (409) + foreign-agent prompt (400), set defaultPersonality
  by name, detach + delete cleanup.

Docs:
- New docs/personalities.md: VLAN-on-ethernet model, system-block
  ordering table, three prompt scopes, CLI walkthrough, web UI
  walkthrough, full API surface, RBAC notes.
- agents.md and chat.md cross-link.
- README's Agents section gains a Personalities subsection.

Test count after Stage 6:
  mcpd:   801/801      cli:  430/430
  web:    7/7          db:   58/62 (4 pre-existing)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michal
2026-04-26 19:48:43 +01:00
parent 0010cc18b7
commit 4cbf58d212
10 changed files with 665 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
COPY src/mcpd/package.json src/mcpd/tsconfig.json src/mcpd/
COPY src/db/package.json src/db/tsconfig.json src/db/
COPY src/shared/package.json src/shared/tsconfig.json src/shared/
COPY src/web/package.json src/web/tsconfig.json src/web/
# Install all dependencies
RUN pnpm install --frozen-lockfile
@@ -19,10 +20,13 @@ COPY src/mcpd/src/ src/mcpd/src/
COPY src/db/src/ src/db/src/
COPY src/db/prisma/ src/db/prisma/
COPY src/shared/src/ src/shared/src/
COPY src/web/src/ src/web/src/
COPY src/web/index.html src/web/vite.config.ts src/web/
# Generate Prisma client and build TypeScript
# Generate Prisma client and build TypeScript + web SPA
RUN pnpm -F @mcpctl/db db:generate
RUN pnpm -F @mcpctl/shared build && pnpm -F @mcpctl/db build && pnpm -F @mcpctl/mcpd build
RUN pnpm -F @mcpctl/web build
# Stage 2: Production runtime
FROM node:20-alpine
@@ -50,6 +54,10 @@ COPY --from=builder /app/src/shared/dist/ src/shared/dist/
COPY --from=builder /app/src/db/dist/ src/db/dist/
COPY --from=builder /app/src/mcpd/dist/ src/mcpd/dist/
# Copy the web SPA bundle. registerWebUi() looks for it at this path
# (or wherever MCPD_WEB_ROOT is set).
COPY --from=builder /app/src/web/dist/ /usr/share/mcpd/web/
# Copy templates for seeding
COPY templates/ templates/