diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 0000000..c114dbb --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,17 @@ +{ + "name": "rapbattle", + "install": "bash .cursor/install.sh", + "terminals": [ + { + "name": "wrangler dev", + "command": "npx wrangler dev --local --ip 0.0.0.0 --port 8787", + "description": "Local Cloudflare Worker (miniflare) serving the arena UI + MCP endpoint on http://localhost:8787. --local keeps D1/R2/KV/DO in-process; the Workers AI (TTS) binding is disabled locally, so /speak audio routes need a real CLOUDFLARE_API_TOKEN and are the only feature not available offline." + } + ], + "ports": [ + { + "name": "wrangler dev", + "port": 8787 + } + ] +} diff --git a/.cursor/install.sh b/.cursor/install.sh new file mode 100755 index 0000000..4b5faf1 --- /dev/null +++ b/.cursor/install.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Idempotent bootstrap for the rapbattle Cloudflare Worker dev environment. +set -euo pipefail +cd "$(dirname "$0")/.." + +# Exact, lockfile-pinned dependencies (mirrors the typecheck CI workflow). +npm ci + +# The Worker's ensureSchema() (src/beats.ts) only ALTERs the base tables and +# creates the auxiliary ones at runtime; the base tables themselves come from +# src/db/schema.sql. Seed them into the local (miniflare) D1 that +# `wrangler dev --local` uses so the arena has real tables on first boot. +# CREATE TABLE IF NOT EXISTS keeps this safe to re-run. +npx wrangler d1 execute rapbattle --local --file=./src/db/schema.sql + +# Local-only secret that unlocks the /admin/* seed + repair routes +# (see src/admin.ts). It never touches production: .dev.vars is git-ignored and +# only read by `wrangler dev`. Without it the app still runs; you just can't use +# the one-shot arena seeder. +if [ ! -f .dev.vars ]; then + cat > .dev.vars <<'EOF' +# Local development secrets for `wrangler dev` only. Git-ignored, non-production. +ADMIN_SECRET="local-dev-secret" +EOF +fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..63d80fc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +# AGENTS.md + +rapbattle is a single Cloudflare Worker (`src/index.ts`) serving the arena UI + an OAuth-gated MCP endpoint, backed by D1, R2, KV, Workers AI (TTS), and a bound-but-unused Durable Object. + +## Cursor Cloud specific instructions + +The Cloud Agent environment is repository-managed via `.cursor/environment.json`. + +### Install + +`install` runs `.cursor/install.sh`, which: + +- runs `npm ci` (lockfile-pinned; matches the typecheck CI), +- applies `src/db/schema.sql` to the local (miniflare) D1 so the base tables exist — the Worker's `ensureSchema()` in `src/beats.ts` only ALTERs those tables and creates the auxiliary ones at runtime, +- writes a git-ignored `.dev.vars` with a local `ADMIN_SECRET` (`local-dev-secret`) so the `/admin/*` seed routes work offline. + +To bootstrap manually: `bash .cursor/install.sh` (idempotent). + +### Dev server + +`npx wrangler dev --local --ip 0.0.0.0 --port 8787` + +This runs as the `wrangler dev` terminal and serves the app on http://localhost:8787. + +**Why `--local` is required:** the remote Workers AI binding (`env.AI`) makes `wrangler dev` open a remote proxy that demands a `CLOUDFLARE_API_TOKEN`, which fails in a non-interactive environment. `--local` disables remote bindings so dev works fully offline (D1/R2/KV/DO are emulated in-process). The only feature unavailable locally is `/speak` TTS audio, since Workers AI has no local emulator. + +### Seed + confirm it works + +Seed the arena (needs the local `ADMIN_SECRET` from `.dev.vars`): + +``` +curl -s -X POST "http://127.0.0.1:8787/admin/seed-rift?secret=local-dev-secret" +``` + +Then confirm: + +- `GET /health` → `{"status":"live",...}` +- `GET /` → arena home renders +- `GET /battle/battle-001` → seeded verse renders (contains "Rift") +- `GET /leaderboard` → Rift on the board +- `GET /stage` → Rift's intro + stage call + +### CI check + +`npm run typecheck` (`tsc --noEmit`) — this is the check run by `.github/workflows/typecheck.yml`.