diff --git a/.env.example b/.env.example index 29ac0184..eab23eb3 100644 --- a/.env.example +++ b/.env.example @@ -81,3 +81,14 @@ FIELD_ENCRYPT_MEK_NAME=lysnr-mek # ── Product Identity ────────────────────────────────────────── DEFAULT_PRODUCT_ID=lysnrai + +# ── Cowork Service (port 4009 — Fastify bridge to Rust runtime) ─ +# cowork-service forwards auth, flags, audit, telemetry, and AI budgets to +# platform-service. The Anthropic key is only needed when running the Rust +# runtime locally via IPC; in the containerised dev stack it is optional. +ANTHROPIC_API_KEY= +RUST_RUNTIME_BIN=cowork-orchestrator +RUST_RUNTIME_TIMEOUT_MS=300000 +OLLAMA_URL=http://localhost:11434/v1 +OLLAMA_MODELS= +FEATURE_FLAGS_ENABLED=true diff --git a/docker-compose.yml b/docker-compose.yml index 9bcb4c88..6aa4bd86 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -215,6 +215,40 @@ services: timeout: 10s retries: 3 + # ── Cowork Service (Fastify bridge to Rust agent runtime) ────── + # Bridges Tauri desktop / clients and cowork-orchestrator, delegating auth, + # flags, audit, telemetry, and AI budgets to platform-service. + cowork-service: + build: + context: . + dockerfile: services/cowork-service/Dockerfile + ports: + - '4009:4009' + env_file: + - .env + environment: + - PORT=4009 + - NODE_ENV=development + - PRODUCT_ID=clawcowork + - COSMOS_ENDPOINT=https://cosmos-emulator:8081 + - PLATFORM_SERVICE_URL=http://platform-service:4003 + - EXTRACTION_SERVICE_URL=http://extraction-service:4005 + depends_on: + cosmos-emulator: + condition: service_healthy + platform-service: + condition: service_healthy + labels: + - 'traefik.enable=true' + - 'traefik.http.routers.cowork.rule=PathPrefix(`/api/cowork`)' + - 'traefik.http.services.cowork.loadbalancer.server.port=4009' + restart: unless-stopped + healthcheck: + test: ['CMD', 'wget', '-q', '--spider', 'http://127.0.0.1:4009/health'] + interval: 10s + timeout: 5s + retries: 10 + # ── Volumes ─────────────────────────────────────────────────────── volumes: azurite-data: diff --git a/services/cowork-service/Dockerfile b/services/cowork-service/Dockerfile new file mode 100644 index 00000000..9932ed0b --- /dev/null +++ b/services/cowork-service/Dockerfile @@ -0,0 +1,36 @@ +# Build context: repo root (docker compose sets context: .) +# +# cowork-service is a lightweight Fastify bridge (no Cosmos containers of its own). +# This Dockerfile mirrors services/mcp-server/Dockerfile but copies the full +# workspace in a single step rather than enumerating every package.json, which +# keeps it resilient to additions/removals of workspace members. +FROM node:22-alpine AS builder +RUN npm config set strict-ssl false \ + && npm install -g pnpm@10 +WORKDIR /app + +# Copy workspace config + lockfile for dependency resolution +COPY package.json pnpm-workspace.yaml pnpm-lock.yaml tsconfig.base.json ./ + +# Copy full workspace sources (dev-compose; not optimised for image size) +COPY packages/ packages/ +COPY services/ services/ +COPY dashboards/ dashboards/ +COPY scripts/ scripts/ + +# Install workspace deps (no frozen lockfile — mirrors the repo's dev install flow) +RUN pnpm install --no-frozen-lockfile + +# Build only cowork-service and its workspace dependencies +RUN pnpm -r --filter @lysnrai/cowork-service... build + +# Deploy to isolated directory (production deps only) +RUN pnpm --filter @lysnrai/cowork-service deploy --legacy /app/deploy + +# ── Production ───────────────────────────────────────────── +FROM node:22-alpine +WORKDIR /app +COPY --from=builder /app/deploy ./ +ENV NODE_ENV=production +EXPOSE 4009 +CMD ["node", "dist/server.js"]