codesight 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -95,12 +95,47 @@ export interface BlastRadiusResult {
95
95
  depth: number;
96
96
  }
97
97
  export interface CodesightConfig {
98
+ /** Disable specific detectors: "routes", "schema", "components", "libs", "config", "middleware", "graph" */
98
99
  disableDetectors?: string[];
100
+ /** Custom route tags: { "billing": ["stripe", "payment"] } */
99
101
  customTags?: Record<string, string[]>;
102
+ /** Max directory depth (default: 10) */
100
103
  maxDepth?: number;
104
+ /** Output directory name (default: ".codesight") */
101
105
  outputDir?: string;
106
+ /** AI tool profile */
102
107
  profile?: "claude-code" | "cursor" | "codex" | "copilot" | "windsurf" | "generic";
108
+ /** Additional ignore patterns (glob-style) */
103
109
  ignorePatterns?: string[];
110
+ /** Custom route patterns: [{ pattern: "router\\.handle\\(", method: "ALL" }] */
111
+ customRoutePatterns?: {
112
+ pattern: string;
113
+ method?: string;
114
+ }[];
115
+ /** Blast radius max BFS depth (default: 5) */
116
+ blastRadiusDepth?: number;
117
+ /** Hot file threshold: min imports to be "hot" (default: 3) */
118
+ hotFileThreshold?: number;
119
+ /** Plugin hooks */
120
+ plugins?: CodesightPlugin[];
121
+ }
122
+ export interface CodesightPlugin {
123
+ /** Plugin name for identification */
124
+ name: string;
125
+ /** Custom detector: runs after built-in detectors */
126
+ detector?: (files: string[], project: ProjectInfo) => Promise<PluginDetectorResult>;
127
+ /** Post-processor: transforms the final ScanResult */
128
+ postProcessor?: (result: ScanResult) => Promise<ScanResult>;
129
+ }
130
+ export interface PluginDetectorResult {
131
+ /** Additional routes to merge */
132
+ routes?: RouteInfo[];
133
+ /** Additional schema models to merge */
134
+ schemas?: SchemaModel[];
135
+ /** Additional components to merge */
136
+ components?: ComponentInfo[];
137
+ /** Additional middleware to merge */
138
+ middleware?: MiddlewareInfo[];
104
139
  }
