codesight 1.0.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.
@@ -0,0 +1,329 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join, relative, basename, extname } from "node:path";
3
+ const IGNORE_DIRS = new Set([
4
+ "node_modules",
5
+ ".git",
6
+ ".next",
7
+ ".nuxt",
8
+ ".svelte-kit",
9
+ "__pycache__",
10
+ ".venv",
11
+ "venv",
12
+ "env",
13
+ "dist",
14
+ "build",
15
+ "out",
16
+ ".output",
17
+ "coverage",
18
+ ".turbo",
19
+ ".vercel",
20
+ ".codesight",
21
+ ".codescope",
22
+ ".ai-codex",
23
+ "vendor",
24
+ ".cache",
25
+ ".parcel-cache",
26
+ ]);
27
+ const CODE_EXTENSIONS = new Set([
28
+ ".ts",
29
+ ".tsx",
30
+ ".js",
31
+ ".jsx",
32
+ ".mjs",
33
+ ".cjs",
34
+ ".py",
35
+ ".go",
36
+ ".vue",
37
+ ".svelte",
38
+ ]);
39
+ export async function collectFiles(root, maxDepth = 10) {
40
+ const files = [];
41
+ async function walk(dir, depth) {
42
+ if (depth > maxDepth)
43
+ return;
44
+ let entries;
45
+ try {
46
+ entries = await readdir(dir, { withFileTypes: true });
47
+ }
48
+ catch {
49
+ return;
50
+ }
51
+ for (const entry of entries) {
52
+ if (entry.name.startsWith(".") && entry.name !== ".env" && entry.name !== ".env.example" && entry.name !== ".env.local")
53
+ continue;
54
+ const fullPath = join(dir, entry.name);
55
+ if (entry.isDirectory()) {
56
+ if (IGNORE_DIRS.has(entry.name))
57
+ continue;
58
+ await walk(fullPath, depth + 1);
59
+ }
60
+ else if (entry.isFile()) {
61
+ const ext = extname(entry.name);
62
+ if (CODE_EXTENSIONS.has(ext) || entry.name === ".env" || entry.name === ".env.example" || entry.name === ".env.local") {
63
+ files.push(fullPath);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ await walk(root, 0);
69
+ return files;
70
+ }
71
+ export async function readFileSafe(path) {
72
+ try {
73
+ return await readFile(path, "utf-8");
74
+ }
75
+ catch {
76
+ return "";
77
+ }
78
+ }
79
+ export async function detectProject(root) {
80
+ const pkgPath = join(root, "package.json");
81
+ let pkg = {};
82
+ try {
83
+ pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
84
+ }
85
+ catch { }
86
+ const name = pkg.name || basename(root);
87
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
88
+ // Detect monorepo
89
+ const isMonorepo = !!(pkg.workspaces || await fileExists(join(root, "pnpm-workspace.yaml")));
90
+ const workspaces = [];
91
+ if (isMonorepo) {
92
+ const wsPatterns = await getWorkspacePatterns(root, pkg);
93
+ for (const pattern of wsPatterns) {
94
+ const wsRoot = join(root, pattern.replace("/*", ""));
95
+ try {
96
+ const wsDirs = await readdir(wsRoot, { withFileTypes: true });
97
+ for (const d of wsDirs) {
98
+ if (!d.isDirectory() || d.name.startsWith("."))
99
+ continue;
100
+ const wsPath = join(wsRoot, d.name);
101
+ const wsPkg = await readJsonSafe(join(wsPath, "package.json"));
102
+ workspaces.push({
103
+ name: wsPkg.name || d.name,
104
+ path: relative(root, wsPath),
105
+ frameworks: await detectFrameworks(wsPath, wsPkg),
106
+ orms: await detectORMs(wsPath, wsPkg),
107
+ });
108
+ }
109
+ }
110
+ catch { }
111
+ }
112
+ }
113
+ // For monorepos, aggregate all workspace deps for top-level detection
114
+ let allDeps = { ...deps };
115
+ if (isMonorepo) {
116
+ for (const ws of workspaces) {
117
+ const wsPkg = await readJsonSafe(join(root, ws.path, "package.json"));
118
+ Object.assign(allDeps, wsPkg.dependencies, wsPkg.devDependencies);
119
+ }
120
+ }
121
+ // Detect language
122
+ const language = await detectLanguage(root, allDeps);
123
+ // For monorepos, aggregate frameworks and orms from workspaces
124
+ let frameworks = await detectFrameworks(root, pkg);
125
+ let orms = await detectORMs(root, pkg);
126
+ if (isMonorepo) {
127
+ for (const ws of workspaces) {
128
+ for (const fw of ws.frameworks) {
129
+ if (!frameworks.includes(fw))
130
+ frameworks.push(fw);
131
+ }
132
+ for (const orm of ws.orms) {
133
+ if (!orms.includes(orm))
134
+ orms.push(orm);
135
+ }
136
+ }
137
+ }
138
+ return {
139
+ root,
140
+ name,
141
+ frameworks,
142
+ orms,
143
+ componentFramework: detectComponentFramework(allDeps),
144
+ isMonorepo,
145
+ workspaces,
146
+ language,
147
+ };
148
+ }
149
+ async function detectFrameworks(root, pkg) {
150
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
151
+ const frameworks = [];
152
+ // Next.js
153
+ if (deps["next"]) {
154
+ const hasAppDir = (await fileExists(join(root, "app"))) ||
155
+ (await fileExists(join(root, "src/app")));
156
+ const hasPagesDir = (await fileExists(join(root, "pages"))) ||
157
+ (await fileExists(join(root, "src/pages")));
158
+ if (hasAppDir)
159
+ frameworks.push("next-app");
160
+ if (hasPagesDir)
161
+ frameworks.push("next-pages");
162
+ if (!hasAppDir && !hasPagesDir)
163
+ frameworks.push("next-app");
164
+ }
165
+ // Hono
166
+ if (deps["hono"])
167
+ frameworks.push("hono");
168
+ // Express
169
+ if (deps["express"])
170
+ frameworks.push("express");
171
+ // Fastify
172
+ if (deps["fastify"])
173
+ frameworks.push("fastify");
174
+ // Koa
175
+ if (deps["koa"])
176
+ frameworks.push("koa");
177
+ // Python frameworks - check for requirements.txt or pyproject.toml
178
+ const pyDeps = await getPythonDeps(root);
179
+ if (pyDeps.includes("flask"))
180
+ frameworks.push("flask");
181
+ if (pyDeps.includes("fastapi"))
182
+ frameworks.push("fastapi");
183
+ if (pyDeps.includes("django"))
184
+ frameworks.push("django");
185
+ // Go frameworks - check go.mod
186
+ const goDeps = await getGoDeps(root);
187
+ if (goDeps.includes("net/http"))
188
+ frameworks.push("go-net-http");
189
+ if (goDeps.includes("gin-gonic/gin"))
190
+ frameworks.push("gin");
191
+ if (goDeps.includes("gofiber/fiber"))
192
+ frameworks.push("fiber");
193
+ return frameworks;
194
+ }
195
+ async function detectORMs(root, pkg) {
196
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
197
+ const orms = [];
198
+ if (deps["drizzle-orm"])
199
+ orms.push("drizzle");
200
+ if (deps["prisma"] || deps["@prisma/client"])
201
+ orms.push("prisma");
202
+ if (deps["typeorm"])
203
+ orms.push("typeorm");
204
+ const pyDeps = await getPythonDeps(root);
205
+ if (pyDeps.includes("sqlalchemy"))
206
+ orms.push("sqlalchemy");
207
+ const goDeps = await getGoDeps(root);
208
+ if (goDeps.some((d) => d.includes("gorm")))
209
+ orms.push("gorm");
210
+ return orms;
211
+ }
212
+ function detectComponentFramework(deps) {
213
+ if (deps["react"] || deps["react-dom"])
214
+ return "react";
215
+ if (deps["vue"])
216
+ return "vue";
217
+ if (deps["svelte"])
218
+ return "svelte";
219
+ return "unknown";
220
+ }
221
+ async function detectLanguage(root, deps) {
222
+ const hasTsConfig = await fileExists(join(root, "tsconfig.json"));
223
+ const hasPyProject = await fileExists(join(root, "pyproject.toml")) || await fileExists(join(root, "backend/pyproject.toml"));
224
+ const hasGoMod = await fileExists(join(root, "go.mod"));
225
+ const hasRequirements = await fileExists(join(root, "requirements.txt")) || await fileExists(join(root, "backend/requirements.txt"));
226
+ const langs = [];
227
+ if (hasTsConfig || deps["typescript"])
228
+ langs.push("typescript");
229
+ if (hasPyProject || hasRequirements)
230
+ langs.push("python");
231
+ if (hasGoMod)
232
+ langs.push("go");
233
+ if (langs.length > 1)
234
+ return "mixed";
235
+ if (langs[0] === "typescript")
236
+ return "typescript";
237
+ if (langs[0] === "python")
238
+ return "python";
239
+ if (langs[0] === "go")
240
+ return "go";
241
+ return "javascript";
242
+ }
243
+ async function getWorkspacePatterns(root, pkg) {
244
+ // pnpm-workspace.yaml
245
+ try {
246
+ const yaml = await readFile(join(root, "pnpm-workspace.yaml"), "utf-8");
247
+ const patterns = [];
248
+ for (const line of yaml.split("\n")) {
249
+ const match = line.match(/^\s*-\s*['"]?([^'"]+)['"]?\s*$/);
250
+ if (match)
251
+ patterns.push(match[1]);
252
+ }
253
+ if (patterns.length > 0)
254
+ return patterns;
255
+ }
256
+ catch { }
257
+ // package.json workspaces
258
+ if (Array.isArray(pkg.workspaces))
259
+ return pkg.workspaces;
260
+ if (pkg.workspaces?.packages)
261
+ return pkg.workspaces.packages;
262
+ return [];
263
+ }
264
+ async function getPythonDeps(root) {
265
+ const deps = [];
266
+ // Check root and common subdirectories
267
+ const searchDirs = [root, join(root, "backend"), join(root, "api"), join(root, "server"), join(root, "src")];
268
+ for (const dir of searchDirs) {
269
+ try {
270
+ const req = await readFile(join(dir, "requirements.txt"), "utf-8");
271
+ for (const line of req.split("\n")) {
272
+ const name = line.split(/[>=<\[]/)[0].trim().toLowerCase();
273
+ if (name && !deps.includes(name))
274
+ deps.push(name);
275
+ }
276
+ }
277
+ catch { }
278
+ try {
279
+ const toml = await readFile(join(dir, "pyproject.toml"), "utf-8");
280
+ const depSection = toml.match(/\[project\][\s\S]*?dependencies\s*=\s*\[([\s\S]*?)\]/);
281
+ if (depSection) {
282
+ for (const match of depSection[1].matchAll(/"([^"]+)"/g)) {
283
+ const name = match[1].split(/[>=<\[]/)[0].trim().toLowerCase();
284
+ if (!deps.includes(name))
285
+ deps.push(name);
286
+ }
287
+ }
288
+ }
289
+ catch { }
290
+ }
291
+ return deps;
292
+ }
293
+ async function getGoDeps(root) {
294
+ const deps = [];
295
+ try {
296
+ const gomod = await readFile(join(root, "go.mod"), "utf-8");
297
+ for (const line of gomod.split("\n")) {
298
+ const match = line.match(/^\s*([\w./-]+)\s+v/);
299
+ if (match)
300
+ deps.push(match[1]);
301
+ }
302
+ // Check for net/http usage in main.go
303
+ try {
304
+ const main = await readFile(join(root, "main.go"), "utf-8");
305
+ if (main.includes("net/http"))
306
+ deps.push("net/http");
307
+ }
308
+ catch { }
309
+ }
310
+ catch { }
311
+ return deps;
312
+ }
313
+ async function fileExists(path) {
314
+ try {
315
+ await stat(path);
316
+ return true;
317
+ }
318
+ catch {
319
+ return false;
320
+ }
321
+ }
322
+ async function readJsonSafe(path) {
323
+ try {
324
+ return JSON.parse(await readFile(path, "utf-8"));
325
+ }
326
+ catch {
327
+ return {};
328
+ }
329
+ }
@@ -0,0 +1,100 @@
1
+ export type Framework = "next-app" | "next-pages" | "hono" | "express" | "fastify" | "koa" | "flask" | "fastapi" | "django" | "go-net-http" | "gin" | "fiber" | "unknown";
2
+ export type ORM = "drizzle" | "prisma" | "typeorm" | "sqlalchemy" | "gorm" | "unknown";
3
+ export type ComponentFramework = "react" | "vue" | "svelte" | "unknown";
4
+ export interface ProjectInfo {
5
+ root: string;
6
+ name: string;
7
+ frameworks: Framework[];
8
+ orms: ORM[];
9
+ componentFramework: ComponentFramework;
10
+ isMonorepo: boolean;
11
+ workspaces: WorkspaceInfo[];
12
+ language: "typescript" | "javascript" | "python" | "go" | "mixed";
13
+ }
14
+ export interface WorkspaceInfo {
15
+ name: string;
16
+ path: string;
17
+ frameworks: Framework[];
18
+ orms: ORM[];
19
+ }
20
+ export interface RouteInfo {
21
+ method: string;
22
+ path: string;
23
+ file: string;
24
+ tags: string[];
25
+ framework: Framework;
26
+ requestType?: string;
27
+ responseType?: string;
28
+ params?: string[];
29
+ }
30
+ export interface SchemaModel {
31
+ name: string;
32
+ fields: SchemaField[];
33
+ relations: string[];
34
+ orm: ORM;
35
+ }
36
+ export interface SchemaField {
37
+ name: string;
38
+ type: string;
39
+ flags: string[];
40
+ }
41
+ export interface ComponentInfo {
42
+ name: string;
43
+ file: string;
44
+ props: string[];
45
+ isClient: boolean;
46
+ isServer: boolean;
47
+ }
48
+ export interface LibExport {
49
+ file: string;
50
+ exports: ExportItem[];
51
+ }
52
+ export interface ExportItem {
53
+ name: string;
54
+ kind: "function" | "class" | "const" | "type" | "interface" | "enum";
55
+ signature?: string;
56
+ }
57
+ export interface ConfigInfo {
58
+ envVars: EnvVar[];
59
+ configFiles: string[];
60
+ dependencies: Record<string, string>;
61
+ devDependencies: Record<string, string>;
62
+ }
63
+ export interface EnvVar {
64
+ name: string;
65
+ source: string;
66
+ hasDefault: boolean;
67
+ }
68
+ export interface MiddlewareInfo {
69
+ name: string;
70
+ file: string;
71
+ type: "auth" | "rate-limit" | "cors" | "validation" | "logging" | "error-handler" | "custom";
72
+ }
73
+ export interface ImportEdge {
74
+ from: string;
75
+ to: string;
76
+ }
77
+ export interface DependencyGraph {
78
+ edges: ImportEdge[];
79
+ hotFiles: {
80
+ file: string;
81
+ importedBy: number;
82
+ }[];
83
+ }
84
+ export interface ScanResult {
85
+ project: ProjectInfo;
86
+ routes: RouteInfo[];
87
+ schemas: SchemaModel[];
88
+ components: ComponentInfo[];
89
+ libs: LibExport[];
90
+ config: ConfigInfo;
91
+ middleware: MiddlewareInfo[];
92
+ graph: DependencyGraph;
93
+ tokenStats: TokenStats;
94
+ }
95
+ export interface TokenStats {
96
+ outputTokens: number;
97
+ estimatedExplorationTokens: number;
98
+ saved: number;
99
+ fileCount: number;
100
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "codesight",
3
+ "version": "1.0.0",
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
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "codesight": "dist/index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "prepublishOnly": "pnpm build"
14
+ },
15
+ "keywords": [
16
+ "ai",
17
+ "cli",
18
+ "context",
19
+ "codebase",
20
+ "claude",
21
+ "cursor",
22
+ "copilot",
23
+ "codex",
24
+ "windsurf",
25
+ "cline",
26
+ "developer-tools",
27
+ "code-analysis",
28
+ "llm",
29
+ "anthropic",
30
+ "openai",
31
+ "mcp",
32
+ "context-engineering",
33
+ "token-savings",
34
+ "repo-map"
35
+ ],
36
+ "author": "Houseofmvps",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/Houseofmvps/codesight"
41
+ },
42
+ "homepage": "https://github.com/Houseofmvps/codesight#readme",
43
+ "devDependencies": {
44
+ "typescript": "^5.7.0",
45
+ "tsx": "^4.19.0",
46
+ "@types/node": "^22.0.0"
47
+ },
48
+ "engines": {
49
+ "node": ">=18.0.0"
50
+ },
51
+ "files": [
52
+ "dist"
53
+ ]
54
+ }