diff --git a/.cursor/Dockerfile b/.cursor/Dockerfile deleted file mode 100644 index ffe3811..0000000 --- a/.cursor/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:24.04 - -ENV DEBIAN_FRONTEND=noninteractive -ENV PATH="/usr/local/node/bin:${PATH}" -ARG NODE_VERSION=24.15.0 - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates \ - curl \ - git \ - gnupg \ - openssh-client \ - postgresql \ - postgresql-contrib \ - python3 \ - ripgrep \ - sudo \ - tmux \ - xz-utils && \ - rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /usr/local/node && \ - curl --retry 3 --retry-delay 5 -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o "/tmp/node-v${NODE_VERSION}-linux-x64.tar.xz" && \ - curl --retry 3 --retry-delay 5 -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" -o /tmp/SHASUMS256.txt && \ - cd /tmp && grep " node-v${NODE_VERSION}-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c - && \ - tar -xJf "/tmp/node-v${NODE_VERSION}-linux-x64.tar.xz" -C /usr/local/node --strip-components=1 && \ - rm "/tmp/node-v${NODE_VERSION}-linux-x64.tar.xz" /tmp/SHASUMS256.txt && \ - corepack enable && \ - corepack prepare pnpm@10.32.1 --activate && \ - ln -sf /usr/local/node/bin/node /usr/local/bin/node && \ - ln -sf /usr/local/node/bin/corepack /usr/local/bin/corepack && \ - ln -sf /usr/local/node/bin/npm /usr/local/bin/npm && \ - ln -sf /usr/local/node/bin/npx /usr/local/bin/npx && \ - ln -sf /usr/local/node/bin/pnpm /usr/local/bin/pnpm && \ - ln -sf /usr/local/node/bin/pnpx /usr/local/bin/pnpx - -RUN useradd -m -s /bin/bash cursor && \ - usermod -aG sudo cursor && \ - echo "cursor ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/cursor && \ - chmod 0440 /etc/sudoers.d/cursor diff --git a/.cursor/environment.json b/.cursor/environment.json deleted file mode 100644 index 91ec59d..0000000 --- a/.cursor/environment.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://www.cursor.com/schemas/environment.schema.json", - "name": "chloei-cloud-agent", - "user": "cursor", - "build": { - "dockerfile": "Dockerfile", - "context": ".." - }, - "install": "bash .cursor/setup.sh", - "start": "sudo service postgresql start" -} diff --git a/.cursor/setup.sh b/.cursor/setup.sh deleted file mode 100644 index 86c111c..0000000 --- a/.cursor/setup.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -export PATH="/usr/local/node/bin:${PATH}" - -run_as_postgres() { - sudo -u postgres "$@" -} - -read_env_var() { - local key="$1" - - if [[ ! -f .env.local ]]; then - return - fi - - python3 - "$key" <<'PY' -from pathlib import Path -import shlex -import sys - -key = sys.argv[1] -for line in Path(".env.local").read_text().splitlines(): - if line.startswith(f"{key}="): - raw_value = line.split("=", 1)[1] - parsed = shlex.split(f"value={raw_value}", comments=False, posix=True) - value = parsed[0].split("=", 1)[1] if parsed else raw_value - print(value) - break -PY -} - -EXISTING_DATABASE_URL="$(read_env_var "DATABASE_URL")" -EXISTING_BETTER_AUTH_URL="$(read_env_var "BETTER_AUTH_URL")" -EXISTING_BETTER_AUTH_SECRET="$(read_env_var "BETTER_AUTH_SECRET")" - -DATABASE_URL_VALUE="${DATABASE_URL:-${EXISTING_DATABASE_URL:-postgresql://chloei:chloei_dev@localhost:5432/chloei}}" -BETTER_AUTH_URL_VALUE="${BETTER_AUTH_URL:-${EXISTING_BETTER_AUTH_URL:-http://localhost:3000}}" -BETTER_AUTH_SECRET_VALUE="${BETTER_AUTH_SECRET:-${EXISTING_BETTER_AUTH_SECRET:-$(node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))")}}" - -ensure_env_var() { - local key="$1" - local value="$2" - - if [[ -z "${value}" ]]; then - return - fi - - touch .env.local - - python3 - "$key" "$value" <<'PY' -from pathlib import Path -import shlex -import sys - -key = sys.argv[1] -value = sys.argv[2] -path = Path(".env.local") -lines = path.read_text().splitlines() -env_line = f"{key}={shlex.quote(value)}" - -updated_existing = False -updated = [] -for line in lines: - if line.startswith(f"{key}="): - updated.append(env_line) - updated_existing = True - else: - updated.append(line) - -if not updated_existing: - updated.append(env_line) - -path.write_text("\n".join(updated) + "\n") -PY -} - -ensure_env_var "DATABASE_URL" "${DATABASE_URL_VALUE}" -ensure_env_var "BETTER_AUTH_URL" "${BETTER_AUTH_URL_VALUE}" -ensure_env_var "BETTER_AUTH_SECRET" "${BETTER_AUTH_SECRET_VALUE}" - -for key in AI_GATEWAY_API_KEY TAVILY_API_KEY SEC_API_USER_AGENT; do - if [[ -n "${!key:-}" ]]; then - ensure_env_var "${key}" "${!key}" - fi -done - -sudo service postgresql start - -for attempt in {1..30}; do - if run_as_postgres pg_isready -q; then - break - fi - - if [[ "${attempt}" -eq 30 ]]; then - echo "PostgreSQL did not become ready in time." >&2 - exit 1 - fi - - sleep 1 -done - -run_as_postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='chloei'" | rg -q 1 || \ - run_as_postgres psql -c "CREATE ROLE chloei WITH LOGIN PASSWORD 'chloei_dev';" - -run_as_postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='chloei'" | rg -q 1 || \ - run_as_postgres createdb -O chloei chloei - -pnpm --version -pnpm install --frozen-lockfile -pnpm exec playwright install --with-deps chromium - -export DATABASE_URL="${DATABASE_URL_VALUE}" -export BETTER_AUTH_URL="${BETTER_AUTH_URL_VALUE}" -export BETTER_AUTH_SECRET="${BETTER_AUTH_SECRET_VALUE}" -pnpm migrate diff --git a/.gitignore b/.gitignore index 940dc1d..778db18 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,3 @@ npm-debug.log* # Claude local session state .claude/scheduled_tasks.lock .claude/settings.local.json - -# Codex local skills -.agents/ -skills-lock.json diff --git a/.prettierignore b/.prettierignore index 5a98edc..87e6029 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,6 +6,5 @@ coverage/ test-results/ pnpm-lock.yaml .pnpm-store/ -.agents/ __pycache__/ .venv/ diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index c82bb3e..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,62 +0,0 @@ -# AGENTS.md - -Instructions for coding agents (Cursor, Codex, Claude Code, etc.) working in this repo. - -- **Architecture & conventions:** see [CLAUDE.md](CLAUDE.md) — the request flow, agent runtime, tools, storage/auth model, code conventions, and the full environment-variable reference live there. Read it before making changes. -- **Generic local setup:** see [README.md](README.md). -- **This file** covers the Cursor Cloud environment and the build/test commands and gotchas an agent needs to run the project. - -Chloei is a Next.js 16 / React 19 chat app on the Vercel AI Gateway, with PostgreSQL-backed auth, threads, and rate limiting. Validate changes with `pnpm lint` (zero warnings), `pnpm typecheck`, and `pnpm test` before finishing. - -## Cursor Cloud-specific instructions - -### Services - -| Service | How to start | Notes | -| ------------------ | ------------------------------- | ----------------------------------------------------------------------------------------------------- | -| PostgreSQL | `sudo service postgresql start` | Native PostgreSQL 16 is provisioned by `.cursor/setup.sh`; must be running before dev server/migrate | -| Next.js dev server | `pnpm dev` | Runs on port 3000; requires `.env.local` with `DATABASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL` | - -The Cursor Cloud image runs `.cursor/setup.sh` during installation and `.cursor/environment.json` starts PostgreSQL. The setup script installs dependencies, creates the `chloei` database/user when needed, writes local auth/database defaults, copies configured Cloud Agent secrets into `.env.local`, installs Playwright Chromium dependencies, and runs `pnpm migrate`. - -### Environment - -- `.env.local` must contain at minimum: `DATABASE_URL=postgresql://chloei:chloei_dev@127.0.0.1:5432/chloei`, `BETTER_AUTH_SECRET=`, `BETTER_AUTH_URL=http://localhost:3000`. -- `AI_GATEWAY_API_KEY` and `TAVILY_API_KEY` are configured as Cloud Agent secrets when available and should be written into `.env.local` before starting the dev server so Next.js picks them up. -- Without `AI_GATEWAY_API_KEY` the app starts and auth works, but `/api/models` returns an empty list and `/api/agent` cannot stream responses. -- Run `pnpm migrate` after provisioning the database and before the first request. - -### Vercel CLI - -- Run `vercel login` in a terminal and approve the device-login URL in your browser before using Vercel CLI commands in Cursor Cloud. -- This repo links to the Chloei Labs `chloei` Vercel project through `.vercel/project.json`. -- Use `vercel env pull .env.local --yes` to refresh Development env vars after login. Re-apply any local-only overrides afterward if you intentionally differ from Vercel Development. - -### Docker daemon - -Docker is optional for this repo because Cursor Cloud uses native PostgreSQL. If you need Docker in this VM, start it with flags that avoid restricted bridge/overlay features: - -```bash -sudo sh -c 'dockerd --data-root=/var/lib/docker-vfs --storage-driver=vfs --iptables=false --bridge=none > /var/log/dockerd.log 2>&1' -``` - -Use `--network host` for local service containers. New terminals should have Docker group access; older terminals may need `sg docker -c 'docker ...'`. - -### Commands reference - -Standard commands are documented in `CLAUDE.md` and `README.md`. Key ones: - -- **Lint**: `pnpm lint` (zero warnings enforced) -- **Typecheck**: `pnpm typecheck` -- **Unit tests**: `pnpm test` (no external services needed) -- **Smoke tests**: `pnpm test:smoke:mock:build` (builds the production app, then runs the mocked smoke test) -- **Dev server**: `pnpm dev` - -### Gotchas - -- The mock Playwright smoke test (`pnpm test:smoke:mock`) uses the production Next.js server, so run `pnpm build` first or use `pnpm test:smoke:mock:build`. -- Unit tests use stubs and run without a database. No external services are needed for `pnpm test`. -- The `pnpm.onlyBuiltDependencies` field in `package.json` already handles build script approval for `sharp`; do not run `pnpm approve-builds`. -- Node.js 24.x is required (pinned in `engines`). The VM needs `/usr/local/node/bin` on `PATH`. -- Prefer the native PostgreSQL service in Cursor Cloud. If you intentionally use Docker for PostgreSQL, run it with host networking because Docker bridge networking is disabled in the compatible daemon mode. -- After signing up a user via `/api/auth/sign-up/email`, the session cookie is automatically set; no separate sign-in step is needed. diff --git a/CLAUDE.md b/CLAUDE.md index 4c54afd..131023e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,9 +38,9 @@ node --test tests/agent-route-contract.test.mjs # Single test file ESLint runs with `--max-warnings=0`, so any warning fails the build. CI also enforces `pnpm format:check`. Run `pnpm lint && pnpm format:check && pnpm typecheck` before committing. -## Local / Cursor Cloud setup +## Local / Claude Code setup -`README.md` covers generic local setup. Cursor Cloud-specific setup lives in `AGENTS.md`, `.cursor/setup.sh`, `.cursor/environment.json`, and `.cursor/Dockerfile`; Cloud agents use native PostgreSQL 16 by default, not Docker. The Claude Code SessionStart hook (`.claude/hooks/session-start.sh`, wired by `.claude/settings.json`) provisions the local database, runs migrations, and installs Playwright Chromium so web sessions can build and test immediately. +`README.md` covers generic local setup. The Claude Code SessionStart hook (`.claude/hooks/session-start.sh`, wired by `.claude/settings.json`) provisions the local database, runs migrations, and installs Playwright Chromium so web sessions can build and test immediately. For Vercel-backed local envs, run `vercel login`, approve the device-login URL, confirm `.vercel/project.json` links to the Chloei Labs `chloei` project, then `vercel env pull .env.local --yes`. diff --git a/README.md b/README.md index 7d09d30..3452468 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Chloei is a Next.js 16 chat app backed by Vercel AI Gateway. It currently expose ## Documentation - **[CLAUDE.md](CLAUDE.md)** — architecture reference and conventions (request flow, agent runtime, tools, storage, auth, env vars). The best starting point for understanding the codebase; also read by Claude Code. -- **[AGENTS.md](AGENTS.md)** — environment setup for coding agents (Cursor Cloud specifics, build/test commands, gotchas). - **[docs/vercel-production-launch-readiness.md](docs/vercel-production-launch-readiness.md)** — production launch checklist (security, reliability, performance, rollback). - **[docs/managed-integrations-rollout.md](docs/managed-integrations-rollout.md)** — managed-integration rollout/rollback runbook (Neon, feature flags). @@ -21,7 +20,7 @@ Chloei is a Next.js 16 chat app backed by Vercel AI Gateway. It currently expose pnpm install cp .env.example .env.local # Fill DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL, and AI_GATEWAY_API_KEY. -# Cursor Cloud sets up native PostgreSQL; local machines must start PostgreSQL first. +# Start PostgreSQL locally before running migrate. pnpm migrate pnpm dev ``` diff --git a/scripts/vercel-ignore-build.mjs b/scripts/vercel-ignore-build.mjs index 07ab39a..b9e1e19 100644 --- a/scripts/vercel-ignore-build.mjs +++ b/scripts/vercel-ignore-build.mjs @@ -2,17 +2,10 @@ import { execFileSync } from "node:child_process" -const explicitSkipFiles = new Set([ - "README.md", - "AGENTS.md", - "CLAUDE.md", - "skills-lock.json", -]) +const explicitSkipFiles = new Set(["README.md", "CLAUDE.md"]) const skipPrefixes = [ - ".agents/", ".claude/", - ".cursor/", ".github/", "dist/", "docs/",