105
140
  export interface ScanResult {
106
141
  project: ProjectInfo;
package/eval/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # codesight Evaluation Suite
2
+
3
+ Reproducible accuracy benchmarks for codesight detectors.
4
+
5
+ ## How It Works
6
+
7
+ Each fixture in `fixtures/` contains:
8
+ - `repo.json` — describes the repo structure (files with inline content)
9
+ - `ground-truth.json` — expected detection results (routes, models, env vars, blast radius)
10
+
11
+ Running `npx codesight --eval` will:
12
+ 1. Create temporary directories from each fixture
13
+ 2. Run codesight detectors on them
14
+ 3. Compare results against ground truth
15
+ 4. Print precision, recall, F1 score, and runtime per fixture
16
+
17
+ ## Fixtures
18
+
19
+ | Fixture | Stack | What it tests |
20
+ |---|---|---|
21
+ | `nextjs-drizzle` | Next.js App Router + Drizzle ORM | Routes, schema, components, env vars |
22
+ | `express-prisma` | Express + Prisma | Route detection, schema parsing, middleware |
23
+ | `fastapi-sqlalchemy` | FastAPI + SQLAlchemy | Python routes, Python ORM, config |
24
+ | `hono-monorepo` | Hono + Drizzle (pnpm monorepo) | Monorepo detection, workspace routes, schema |
25
+
26
+ ## Adding a Fixture
27
+
28
+ 1. Create a folder in `fixtures/` with `repo.json` and `ground-truth.json`
29
+ 2. Follow the JSON schema used by existing fixtures
30
+ 3. Run `npx codesight --eval` to verify
31
+
32
+ ## Metrics
33
+
34
+ - **Precision**: of all items codesight detected, how many are correct?
35
+ - **Recall**: of all items that exist, how many did codesight find?
36
+ - **F1**: harmonic mean of precision and recall
@@ -0,0 +1,31 @@
1
+ {
2
+ "routes": [
3
+ { "method": "POST", "path": "/login" },
4
+ { "method": "POST", "path": "/register" },
5
+ { "method": "GET", "path": "/" },
6
+ { "method": "GET", "path": "/:id" },
7
+ { "method": "PUT", "path": "/:id" },
8
+ { "method": "DELETE", "path": "/:id" },
9
+ { "method": "POST", "path": "/" }
10
+ ],
11
+ "models": [
12
+ {
13
+ "name": "User",
14
+ "fields": ["id", "email", "password", "name", "role", "posts", "createdAt"]
15
+ },
16
+ {
17
+ "name": "Post",
18
+ "fields": ["id", "title", "content", "published", "author", "authorId", "tags", "createdAt"]
19
+ },
20
+ {
21
+ "name": "Tag",
22
+ "fields": ["id", "name", "posts"]
23
+ },
24
+ {
25
+ "name": "enum:Role",
26
+ "fields": ["USER", "ADMIN"]
27
+ }
28
+ ],
29
+ "envVars": ["DATABASE_URL", "JWT_SECRET", "PORT", "REDIS_URL", "CORS_ORIGIN"],
30
+ "middleware": ["auth", "error", "rate-limit", "cors"]
31
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "express-prisma-api",
3
+ "description": "Express.js REST API with Prisma ORM and middleware",
4
+ "files": {
5
+ "package.json": "{\"name\":\"api-server\",\"dependencies\":{\"express\":\"4.18.0\",\"@prisma/client\":\"5.0.0\",\"cors\":\"2.8.5\",\"helmet\":\"7.0.0\",\"express-rate-limit\":\"7.0.0\",\"jsonwebtoken\":\"9.0.0\"},\"devDependencies\":{\"typescript\":\"5.3.0\",\"@types/express\":\"4.17.0\",\"@types/node\":\"20.0.0\",\"prisma\":\"5.0.0\"}}",
6
+ "tsconfig.json": "{\"compilerOptions\":{\"target\":\"es2017\",\"module\":\"commonjs\",\"outDir\":\"dist\"}}",
7
+ ".env.example": "DATABASE_URL=postgresql://localhost:5432/api\nJWT_SECRET=changeme\nPORT=3000\nREDIS_URL=redis://localhost:6379\nCORS_ORIGIN=http://localhost:3001",
8
+ "prisma/schema.prisma": "datasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n password String\n name String?\n role Role @default(USER)\n posts Post[]\n createdAt DateTime @default(now())\n}\n\nmodel Post {\n id Int @id @default(autoincrement())\n title String\n content String?\n published Boolean @default(false)\n author User @relation(fields: [authorId], references: [id])\n authorId Int\n tags Tag[]\n createdAt DateTime @default(now())\n}\n\nmodel Tag {\n id Int @id @default(autoincrement())\n name String @unique\n posts Post[]\n}\n\nenum Role {\n USER\n ADMIN\n}",
9
+ "src/index.ts": "import express from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { authRouter } from './routes/auth';\nimport { usersRouter } from './routes/users';\nimport { postsRouter } from './routes/posts';\nimport { errorHandler } from './middleware/error';\nimport { rateLimiter } from './middleware/rate-limit';\n\nconst app = express();\n\napp.use(cors());\napp.use(helmet());\napp.use(express.json());\napp.use(rateLimiter);\n\napp.use('/api/auth', authRouter);\napp.use('/api/users', usersRouter);\napp.use('/api/posts', postsRouter);\n\napp.use(errorHandler);\n\napp.listen(process.env.PORT || 3000);",
10
+ "src/routes/auth.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { generateToken } from '../lib/jwt';\n\nexport const authRouter = Router();\n\nauthRouter.post('/login', async (req, res) => {\n const { email, password } = req.body;\n const user = await prisma.user.findUnique({ where: { email } });\n if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n const token = generateToken(user.id);\n res.json({ token });\n});\n\nauthRouter.post('/register', async (req, res) => {\n const { email, password, name } = req.body;\n const user = await prisma.user.create({ data: { email, password, name } });\n const token = generateToken(user.id);\n res.status(201).json({ token });\n});",
11
+ "src/routes/users.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { authenticate } from '../middleware/auth';\n\nexport const usersRouter = Router();\n\nusersRouter.get('/', authenticate, async (req, res) => {\n const users = await prisma.user.findMany();\n res.json(users);\n});\n\nusersRouter.get('/:id', authenticate, async (req, res) => {\n const user = await prisma.user.findUnique({ where: { id: parseInt(req.params.id) } });\n res.json(user);\n});\n\nusersRouter.put('/:id', authenticate, async (req, res) => {\n const user = await prisma.user.update({ where: { id: parseInt(req.params.id) }, data: req.body });\n res.json(user);\n});\n\nusersRouter.delete('/:id', authenticate, async (req, res) => {\n await prisma.user.delete({ where: { id: parseInt(req.params.id) } });\n res.json({ deleted: true });\n});",
12
+ "src/routes/posts.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { authenticate } from '../middleware/auth';\n\nexport const postsRouter = Router();\n\npostsRouter.get('/', async (req, res) => {\n const posts = await prisma.post.findMany({ include: { author: true, tags: true } });\n res.json(posts);\n});\n\npostsRouter.get('/:id', async (req, res) => {\n const post = await prisma.post.findUnique({ where: { id: parseInt(req.params.id) }, include: { author: true, tags: true } });\n res.json(post);\n});\n\npostsRouter.post('/', authenticate, async (req, res) => {\n const post = await prisma.post.create({ data: { ...req.body, authorId: req.userId } });\n res.status(201).json(post);\n});\n\npostsRouter.put('/:id', authenticate, async (req, res) => {\n const post = await prisma.post.update({ where: { id: parseInt(req.params.id) }, data: req.body });\n res.json(post);\n});\n\npostsRouter.delete('/:id', authenticate, async (req, res) => {\n await prisma.post.delete({ where: { id: parseInt(req.params.id) } });\n res.json({ deleted: true });\n});",
13
+ "src/middleware/auth.ts": "import { Request, Response, NextFunction } from 'express';\nimport { verifyToken } from '../lib/jwt';\n\nexport function authenticate(req: Request, res: Response, next: NextFunction) {\n const token = req.headers.authorization?.replace('Bearer ', '');\n if (!token) return res.status(401).json({ error: 'No token' });\n try {\n const payload = verifyToken(token);\n (req as any).userId = payload.userId;\n next();\n } catch {\n res.status(401).json({ error: 'Invalid token' });\n }\n}",
14
+ "src/middleware/error.ts": "import { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {\n console.error(err.stack);\n res.status(500).json({ error: 'Internal server error' });\n}",
15
+ "src/middleware/rate-limit.ts": "import rateLimit from 'express-rate-limit';\n\nexport const rateLimiter = rateLimit({\n windowMs: 15 * 60 * 1000,\n max: 100,\n message: { error: 'Too many requests' }\n});",
16
+ "src/lib/prisma.ts": "import { PrismaClient } from '@prisma/client';\n\nexport const prisma = new PrismaClient();",
17
+ "src/lib/jwt.ts": "import jwt from 'jsonwebtoken';\n\nconst SECRET = process.env.JWT_SECRET || 'dev-secret';\n\nexport function generateToken(userId: number): string {\n return jwt.sign({ userId }, SECRET, { expiresIn: '24h' });\n}\n\nexport function verifyToken(token: string): { userId: number } {\n return jwt.verify(token, SECRET) as { userId: number };\n}"
18
+ }
19
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "routes": [
3
+ { "method": "GET", "path": "/health" },
4
+ { "method": "GET", "path": "/" },
5
+ { "method": "GET", "path": "/{user_id}" },
6
+ { "method": "POST", "path": "/" },
7
+ { "method": "DELETE", "path": "/{user_id}" },
8
+ { "method": "GET", "path": "/{item_id}" },
9
+ { "method": "POST", "path": "/" },
10
+ { "method": "PUT", "path": "/{item_id}" },
11
+ { "method": "POST", "path": "/login" },
12
+ { "method": "POST", "path": "/register" }
13
+ ],
14
+ "models": [
15
+ {
16
+ "name": "User",
17
+ "fields": ["id", "email", "password", "name", "is_active", "items", "created_at"]
18
+ },
19
+ {
20
+ "name": "Item",
21
+ "fields": ["id", "title", "description", "price", "owner_id", "owner", "created_at"]
22
+ },
23
+ {
24
+ "name": "Category",
25
+ "fields": ["id", "name", "description"]
26
+ }
27
+ ],
28
+ "envVars": ["DATABASE_URL", "SECRET_KEY", "DEBUG", "ALLOWED_ORIGINS"]
29
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "fastapi-sqlalchemy-api",
3
+ "description": "FastAPI with SQLAlchemy models",
4
+ "files": {
5
+ "requirements.txt": "fastapi==0.104.0\nuvicorn==0.24.0\nsqlalchemy==2.0.23\nalembic==1.12.0\npydantic==2.5.0\npython-dotenv==1.0.0",
6
+ ".env.example": "DATABASE_URL=postgresql://localhost:5432/fastapi_db\nSECRET_KEY=changeme\nDEBUG=true\nALLOWED_ORIGINS=http://localhost:3000",
7
+ "app/__init__.py": "",
8
+ "app/main.py": "from fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom app.routes import users, items, auth\n\napp = FastAPI(title=\"My API\")\n\napp.add_middleware(CORSMiddleware, allow_origins=[\"*\"])\n\napp.include_router(users.router, prefix=\"/api/users\", tags=[\"users\"])\napp.include_router(items.router, prefix=\"/api/items\", tags=[\"items\"])\napp.include_router(auth.router, prefix=\"/api/auth\", tags=[\"auth\"])\n\n@app.get(\"/health\")\ndef health():\n return {\"status\": \"ok\"}",
9
+ "app/routes/__init__.py": "",
10
+ "app/routes/users.py": "from fastapi import APIRouter, Depends, HTTPException\nfrom sqlalchemy.orm import Session\nfrom app.db import get_db\nfrom app.models import User\n\nrouter = APIRouter()\n\n@router.get(\"/\")\ndef list_users(db: Session = Depends(get_db)):\n return db.query(User).all()\n\n@router.get(\"/{user_id}\")\ndef get_user(user_id: int, db: Session = Depends(get_db)):\n user = db.query(User).filter(User.id == user_id).first()\n if not user:\n raise HTTPException(status_code=404)\n return user\n\n@router.post(\"/\")\ndef create_user(data: dict, db: Session = Depends(get_db)):\n user = User(**data)\n db.add(user)\n db.commit()\n return user\n\n@router.delete(\"/{user_id}\")\ndef delete_user(user_id: int, db: Session = Depends(get_db)):\n db.query(User).filter(User.id == user_id).delete()\n db.commit()\n return {\"deleted\": True}",
11
+ "app/routes/items.py": "from fastapi import APIRouter, Depends\nfrom sqlalchemy.orm import Session\nfrom app.db import get_db\nfrom app.models import Item\n\nrouter = APIRouter()\n\n@router.get(\"/\")\ndef list_items(db: Session = Depends(get_db)):\n return db.query(Item).all()\n\n@router.get(\"/{item_id}\")\ndef get_item(item_id: int, db: Session = Depends(get_db)):\n return db.query(Item).filter(Item.id == item_id).first()\n\n@router.post(\"/\")\ndef create_item(data: dict, db: Session = Depends(get_db)):\n item = Item(**data)\n db.add(item)\n db.commit()\n return item\n\n@router.put(\"/{item_id}\")\ndef update_item(item_id: int, data: dict, db: Session = Depends(get_db)):\n item = db.query(Item).filter(Item.id == item_id).first()\n for k, v in data.items():\n setattr(item, k, v)\n db.commit()\n return item",
12
+ "app/routes/auth.py": "from fastapi import APIRouter\n\nrouter = APIRouter()\n\n@router.post(\"/login\")\ndef login(data: dict):\n return {\"token\": \"fake-token\"}\n\n@router.post(\"/register\")\ndef register(data: dict):\n return {\"user\": data}",
13
+ "app/models.py": "from sqlalchemy import Column, Integer, String, Boolean, ForeignKey, DateTime, Float\nfrom sqlalchemy.orm import relationship\nfrom datetime import datetime\nfrom app.db import Base\n\nclass User(Base):\n __tablename__ = 'users'\n id = Column(Integer, primary_key=True)\n email = Column(String, unique=True, nullable=False)\n password = Column(String, nullable=False)\n name = Column(String)\n is_active = Column(Boolean, default=True)\n items = relationship('Item', back_populates='owner')\n created_at = Column(DateTime, default=datetime.utcnow)\n\nclass Item(Base):\n __tablename__ = 'items'\n id = Column(Integer, primary_key=True)\n title = Column(String, nullable=False)\n description = Column(String)\n price = Column(Float)\n owner_id = Column(Integer, ForeignKey('users.id'))\n owner = relationship('User', back_populates='items')\n created_at = Column(DateTime, default=datetime.utcnow)\n\nclass Category(Base):\n __tablename__ = 'categories'\n id = Column(Integer, primary_key=True)\n name = Column(String, unique=True, nullable=False)\n description = Column(String)",
14
+ "app/db.py": "from sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker, declarative_base\nimport os\n\nDATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///./test.db')\nengine = create_engine(DATABASE_URL)\nSessionLocal = sessionmaker(bind=engine)\nBase = declarative_base()\n\ndef get_db():\n db = SessionLocal()\n try:\n yield db\n finally:\n db.close()"
15
+ }
16
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "routes": [
3
+ { "method": "GET", "path": "/health" },
4
+ { "method": "POST", "path": "/login" },
5
+ { "method": "POST", "path": "/register" },
6
+ { "method": "POST", "path": "/refresh" },
7
+ { "method": "GET", "path": "/" },
8
+ { "method": "GET", "path": "/:id" },
9
+ { "method": "PUT", "path": "/:id" },
10
+ { "method": "DELETE", "path": "/:id" },
11
+ { "method": "GET", "path": "/" },
12
+ { "method": "GET", "path": "/:id" },
13
+ { "method": "POST", "path": "/" }
14
+ ],
15
+ "models": [
16
+ {
17
+ "name": "users",
18
+ "fields": ["id", "email", "name", "role", "createdAt"],
19
+ "relations": ["projects"]
20
+ },
21
+ {
22
+ "name": "projects",
23
+ "fields": ["id", "name", "description", "ownerId", "isPublic", "createdAt"],
24
+ "relations": ["owner"]
25
+ }
26
+ ],
27
+ "components": [
28
+ { "name": "ProjectCard", "props": ["name", "description", "isPublic"] },
29
+ { "name": "UserAvatar", "props": ["name", "size"] }
30
+ ],
31
+ "envVars": ["DATABASE_URL", "JWT_SECRET", "PORT"],
32
+ "middleware": ["auth"]
33
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "hono-monorepo",
3
+ "description": "Hono API + React frontend in pnpm monorepo with Drizzle",
4
+ "files": {
5
+ "package.json": "{\"name\":\"my-monorepo\",\"private\":true}",
6
+ "pnpm-workspace.yaml": "packages:\n - 'apps/*'\n - 'packages/*'",
7
+ "apps/api/package.json": "{\"name\":\"@mono/api\",\"dependencies\":{\"hono\":\"4.0.0\",\"drizzle-orm\":\"0.30.0\",\"pg\":\"8.11.0\",\"zod\":\"3.22.0\"},\"devDependencies\":{\"typescript\":\"5.3.0\"}}",
8
+ "apps/api/.env.example": "DATABASE_URL=postgres://localhost:5432/mono\nJWT_SECRET=secret\nPORT=4000",
9
+ "apps/api/src/index.ts": "import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { logger } from 'hono/logger';\nimport { authRoutes } from './routes/auth';\nimport { userRoutes } from './routes/users';\nimport { projectRoutes } from './routes/projects';\n\nconst app = new Hono();\n\napp.use('*', cors());\napp.use('*', logger());\n\napp.get('/health', (c) => c.json({ ok: true }));\n\napp.route('/api/auth', authRoutes);\napp.route('/api/users', userRoutes);\napp.route('/api/projects', projectRoutes);\n\nexport default app;",
10
+ "apps/api/src/routes/auth.ts": "import { Hono } from 'hono';\nimport { zValidator } from '@hono/zod-validator';\nimport { z } from 'zod';\n\nexport const authRoutes = new Hono();\n\nconst loginSchema = z.object({ email: z.string().email(), password: z.string() });\n\nauthRoutes.post('/login', zValidator('json', loginSchema), async (c) => {\n const { email, password } = c.req.valid('json');\n return c.json({ token: 'jwt-token' });\n});\n\nauthRoutes.post('/register', async (c) => {\n const body = await c.req.json();\n return c.json({ user: body }, 201);\n});\n\nauthRoutes.post('/refresh', async (c) => {\n return c.json({ token: 'new-token' });\n});",
11
+ "apps/api/src/routes/users.ts": "import { Hono } from 'hono';\nimport { db } from '../db';\nimport { users } from '../db/schema';\nimport { eq } from 'drizzle-orm';\n\nexport const userRoutes = new Hono();\n\nuserRoutes.get('/', async (c) => {\n const all = await db.select().from(users);\n return c.json(all);\n});\n\nuserRoutes.get('/:id', async (c) => {\n const id = parseInt(c.req.param('id'));\n const user = await db.select().from(users).where(eq(users.id, id));\n return c.json(user[0]);\n});\n\nuserRoutes.put('/:id', async (c) => {\n const id = parseInt(c.req.param('id'));\n const body = await c.req.json();\n const updated = await db.update(users).set(body).where(eq(users.id, id)).returning();\n return c.json(updated[0]);\n});\n\nuserRoutes.delete('/:id', async (c) => {\n const id = parseInt(c.req.param('id'));\n await db.delete(users).where(eq(users.id, id));\n return c.json({ deleted: true });\n});",
12
+ "apps/api/src/routes/projects.ts": "import { Hono } from 'hono';\nimport { db } from '../db';\nimport { projects } from '../db/schema';\nimport { eq } from 'drizzle-orm';\n\nexport const projectRoutes = new Hono();\n\nprojectRoutes.get('/', async (c) => {\n const all = await db.select().from(projects);\n return c.json(all);\n});\n\nprojectRoutes.get('/:id', async (c) => {\n const id = parseInt(c.req.param('id'));\n const project = await db.select().from(projects).where(eq(projects.id, id));\n return c.json(project[0]);\n});\n\nprojectRoutes.post('/', async (c) => {\n const body = await c.req.json();\n const created = await db.insert(projects).values(body).returning();\n return c.json(created[0], 201);\n});",
13
+ "apps/api/src/db/index.ts": "import { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\n\nconst pool = new Pool({ connectionString: process.env.DATABASE_URL });\nexport const db = drizzle(pool);",
14
+ "apps/api/src/db/schema.ts": "import { pgTable, serial, text, timestamp, integer, boolean } from 'drizzle-orm/pg-core';\nimport { relations } from 'drizzle-orm';\n\nexport const users = pgTable('users', {\n id: serial('id').primaryKey(),\n email: text('email').notNull().unique(),\n name: text('name'),\n role: text('role').default('user'),\n createdAt: timestamp('created_at').defaultNow()\n});\n\nexport const projects = pgTable('projects', {\n id: serial('id').primaryKey(),\n name: text('name').notNull(),\n description: text('description'),\n ownerId: integer('owner_id').notNull().references(() => users.id),\n isPublic: boolean('is_public').default(true),\n createdAt: timestamp('created_at').defaultNow()\n});\n\nexport const usersRelations = relations(users, ({ many }) => ({\n projects: many(projects)\n}));\n\nexport const projectsRelations = relations(projects, ({ one }) => ({\n owner: one(users, { fields: [projects.ownerId], references: [users.id] })\n}));",
15
+ "apps/api/src/middleware/auth.ts": "import { Context, Next } from 'hono';\n\nexport async function authMiddleware(c: Context, next: Next) {\n const token = c.req.header('Authorization');\n if (!token) return c.json({ error: 'Unauthorized' }, 401);\n await next();\n}",
16
+ "apps/web/package.json": "{\"name\":\"@mono/web\",\"dependencies\":{\"react\":\"18.0.0\",\"react-dom\":\"18.0.0\"},\"devDependencies\":{\"typescript\":\"5.3.0\",\"vite\":\"5.0.0\"}}",
17
+ "apps/web/src/components/ProjectCard.tsx": "import React from 'react';\n\ninterface ProjectCardProps {\n name: string;\n description: string;\n isPublic: boolean;\n}\n\nexport function ProjectCard({ name, description, isPublic }: ProjectCardProps) {\n return <div><h3>{name}</h3><p>{description}</p>{isPublic && <span>Public</span>}</div>;\n}",
18
+ "apps/web/src/components/UserAvatar.tsx": "'use client';\nimport React from 'react';\n\ninterface UserAvatarProps {\n name: string;\n size?: number;\n}\n\nexport function UserAvatar({ name, size = 40 }: UserAvatarProps) {\n return <div style={{ width: size, height: size }}>{name[0]}</div>;\n}"
19
+ }
20
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "routes": [
3
+ { "method": "GET", "path": "/api/users" },
4
+ { "method": "POST", "path": "/api/users" },
5
+ { "method": "GET", "path": "/api/users/[id]" },
6
+ { "method": "PUT", "path": "/api/users/[id]" },
7
+ { "method": "DELETE", "path": "/api/users/[id]" },
8
+ { "method": "GET", "path": "/api/posts" },
9
+ { "method": "POST", "path": "/api/posts" },
10
+ { "method": "GET", "path": "/api/posts/[id]/comments" },
11
+ { "method": "POST", "path": "/api/posts/[id]/comments" }
12
+ ],
13
+ "models": [
14
+ {
15
+ "name": "users",
16
+ "fields": ["id", "email", "name", "createdAt"],
17
+ "relations": ["posts", "comments"]
18
+ },
19
+ {
20
+ "name": "posts",
21
+ "fields": ["id", "title", "content", "published", "authorId", "createdAt"],
22
+ "relations": ["author", "comments"]
23
+ },
24
+ {
25
+ "name": "comments",
26
+ "fields": ["id", "body", "postId", "authorId", "createdAt"],
27
+ "relations": []
28
+ }
29
+ ],
30
+ "components": [
31
+ { "name": "UserCard", "props": ["name", "email", "avatar"] },
32
+ { "name": "PostList", "props": ["posts", "onSelect"] },
33
+ { "name": "CommentForm", "props": ["postId", "onSubmit"] }
34
+ ],
35
+ "envVars": ["DATABASE_URL", "NEXTAUTH_SECRET", "NEXT_PUBLIC_API_URL"],
36
+ "middleware": ["middleware", "auth"]
37
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "nextjs-drizzle-app",
3
+ "description": "Next.js App Router with Drizzle ORM and React components",
4
+ "files": {
5
+ "package.json": "{\"name\":\"my-app\",\"dependencies\":{\"next\":\"14.0.0\",\"react\":\"18.0.0\",\"drizzle-orm\":\"0.30.0\",\"pg\":\"8.11.0\",\"zod\":\"3.22.0\"},\"devDependencies\":{\"typescript\":\"5.3.0\",\"@types/node\":\"20.0.0\"}}",
6
+ "tsconfig.json": "{\"compilerOptions\":{\"target\":\"es2017\",\"module\":\"esnext\",\"jsx\":\"react-jsx\"}}",
7
+ ".env.example": "DATABASE_URL=postgres://localhost:5432/mydb\nNEXTAUTH_SECRET=\nNEXT_PUBLIC_API_URL=http://localhost:3000",
8
+ "drizzle.config.ts": "import { defineConfig } from 'drizzle-kit';\nexport default defineConfig({ schema: './src/db/schema.ts', driver: 'pg' });",
9
+ "src/db/schema.ts": "import { pgTable, serial, text, timestamp, integer, boolean } from 'drizzle-orm/pg-core';\nimport { relations } from 'drizzle-orm';\n\nexport const users = pgTable('users', {\n id: serial('id').primaryKey(),\n email: text('email').notNull().unique(),\n name: text('name'),\n createdAt: timestamp('created_at').defaultNow()\n});\n\nexport const posts = pgTable('posts', {\n id: serial('id').primaryKey(),\n title: text('title').notNull(),\n content: text('content'),\n published: boolean('published').default(false),\n authorId: integer('author_id').notNull().references(() => users.id),\n createdAt: timestamp('created_at').defaultNow()\n});\n\nexport const comments = pgTable('comments', {\n id: serial('id').primaryKey(),\n body: text('body').notNull(),\n postId: integer('post_id').notNull().references(() => posts.id),\n authorId: integer('author_id').notNull().references(() => users.id),\n createdAt: timestamp('created_at').defaultNow()\n});\n\nexport const usersRelations = relations(users, ({ many }) => ({\n posts: many(posts),\n comments: many(comments)\n}));\n\nexport const postsRelations = relations(posts, ({ one, many }) => ({\n author: one(users, { fields: [posts.authorId], references: [users.id] }),\n comments: many(comments)\n}));",
10
+ "src/app/api/users/route.ts": "import { NextResponse } from 'next/server';\nimport { db } from '@/db';\nimport { users } from '@/db/schema';\n\nexport async function GET() {\n const all = await db.select().from(users);\n return NextResponse.json(all);\n}\n\nexport async function POST(req: Request) {\n const body = await req.json();\n const user = await db.insert(users).values(body).returning();\n return NextResponse.json(user, { status: 201 });\n}",
11
+ "src/app/api/users/[id]/route.ts": "import { NextResponse } from 'next/server';\nimport { db } from '@/db';\nimport { users } from '@/db/schema';\nimport { eq } from 'drizzle-orm';\n\nexport async function GET(req: Request, { params }: { params: { id: string } }) {\n const user = await db.select().from(users).where(eq(users.id, parseInt(params.id)));\n return NextResponse.json(user[0]);\n}\n\nexport async function PUT(req: Request, { params }: { params: { id: string } }) {\n const body = await req.json();\n const updated = await db.update(users).set(body).where(eq(users.id, parseInt(params.id))).returning();\n return NextResponse.json(updated[0]);\n}\n\nexport async function DELETE(req: Request, { params }: { params: { id: string } }) {\n await db.delete(users).where(eq(users.id, parseInt(params.id)));\n return NextResponse.json({ deleted: true });\n}",
12
+ "src/app/api/posts/route.ts": "import { NextResponse } from 'next/server';\nimport { db } from '@/db';\nimport { posts } from '@/db/schema';\n\nexport async function GET() {\n const all = await db.select().from(posts);\n return NextResponse.json(all);\n}\n\nexport async function POST(req: Request) {\n const body = await req.json();\n const post = await db.insert(posts).values(body).returning();\n return NextResponse.json(post, { status: 201 });\n}",
13
+ "src/app/api/posts/[id]/comments/route.ts": "import { NextResponse } from 'next/server';\nimport { db } from '@/db';\nimport { comments } from '@/db/schema';\nimport { eq } from 'drizzle-orm';\n\nexport async function GET(req: Request, { params }: { params: { id: string } }) {\n const all = await db.select().from(comments).where(eq(comments.postId, parseInt(params.id)));\n return NextResponse.json(all);\n}\n\nexport async function POST(req: Request, { params }: { params: { id: string } }) {\n const body = await req.json();\n const comment = await db.insert(comments).values({ ...body, postId: parseInt(params.id) }).returning();\n return NextResponse.json(comment, { status: 201 });\n}",
14
+ "src/components/UserCard.tsx": "'use client';\nimport React from 'react';\n\ninterface UserCardProps {\n name: string;\n email: string;\n avatar?: string;\n}\n\nexport function UserCard({ name, email, avatar }: UserCardProps) {\n return <div className=\"card\"><h3>{name}</h3><p>{email}</p></div>;\n}",
15
+ "src/components/PostList.tsx": "import React from 'react';\n\ninterface PostListProps {\n posts: Array<{ id: number; title: string; published: boolean }>;\n onSelect: (id: number) => void;\n}\n\nexport function PostList({ posts, onSelect }: PostListProps) {\n return <ul>{posts.map(p => <li key={p.id} onClick={() => onSelect(p.id)}>{p.title}</li>)}</ul>;\n}",
16
+ "src/components/CommentForm.tsx": "'use client';\nimport React, { useState } from 'react';\n\ninterface CommentFormProps {\n postId: number;\n onSubmit: (body: string) => void;\n}\n\nexport function CommentForm({ postId, onSubmit }: CommentFormProps) {\n const [body, setBody] = useState('');\n return <form onSubmit={() => onSubmit(body)}><textarea value={body} onChange={e => setBody(e.target.value)} /><button type=\"submit\">Submit</button></form>;\n}",
17
+ "src/middleware.ts": "import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nexport function middleware(request: NextRequest) {\n const token = request.headers.get('authorization');\n if (!token && request.nextUrl.pathname.startsWith('/api')) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n }\n return NextResponse.next();\n}\n\nexport const config = { matcher: '/api/:path*' };",
18
+ "src/lib/auth.ts": "export function verifyToken(token: string): boolean {\n return token.startsWith('Bearer ');\n}\n\nexport function createToken(userId: number): string {\n return `Bearer ${userId}-${Date.now()}`;\n}",
19
+ "src/lib/validate.ts": "import { z } from 'zod';\n\nexport const createUserSchema = z.object({\n email: z.string().email(),\n name: z.string().min(1)\n});\n\nexport const createPostSchema = z.object({\n title: z.string().min(1),\n content: z.string().optional(),\n published: z.boolean().optional()\n});"
20
+ }
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codesight",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "See your codebase clearly. Universal AI context generator that maps routes, schema, components, dependencies, and more for Claude Code, Cursor, Copilot, Codex, and any AI coding tool.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -50,6 +50,7 @@
50
50
  "node": ">=18.0.0"
51
51
  },
52
52
  "files": [
53
- "dist"
53
+ "dist",
54
+ "eval"
54
55
  ]
55
56
  }