diff --git a/AGENTS.md b/AGENTS.md index ef9d617..c3930b7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,3 +9,37 @@ Project guidelines: - every svelte component should have `lang="ts"` - when making changes in effect, use the effect generator syntax whenever possible. if you need to call an async function use `Effect.tryPromise`. helper functions should be generators, the backend should be composed of effects - after changes, format, lint, and check the package/app you touched + +## Cursor Cloud specific instructions + +### Repository overview + +Turborepo monorepo (`bun` workspaces). Primary product is a YouTube/X channel monitoring platform. + +| Area | Path | Purpose | +|------|------|---------| +| Dashboard | `apps/dashboard` | SvelteKit 5 + Tailwind v4 web app (main UI) | +| Web | `apps/web` | Minimal SvelteKit app (placeholder) | +| Live Crawler | `apps/live-crawler` | Background polling service for YouTube data | +| Core | `packages/core` | Shared env loading and Effect helpers | +| DB | `packages/db` | Drizzle ORM schema + database layer (PostgreSQL) | +| Crawl Helpers | `packages/crawl-helpers` | Crawl orchestration logic | +| youtube-read, x-read, notion-read, gmail-read, slack-read | `packages/*-read` | API integration libraries/tests | + +### Key commands (run from repo root) + +- `bun install` — install all workspace dependencies +- `bun run format:check` / `bun run format` — prettier check/fix +- `bun run check` — turbo type-check across all packages +- `bun run dev:dash` — start dashboard dev server (Vite, port 5173) +- `bun run db:start` — start PostgreSQL 17 via Docker +- `bun run db:push` — push Drizzle schema (use `--force` to skip interactive prompt in CI/non-TTY) +- `bun run db:studio` — open Drizzle Studio + +### Non-obvious caveats + +- **Docker required**: PostgreSQL runs in Docker (`postgres:17`). The `db:start` script manages the container. In Cloud Agent VMs, Docker must be installed with `fuse-overlayfs` storage driver and `iptables-legacy`. After installing, run `sudo chmod 666 /var/run/docker.sock` so the non-root user can access Docker. +- **Non-TTY drizzle-kit push**: `bun run db:push` requires interactive confirmation. Pass `--force` flag: `bunx drizzle-kit push --config=packages/db/drizzle.config.ts --force`. +- **`.env` file**: Copy `.env.example` to `.env` at the repo root. The default `DATABASE_URL` points to the local Docker Postgres. API keys (YouTube, X, Notion, Slack, Gmail) are only needed for their respective crawl packages. +- **Pre-existing type errors in `crawl-helpers`**: `bun run check` fails for `@ns-sentinel/crawl-helpers` due to drizzle-orm type mismatches. This is a known pre-existing issue on `main` and is unrelated to your changes. +- **Dashboard depends on `drizzle-orm`**: The dashboard directly imports `drizzle-orm` in `src/lib/server/dashboard.ts`. It must be listed in the dashboard's `package.json` dependencies for Vite SSR resolution to work. diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 0311999..d128c94 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -15,6 +15,7 @@ "@sveltejs/vite-plugin-svelte": "^7.0.0", "@tailwindcss/vite": "^4.2.2", "@types/node": "^25.5.0", + "drizzle-orm": "^0.45.2", "effect": "4.0.0-beta.41", "svelte": "^5.55.0", "svelte-check": "^4.4.5", diff --git a/bun.lock b/bun.lock index d447750..5edc432 100644 --- a/bun.lock +++ b/bun.lock @@ -24,6 +24,7 @@ "@sveltejs/vite-plugin-svelte": "^7.0.0", "@tailwindcss/vite": "^4.2.2", "@types/node": "^25.5.0", + "drizzle-orm": "^0.45.2", "effect": "4.0.0-beta.41", "svelte": "^5.55.0", "svelte-check": "^4.4.5", @@ -811,6 +812,8 @@ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "@ns-sentinel/db/drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw=="], @@ -823,6 +826,8 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "dashboard/drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], + "dashboard/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], "gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],