codesight 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,113 +1,178 @@
1
- # codesight
1
+ <div align="center">
2
2
 
3
- See your codebase clearly. One command gives your AI assistant complete project understanding.
3
+ ### Your AI assistant wastes thousands of tokens every conversation just figuring out your project. codesight fixes that in one command.
4
+
5
+ **Zero dependencies. 25+ framework detectors. 4 ORM parsers. MCP server. One `npx` call.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/codesight?style=for-the-badge&logo=npm&color=CB3837)](https://www.npmjs.com/package/codesight)
8
+ [![npm downloads](https://img.shields.io/npm/dm/codesight?style=for-the-badge&logo=npm&color=blue&label=Monthly%20Downloads)](https://www.npmjs.com/package/codesight)
9
+ [![npm total](https://img.shields.io/npm/dt/codesight?style=for-the-badge&logo=npm&color=cyan&label=Total%20Downloads)](https://www.npmjs.com/package/codesight)
10
+ [![GitHub stars](https://img.shields.io/github/stars/Houseofmvps/codesight?style=for-the-badge&logo=github&color=gold)](https://github.com/Houseofmvps/codesight/stargazers)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge&logo=opensourceinitiative)](LICENSE)
12
+ [![Sponsor](https://img.shields.io/badge/Sponsor-EA4AAA?style=for-the-badge&logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Houseofmvps)
13
+
14
+ ---
15
+
16
+ [![Follow @kaileskkhumar](https://img.shields.io/badge/Follow%20%40kaileskkhumar-000000?style=for-the-badge&logo=x&logoColor=white)](https://x.com/kaileskkhumar)
17
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-Connect-0A66C2?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/in/kailesk-khumar)
18
+ [![houseofmvps.com](https://img.shields.io/badge/houseofmvps.com-Website-green?style=for-the-badge&logo=google-chrome&logoColor=white)](https://houseofmvps.com)
19
+
20
+ **Built by [Kailesk Khumar](https://www.linkedin.com/in/kailesk-khumar), solo founder of [houseofmvps.com](https://houseofmvps.com)**
21
+
22
+ *Also: [ultraship](https://github.com/Houseofmvps/ultraship) (39 expert skills for Claude Code) · [claude-rank](https://github.com/Houseofmvps/claude-rank) (SEO/GEO/AEO plugin for Claude Code)*
23
+
24
+ </div>
25
+
26
+ ---
4
27
 
5
- ```bash
6
- npx codesight
28
+ ```
29
+ 0 dependencies · Node.js >= 18 · 27 tests · MIT
7
30
  ```
8
31
 
9
- **Works with Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Windsurf, Cline, and any AI coding tool.**
32
+ ## Works With
10
33
 
11
- ## The Problem
34
+ **Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Windsurf, Cline, Aider**, and anything that reads markdown.
12
35
 
13
- Every AI coding conversation starts the same way: your assistant burns thousands of tokens exploring files, grepping for patterns, and reading configs just to understand your project. On a 65-route Hono API with 18 Drizzle models, that costs **~68,000 tokens per conversation** in exploration alone.
36
+ ## Install
14
37
 
15
- codesight pre-generates that understanding into ~4,000 tokens of structured context. **Your AI starts every conversation already knowing your routes, schema, components, dependencies, and architecture.**
38
+ ```bash
39
+ npx codesight
40
+ ```
16
41
 
17
- ## Quick Start
42
+ That's it. Run it in any project root. No config, no setup, no API keys.
18
43
 
19
44
  ```bash
20
- npx codesight # Scan and generate context
21
45
  npx codesight --init # Also generate CLAUDE.md, .cursorrules, codex.md, AGENTS.md
22
46
  npx codesight --open # Also open interactive HTML report in browser
47
+ npx codesight --mcp # Start as MCP server for Claude Code / Cursor
48
+ npx codesight --benchmark # Show detailed token savings breakdown
49
+ ```
50
+
51
+ ## What It Does
52
+
53
+ Every AI coding conversation starts the same way. Your assistant reads files, greps for patterns, opens configs, just to understand the project. That exploration costs tens of thousands of tokens before it writes a single line of code.
54
+
55
+ codesight scans your codebase once and generates a structured context map. Routes, database schema, components, dependencies, environment variables, middleware, all condensed into ~3,000 to 5,000 tokens of structured markdown. Your AI reads one file and knows the entire project.
56
+
57
+ ```
58
+ Output size: ~3,200 tokens
59
+ Exploration cost: ~52,000 tokens (without codesight)
60
+ Saved: ~48,800 tokens per conversation
23
61
  ```
24
62
 
25
63
  ## What It Generates
26
64
 
27
65
  ```
28
66
  .codesight/
29
- CODESIGHT.md # Combined AI context map (point your assistant here)
30
- routes.md # API routes with methods, params, request/response types, tags
31
- schema.md # Database models with fields, types, PKs, FKs, relations
32
- components.md # UI components with props (shadcn/radix filtered out)
33
- libs.md # Library exports with function signatures
34
- config.md # Env vars (required vs default), config files, key deps
35
- middleware.md # Auth, rate limiting, CORS, validation, logging
36
- graph.md # Dependency graph: most-imported files + import map
37
- report.html # Interactive visual report (with --html or --open)
67
+ CODESIGHT.md Combined context map (one file, full project understanding)
68
+ routes.md Every API route with method, path, params, and what it touches
69
+ schema.md Every database model with fields, types, keys, and relations
70
+ components.md Every UI component with its props
71
+ libs.md Every library export with function signatures
72
+ config.md Every env var (required vs default), config files, key deps
73
+ middleware.md Auth, rate limiting, CORS, validation, logging, error handlers
74
+ graph.md Which files import what and which break the most things if changed
75
+ report.html Interactive visual dashboard (with --html or --open)
38
76
  ```
39
77
 
40
- ## Real Output Example
78
+ ## Routes
41
79
 
42
- From a production SaaS monorepo (Hono + Drizzle + React):
80
+ Not just paths. Methods, URL parameters, what each route touches (auth, database, cache, payments, AI, email, queues), and where the handler lives. Detects routes across 25+ frameworks automatically.
43
81
 
44
82
  ```markdown
45
- # savemrr AI Context Map
46
-
47
- > **Stack:** hono | drizzle | react | typescript
48
- > **Monorepo:** @savemrr/api, @savemrr/dashboard, @savemrr/widget, @savemrr/shared
49
-
50
- > 65 routes | 18 models | 16 components | 36 lib files | 22 env vars | 5 middleware | 53 import links
51
- > **Token savings:** this file is ~4,041 tokens. Without it, AI exploration would cost ~68,640 tokens.
52
- > **Saves ~64,599 tokens per conversation.**
53
-
54
- ---
55
-
56
- # Routes
83
+ - `POST` `/auth/login` [auth, db, email]
84
+ - `GET` `/api/projects/:id/analytics` params(id) [auth, db, cache]
85
+ - `POST` `/api/billing/checkout` [auth, db, payment]
86
+ - `QUERY` `getUsers` [db] # tRPC procedures
87
+ - `MUTATION` `createProject` [db, ai] # tRPC mutations
88
+ ```
57
89
 
58
- - `POST` `/magic-link` [auth, db, cache, email]
59
- - `POST` `/verify` [auth, db, cache, email]
60
- - `GET` `/me` [auth, db, cache, email]
61
- - `GET` `/overview` [auth, db, queue, payment, ai]
62
- - `GET` `/shield` [auth, db, queue, payment, ai]
63
- - `GET` `/rescue` [auth, db, queue, payment, ai]
64
- - `POST` `/rescue/:id/send-now` params(id) [auth, db, queue, payment, ai]
65
- ...
90
+ ## Schema
66
91
 
67
- # Schema
92
+ Models, fields, types, primary keys, foreign keys, unique constraints, relations. Parsed directly from your ORM definitions. No need to open migration files.
68
93
 
94
+ ```markdown
69
95
  ### users
70
96
  - id: uuid (pk, default)
71
97
  - email: text (unique, required)
72
- - tier: text (required, default)
73
- - polarSubId: text (fk)
74
- - settings: jsonb (required, default)
98
+ - plan: text (required, default)
99
+ - stripeCustomerId: text (fk)
75
100
 
76
- ### stripe_connections
101
+ ### projects
77
102
  - id: uuid (pk, default)
78
103
  - userId: uuid (fk)
79
- ...
104
+ - name: text (required)
105
+ - domain: text (unique)
106
+ - _relations_: userId -> users.id
107
+ ```
108
+
109
+ ## Dependency Graph
80
110
 
81
- # Dependency Graph
111
+ The files imported the most are the ones that break the most things when changed. codesight finds them and tells your AI to be careful.
82
112
 
113
+ ```markdown
83
114
  ## Most Imported Files (change these carefully)
84
- - `packages/shared/src/index.ts` — imported by **12** files
85
- - `apps/api/src/lib/db.ts` — imported by **8** files
86
- - `apps/api/src/lib/auth.ts` — imported by **6** files
115
+ - `packages/shared/src/index.ts` — imported by **14** files
116
+ - `apps/api/src/lib/db.ts` — imported by **9** files
117
+ - `apps/api/src/lib/auth.ts` — imported by **7** files
118
+ ```
119
+
120
+ ## Environment Audit
121
+
122
+ Every env var across your codebase, flagged as required or has default, with the exact file where it is referenced.
123
+
124
+ ```markdown
125
+ - `DATABASE_URL` **required** — apps/api/src/lib/db.ts
126
+ - `JWT_SECRET` **required** — apps/api/src/lib/auth.ts
127
+ - `PORT` (has default) — apps/api/src/index.ts
128
+ ```
129
+
130
+ ## Token Benchmark
131
+
132
+ See exactly where your token savings come from:
133
+
134
+ ```bash
135
+ npx codesight --benchmark
136
+ ```
137
+
138
+ ```
139
+ Token Savings Breakdown:
140
+ ┌──────────────────────────────────────────────────┐
141
+ │ What codesight found │ Exploration cost │
142
+ ├──────────────────────────────┼────────────────────┤
143
+ │ 65 routes │ ~26,000 tokens │
144
+ │ 18 schema models │ ~ 5,400 tokens │
145
+ │ 16 components │ ~ 4,000 tokens │
146
+ │ 36 library files │ ~ 7,200 tokens │
147
+ │ 22 env vars │ ~ 2,200 tokens │
148
+ │ 92 files (search overhead) │ ~ 4,000 tokens │
149
+ ├──────────────────────────────┼────────────────────┤
150
+ │ codesight output │ ~ 4,041 tokens │
151
+ │ SAVED PER CONVERSATION │ ~64,599 tokens │
152
+ └──────────────────────────────┴────────────────────┘
87
153
  ```
88
154
 
89
- ## What It Detects
155
+ ## Supported Stacks
90
156
 
91
157
  | Category | Supported |
92
158
  |---|---|
93
- | **Routes** | Hono, Express, Fastify, Next.js (App + Pages), Koa, FastAPI, Flask, Django, Go (net/http, Gin, Fiber) |
94
- | **Schema** | Drizzle, Prisma, TypeORM, SQLAlchemy |
95
- | **Components** | React, Vue, Svelte (filters out shadcn/radix primitives) |
96
- | **Libraries** | TypeScript/JavaScript, Python, Go exports with function signatures |
97
- | **Config** | Environment variables (required vs defaults), config files, notable dependencies |
159
+ | **Routes** | Hono, Express, Fastify, Next.js (App + Pages), Koa, NestJS, tRPC, Elysia, AdonisJS, SvelteKit, Remix, Nuxt, FastAPI, Flask, Django, Go (net/http, Gin, Fiber, Echo, Chi), Rails, Phoenix, Spring Boot, Actix, Axum, raw http.createServer |
160
+ | **Schema** | Drizzle, Prisma, TypeORM, Mongoose, Sequelize, SQLAlchemy, ActiveRecord, Ecto |
161
+ | **Components** | React, Vue, Svelte (auto-filters shadcn/ui and Radix primitives) |
162
+ | **Libraries** | TypeScript, JavaScript, Python, Go, Ruby, Elixir, Java, Kotlin, Rust (exports with function signatures) |
98
163
  | **Middleware** | Auth, rate limiting, CORS, validation, logging, error handlers |
99
164
  | **Dependencies** | Import graph with hot file detection (most imported = highest blast radius) |
100
- | **Contracts** | URL params, request types, response types extracted from route handlers |
101
- | **Monorepos** | pnpm, npm, yarn workspaces with cross-workspace detection |
102
- | **Languages** | TypeScript, JavaScript, Python, Go |
165
+ | **Contracts** | URL params, request types, response types from route handlers |
166
+ | **Monorepos** | pnpm, npm, yarn workspaces (cross-workspace detection) |
167
+ | **Languages** | TypeScript, JavaScript, Python, Go, Ruby, Elixir, Java, Kotlin, Rust, PHP |
103
168
 
104
- ## Auto-Generate AI Config Files
169
+ ## AI Config Generation
105
170
 
106
171
  ```bash
107
172
  npx codesight --init
108
173
  ```
109
174
 
110
- Generates instruction files for every major AI coding tool:
175
+ Generates ready-to-use instruction files for every major AI coding tool at once:
111
176
 
112
177
  | File | Tool |
113
178
  |---|---|
@@ -115,25 +180,9 @@ Generates instruction files for every major AI coding tool:
115
180
  | `.cursorrules` | Cursor |
116
181
  | `.github/copilot-instructions.md` | GitHub Copilot |
117
182
  | `codex.md` | OpenAI Codex CLI |
118
- | `AGENTS.md` | OpenAI Codex |
119
-
120
- Each file includes your project's stack, key architecture facts, hot files, and required env vars so your AI assistant knows the project from the first message.
183
+ | `AGENTS.md` | OpenAI Codex agents |
121
184
 
122
- ## Interactive HTML Report
123
-
124
- ```bash
125
- npx codesight --open
126
- ```
127
-
128
- Generates a visual dashboard with:
129
- - Token savings hero metric
130
- - Route table with methods, contracts, and tags
131
- - Schema cards with fields and relations
132
- - Dependency hot files with impact bars
133
- - Environment variables (required vs defaults)
134
- - Full middleware map
135
-
136
- Screenshots of this report are what go viral on Twitter.
185
+ Each file is pre-filled with your project's stack, architecture, high-impact files, and required env vars. Your AI reads it on startup and starts with full context from the first message.
137
186
 
138
187
  ## MCP Server
139
188
 
@@ -141,7 +190,7 @@ Screenshots of this report are what go viral on Twitter.
141
190
  npx codesight --mcp
142
191
  ```
143
192
 
144
- Runs as a Model Context Protocol server that Claude Code and Cursor can connect to. Add to your MCP config:
193
+ Runs as a Model Context Protocol server. Claude Code and Cursor call it directly to get project context on demand.
145
194
 
146
195
  ```json
147
196
  {
@@ -154,23 +203,50 @@ Runs as a Model Context Protocol server that Claude Code and Cursor can connect
154
203
  }
155
204
  ```
156
205
 
157
- Your AI assistant can then call the `codesight_scan` tool to get full project context on demand.
206
+ Exposes one tool: `codesight_scan`. Your AI calls it whenever it needs to understand the project.
158
207
 
159
- ## Watch Mode
208
+ ## Visual Report
160
209
 
161
210
  ```bash
162
- npx codesight --watch
211
+ npx codesight --open
212
+ ```
213
+
214
+ Opens an interactive HTML dashboard in your browser. Routes table with method badges and tags. Schema cards with fields and relations. Dependency hot files with impact bars. Env var audit. Token savings breakdown. Useful for onboarding or just seeing your project from above.
215
+
216
+ ## GitHub Action
217
+
218
+ Add to your CI pipeline to keep context fresh on every push:
219
+
220
+ ```yaml
221
+ name: codesight
222
+ on: [push]
223
+ jobs:
224
+ scan:
225
+ runs-on: ubuntu-latest
226
+ steps:
227
+ - uses: actions/checkout@v4
228
+ - run: npx codesight
229
+ - uses: actions/upload-artifact@v4
230
+ with:
231
+ name: codesight
232
+ path: .codesight/
163
233
  ```
164
234
 
165
- Re-scans automatically when files change. Keeps context fresh during development.
235
+ ## Watch Mode and Git Hook
166
236
 
167
- ## Git Pre-Commit Hook
237
+ **Watch mode** re-scans when files change:
238
+
239
+ ```bash
240
+ npx codesight --watch
241
+ ```
242
+
243
+ **Git hook** regenerates context on every commit:
168
244
 
169
245
  ```bash
170
246
  npx codesight --hook
171
247
  ```
172
248
 
173
- Installs a git pre-commit hook that regenerates context on every commit. Context stays up to date automatically.
249
+ Context stays fresh without thinking about it.
174
250
 
175
251
  ## All Options
176
252
 
@@ -178,36 +254,56 @@ Installs a git pre-commit hook that regenerates context on every commit. Context
178
254
  npx codesight # Scan current directory
179
255
  npx codesight ./my-project # Scan specific directory
180
256
  npx codesight --init # Generate AI config files
181
- npx codesight --open # Open interactive HTML report
182
- npx codesight --html # Generate HTML report (no open)
257
+ npx codesight --open # Open visual HTML report
258
+ npx codesight --html # Generate HTML report without opening
183
259
  npx codesight --mcp # Start MCP server
184
260
  npx codesight --watch # Watch mode
185
261
  npx codesight --hook # Install git pre-commit hook
186
- npx codesight --json # Output JSON
262
+ npx codesight --benchmark # Detailed token savings breakdown
263
+ npx codesight --json # Output as JSON
187
264
  npx codesight -o .ai-context # Custom output directory
188
265
  npx codesight -d 5 # Limit directory depth
189
266
  ```
190
267
 
191
- ## Why Not Repomix?
268
+ ## How It Compares
192
269
 
193
- Repomix dumps your entire codebase into one file. codesight maps your architecture.
270
+ Most AI context tools dump your entire codebase into one file. codesight takes a different approach: it **parses** your code to extract structured information.
194
271
 
195
- | | Repomix | codesight |
272
+ | | codesight | File concatenation tools |
196
273
  |---|---|---|
197
- | **Approach** | Raw code dump | Structured intelligence |
198
- | **Output** | One giant text blob | Semantic context files |
199
- | **AI gets** | "Here is all the code" | "Here is the architecture" |
200
- | **Token cost** | Huge (entire codebase) | Tiny (~4K tokens for full map) |
201
- | **Route discovery** | Read every file | Instant from routes.md |
202
- | **Schema understanding** | Read every migration | Instant from schema.md |
203
- | **Change blast radius** | Unknown | Visible in dependency graph |
204
- | **AI config generation** | No | CLAUDE.md, .cursorrules, codex.md, AGENTS.md |
205
- | **Runtime deps** | 26 | **Zero** |
274
+ | **Output** | Structured routes, schema, components, deps | Raw file contents |
275
+ | **Token cost** | ~3,000-5,000 tokens | 50,000-500,000+ tokens |
276
+ | **Route detection** | 25+ frameworks auto-detected | None |
277
+ | **Schema parsing** | ORM-aware with relations | None |
278
+ | **Dependency graph** | Hot file detection | None |
279
+ | **AI config generation** | CLAUDE.md, .cursorrules, etc. | None |
280
+ | **MCP server** | Built-in | Varies |
281
+ | **Dependencies** | Zero | Varies |
206
282
 
207
- ## Zero Dependencies
283
+ ## Contributing
208
284
 
209
- codesight has zero runtime dependencies. Just Node.js built-ins. Fast, portable, no supply chain risk.
285
+ ```bash
286
+ git clone https://github.com/Houseofmvps/codesight.git
287
+ cd codesight
288
+ pnpm install
289
+ pnpm dev # Run locally
290
+ pnpm build # Compile TypeScript
291
+ pnpm test # Run 27 tests
292
+ ```
293
+
294
+ PRs welcome. Open an issue first for large changes.
210
295
 
211
296
  ## License
212
297
 
213
298
  MIT
299
+
300
+ ---
301
+
302
+ <div align="center">
303
+
304
+ If codesight saves you tokens, [star it on GitHub](https://github.com/Houseofmvps/codesight) so others find it too.
305
+
306
+ [![GitHub stars](https://img.shields.io/github/stars/Houseofmvps/codesight?style=for-the-badge&logo=github&color=gold)](https://github.com/Houseofmvps/codesight/stargazers)
307
+ [![Sponsor](https://img.shields.io/badge/Sponsor-EA4AAA?style=for-the-badge&logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Houseofmvps)
308
+
309
+ </div>
@@ -36,9 +36,16 @@ export async function enrichRouteContracts(routes, project) {
36
36
  case "express":
37
37
  case "fastify":
38
38
  case "koa":
39
+ case "nestjs":
40
+ case "elysia":
41
+ case "adonis":
42
+ case "raw-http":
39
43
  enrichTSRoute(route, content);
40
44
  break;
41
45
  case "next-app":
46
+ case "sveltekit":
47
+ case "remix":
48
+ case "nuxt":
42
49
  enrichNextRoute(route, content);
43
50
  break;
44
51
  case "fastapi":
@@ -3,7 +3,15 @@ import { readFileSafe } from "../scanner.js";
3
3
  export async function detectDependencyGraph(files, project) {
4
4
  const edges = [];
5
5
  const importCount = new Map();
6
- const codeFiles = files.filter((f) => f.match(/\.(ts|tsx|js|jsx|mjs|py|go)$/));
6
+ const codeFiles = files.filter((f) => f.match(/\.(ts|tsx|js|jsx|mjs|py|go|rb|ex|exs|java|kt|rs|php)$/));
7
+ // Build a lookup map for faster resolution: relative path -> true
8
+ const relPathSet = new Set();
9
+ const relPaths = [];
10
+ for (const file of files) {
11
+ const rel = relative(project.root, file);
12
+ relPathSet.add(rel);
13
+ relPaths.push(rel);
14
+ }
7
15
  for (const file of codeFiles) {
8
16
  const content = await readFileSafe(file);
9
17
  if (!content)
@@ -16,8 +24,20 @@ export async function detectDependencyGraph(files, project) {
16
24
  else if (ext === ".go") {
17
25
  extractGoImports(content, rel, edges, importCount);
18
26
  }
27
+ else if (ext === ".rb") {
28
+ extractRubyImports(content, rel, edges, importCount);
29
+ }
30
+ else if (ext === ".ex" || ext === ".exs") {
31
+ extractElixirImports(content, rel, edges, importCount);
32
+ }
33
+ else if (ext === ".java" || ext === ".kt") {
34
+ extractJavaImports(content, rel, edges, importCount, relPaths);
35
+ }
36
+ else if (ext === ".rs") {
37
+ extractRustImports(content, rel, edges, importCount);
38
+ }
19
39
  else {
20
- extractTSImports(content, rel, file, project, files, edges, importCount);
40
+ extractTSImports(content, rel, file, project, relPathSet, edges, importCount);
21
41
  }
22
42
  }
23
43
  // Sort by most imported
@@ -27,7 +47,7 @@ export async function detectDependencyGraph(files, project) {
27
47
  .slice(0, 20);
28
48
  return { edges, hotFiles };
29
49
  }
30
- function extractTSImports(content, rel, absPath, project, allFiles, edges, importCount) {
50
+ function extractTSImports(content, rel, absPath, project, relPathSet, edges, importCount) {
31
51
  // Match: import ... from "./path" or import("./path") or require("./path")
32
52
  const patterns = [
33
53
  /(?:import|export)\s+.*?from\s+['"]([^'"]+)['"]/g,
@@ -50,8 +70,10 @@ function extractTSImports(content, rel, absPath, project, allFiles, edges, impor
50
70
  const dir = dirname(absPath);
51
71
  resolvedPath = relative(project.root, resolve(dir, importPath));
52
72
  }
53
- // Strip extension and try to find the actual file
54
- const normalized = normalizeImportPath(resolvedPath, allFiles, project.root);
73
+ // Strip .js/.mjs extension that TypeScript adds for ESM compatibility
74
+ // e.g., import { foo } from "./bar.js" actually refers to ./bar.ts
75
+ const stripped = resolvedPath.replace(/\.(js|mjs|cjs)$/, "");
76
+ const normalized = normalizeImportPath(stripped, relPathSet);
55
77
  if (normalized && normalized !== rel) {
56
78
  edges.push({ from: rel, to: normalized });
57
79
  importCount.set(normalized, (importCount.get(normalized) || 0) + 1);
@@ -70,11 +92,9 @@ function extractPythonImports(content, rel, edges, importCount) {
70
92
  }
71
93
  }
72
94
  function extractGoImports(content, rel, edges, importCount) {
73
- // Go doesn't have relative imports in the same way, but we can track internal package imports
74
95
  const importBlock = content.match(/import\s*\(([\s\S]*?)\)/);
75
96
  if (!importBlock)
76
97
  return;
77
- // Look for internal package paths (not standard library)
78
98
  const lines = importBlock[1].split("\n");
79
99
  for (const line of lines) {
80
100
  const pathMatch = line.match(/["']([^"']+)["']/);
@@ -85,29 +105,73 @@ function extractGoImports(content, rel, edges, importCount) {
85
105
  }
86
106
  }
87
107
  }
88
- function normalizeImportPath(importPath, allFiles, root) {
89
- // Try exact match first
90
- for (const file of allFiles) {
91
- const rel = relative(root, file);
92
- if (rel === importPath)
93
- return rel;
108
+ function extractRubyImports(content, rel, edges, importCount) {
109
+ // require_relative "./path"
110
+ const pattern = /require_relative\s+['"]([^'"]+)['"]/g;
111
+ let match;
112
+ while ((match = pattern.exec(content)) !== null) {
113
+ const target = match[1].replace(/^\.\//, "") + ".rb";
114
+ edges.push({ from: rel, to: target });
115
+ importCount.set(target, (importCount.get(target) || 0) + 1);
116
+ }
117
+ }
118
+ function extractElixirImports(content, rel, edges, importCount) {
119
+ // alias MyApp.Accounts.User
120
+ const pattern = /(?:alias|import|use)\s+([\w.]+)/g;
121
+ let match;
122
+ while ((match = pattern.exec(content)) !== null) {
123
+ const mod = match[1];
124
+ // Convert module path to potential file: MyApp.Accounts.User -> lib/my_app/accounts/user.ex
125
+ if (mod.includes(".") && !mod.startsWith("Ecto") && !mod.startsWith("Phoenix") && !mod.startsWith("Plug")) {
126
+ const target = "lib/" + mod.split(".").map(s => s.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "")).join("/") + ".ex";
127
+ edges.push({ from: rel, to: target });
128
+ importCount.set(target, (importCount.get(target) || 0) + 1);
129
+ }
130
+ }
131
+ }
132
+ function extractJavaImports(content, rel, edges, importCount, relPaths) {
133
+ // import com.myapp.service.UserService;
134
+ const pattern = /^import\s+([\w.]+);/gm;
135
+ let match;
136
+ while ((match = pattern.exec(content)) !== null) {
137
+ const imp = match[1];
138
+ // Skip standard library and common third-party
139
+ if (imp.startsWith("java.") || imp.startsWith("javax.") || imp.startsWith("org.springframework") || imp.startsWith("org.apache"))
140
+ continue;
141
+ // Convert to path pattern: com.myapp.service.UserService -> UserService
142
+ const className = imp.split(".").pop();
143
+ const found = relPaths.find(p => p.endsWith(`/${className}.java`) || p.endsWith(`/${className}.kt`));
144
+ if (found && found !== rel) {
145
+ edges.push({ from: rel, to: found });
146
+ importCount.set(found, (importCount.get(found) || 0) + 1);
147
+ }
94
148
  }
149
+ }
150
+ function extractRustImports(content, rel, edges, importCount) {
151
+ // mod my_module; or use crate::my_module::something;
152
+ const modPattern = /^mod\s+(\w+)\s*;/gm;
153
+ let match;
154
+ while ((match = modPattern.exec(content)) !== null) {
155
+ const dir = dirname(rel);
156
+ const target = dir === "." ? `${match[1]}.rs` : `${dir}/${match[1]}.rs`;
157
+ edges.push({ from: rel, to: target });
158
+ importCount.set(target, (importCount.get(target) || 0) + 1);
159
+ }
160
+ }
161
+ function normalizeImportPath(importPath, relPathSet) {
162
+ // Try exact match first
163
+ if (relPathSet.has(importPath))
164
+ return importPath;
95
165
  // Try with extensions
96
166
  const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
97
167
  for (const ext of extensions) {
98
- for (const file of allFiles) {
99
- const rel = relative(root, file);
100
- if (rel === importPath + ext)
101
- return rel;
102
- }
168
+ if (relPathSet.has(importPath + ext))
169
+ return importPath + ext;
103
170
  }
104
171
  // Try index files
105
172
  for (const ext of extensions) {
106
- for (const file of allFiles) {
107
- const rel = relative(root, file);
108
- if (rel === importPath + "/index" + ext)
109
- return rel;
110
- }
173
+ if (relPathSet.has(importPath + "/index" + ext))
174
+ return importPath + "/index" + ext;
111
175
  }
112
176
  return null;
113
177
  }