packages/server/— Next.js 16 app (pnpm). Has its own git repo andAGENTS.md.packages/cli/— Bun CLI (@diff4/cli). Commander.js, builds to standalone binaries viabun build.skills/diff4/— OpenCode skill definition for the CLI.docker-compose.yml— PostgreSQL 16 for the server (port 59876, user/dbpostgres/render4).
The two packages use different package managers and different runtimes: pnpm/Node for server, Bun for CLI.
docker compose up -d # from repo root — starts PostgreSQL
pnpm install
pnpm db:generate # generates Prisma client to app/generated/prisma (gitignored)
pnpm db:push # pushes schema to DB
pnpm dev # Next.js dev server on :3000Requires .env with DATABASE_URL and NEXT_PUBLIC_BASE_URL (see packages/server/.env for local defaults).
- Lint:
pnpm lint(flat ESLint config with eslint-config-next) - Typecheck:
npx tsc --noEmit— do NOT usenext buildfor type checking - Build:
pnpm build(produces standalone output for Docker)
- Dev:
bun run src/index.ts - Build:
bun run build(single JS file) - Cross-platform binaries:
bun run build:binary - Lint:
tsc --noEmit
- Prisma client location is
app/generated/prisma(non-default). Import via@/app/generated/prisma/client. - API routes must use
ok(data)/err(error)from@/lib/api-response— never return raw JSON. - Server actions use
next-safe-actionvia@/lib/safe-action. - Prisma adapter is
@prisma/adapter-pg(not the default driver adapter). Config inprisma.config.tsloadsdotenv/config. - Next.js is version 16 — APIs may differ from training data. Check
node_modules/next/dist/docs/if unsure. - fumadocs powers
/docsfrom MDX incontent/docs/. Generated output in.source(gitignored). - Tailwind CSS v4 with
@tailwindcss/postcss(not v3 config format). - UI libraries: shadcn (radix-ui), base-ui, lucide-react, motion.
- Release: Git tags (
v*) trigger.github/workflows/release.ymlwhich builds CLI binaries and attaches to GitHub Release.
/— Landing page/p/[id]— Diff viewer (decrypts client-side)/f/[id]— File bundle viewer (decrypts client-side)/docs— fumadocs MDX documentation/api/diff,/api/files,/api/search— API routeslib/crypto.ts— AES-256-GCM encryption/decryption (shared logic with CLI)components/ai/— AI-related UI components
CLI and Server run on different runtimes (Bun vs Node) and communicate via encrypted payloads. The pre-encryption plaintext JSON structure is an implicit API contract — any change to one side must be verified against the other.
Actual incident: CLI files command sent [{path, content}], but Server file-decrypt-viewer expected {files: [{title, content}]}, causing post-decryption parse failure.
Rules:
- When modifying CLI pre-encryption data structure, verify compatibility with Server decrypt components (
diff-decrypt-viewer.tsx,file-decrypt-viewer.tsx) - When modifying Server decrypt/parse logic, verify compatibility with CLI commands (
commands/*.ts) - Watch field names: CLI used
path, Server expectstitle; CLI must wrap with{files: [...]} - Core principle: matching crypto algorithms does not guarantee data format compatibility — the plaintext structure is a contract independent of encryption