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/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { calculateTokenStats } from "./detectors/tokens.js";
14
14
  import { writeOutput } from "./formatter.js";
15
15
  import { generateAIConfigs } from "./generators/ai-config.js";
16
16
  import { generateHtmlReport } from "./generators/html-report.js";
17
- const VERSION = "1.0.0";
17
+ const VERSION = "1.1.0";
18
18
  const BRAND = "codesight";
19
19
  function printHelp() {
20
20
  console.log(`
@@ -32,6 +32,7 @@ function printHelp() {
32
32
  --open Generate HTML report and open in browser
33
33
  --mcp Start as MCP server (for Claude Code, Cursor)
34
34
  --json Output JSON instead of markdown
35
+ --benchmark Show detailed token savings breakdown
35
36
  -v, --version Show version
36
37
  -h, --help Show this help
37
38
 
@@ -218,6 +219,7 @@ async function main() {
218
219
  let doHtml = false;
219
220
  let doOpen = false;
220
221
  let doMcp = false;
222
+ let doBenchmark = false;
221
223
  for (let i = 0; i < args.length; i++) {
222
224
  const arg = args[i];
223
225
  if ((arg === "-o" || arg === "--output") && args[i + 1]) {
@@ -248,6 +250,9 @@ async function main() {
248
250
  else if (arg === "--mcp") {
249
251
  doMcp = true;
250
252
  }
253
+ else if (arg === "--benchmark") {
254
+ doBenchmark = true;
255
+ }
251
256
  else if (!arg.startsWith("-")) {
252
257
  targetDir = resolve(arg);
253
258
  }
@@ -293,6 +298,37 @@ async function main() {
293
298
  console.log(" Opening in browser...");
294
299
  }
295
300
  }
301
+ // Benchmark output
302
+ if (doBenchmark) {
303
+ const ts = result.tokenStats;
304
+ const r = result;
305
+ console.log(`
306
+ Token Savings Breakdown:
307
+ ┌──────────────────────────────────────────────────┐
308
+ │ What codesight found │ Exploration cost │
309
+ ├──────────────────────────────┼────────────────────┤
310
+ │ ${String(r.routes.length).padStart(3)} routes │ ~${(r.routes.length * 400).toLocaleString().padStart(6)} tokens │
311
+ │ ${String(r.schemas.length).padStart(3)} schema models │ ~${(r.schemas.length * 300).toLocaleString().padStart(6)} tokens │
312
+ │ ${String(r.components.length).padStart(3)} components │ ~${(r.components.length * 250).toLocaleString().padStart(6)} tokens │
313
+ │ ${String(r.libs.length).padStart(3)} library files │ ~${(r.libs.length * 200).toLocaleString().padStart(6)} tokens │
314
+ │ ${String(r.config.envVars.length).padStart(3)} env vars │ ~${(r.config.envVars.length * 100).toLocaleString().padStart(6)} tokens │
315
+ │ ${String(r.middleware.length).padStart(3)} middleware │ ~${(r.middleware.length * 200).toLocaleString().padStart(6)} tokens │
316
+ │ ${String(r.graph.hotFiles.length).padStart(3)} hot files │ ~${(r.graph.hotFiles.length * 150).toLocaleString().padStart(6)} tokens │
317
+ │ ${String(ts.fileCount).padStart(3)} files (search overhead) │ ~${(Math.min(ts.fileCount, 50) * 80).toLocaleString().padStart(6)} tokens │
318
+ ├──────────────────────────────┼────────────────────┤
319
+ │ codesight output │ ~${ts.outputTokens.toLocaleString().padStart(6)} tokens │
320
+ │ Manual exploration (1.3x) │ ~${ts.estimatedExplorationTokens.toLocaleString().padStart(6)} tokens │
321
+ │ SAVED PER CONVERSATION │ ~${ts.saved.toLocaleString().padStart(6)} tokens │
322
+ └──────────────────────────────┴────────────────────┘
323
+
324
+ How this is calculated:
325
+ - Each route found saves ~400 tokens of file reading + grep exploration
326
+ - Each schema model saves ~300 tokens of migration/ORM file parsing
327
+ - Each component saves ~250 tokens of prop discovery
328
+ - Search overhead: AI typically runs ${Math.min(ts.fileCount, 50)} glob/grep operations
329
+ - 1.3x multiplier: AI revisits files during multi-turn exploration
330
+ `);
331
+ }
296
332
  // Watch mode (blocks)
297
333
  if (doWatch) {
298
334
  await watchMode(root, outputDirName, maxDepth);
package/dist/scanner.js CHANGED
@@ -35,6 +35,13 @@ const CODE_EXTENSIONS = new Set([
35
35
  ".go",
36
36
  ".vue",
37
37
  ".svelte",
38
+ ".rb",
39
+ ".ex",
40
+ ".exs",
41
+ ".java",
42
+ ".kt",
43
+ ".rs",
44
+ ".php",
38
45
  ]);
39
46
  export async function collectFiles(root, maxDepth = 10) {
40
47
  const files = [];
@@ -174,6 +181,27 @@ async function detectFrameworks(root, pkg) {
174
181
  // Koa
175
182
  if (deps["koa"])
176
183
  frameworks.push("koa");
184
+ // NestJS
185
+ if (deps["@nestjs/core"] || deps["@nestjs/common"])
186
+ frameworks.push("nestjs");
187
+ // Elysia (Bun)
188
+ if (deps["elysia"])
189
+ frameworks.push("elysia");
190
+ // AdonisJS
191
+ if (deps["@adonisjs/core"])
192
+ frameworks.push("adonis");
193
+ // tRPC
194
+ if (deps["@trpc/server"])
195
+ frameworks.push("trpc");
196
+ // SvelteKit
197
+ if (deps["@sveltejs/kit"])
198
+ frameworks.push("sveltekit");
199
+ // Remix
200
+ if (deps["@remix-run/node"] || deps["@remix-run/react"])
201
+ frameworks.push("remix");
202
+ // Nuxt
203
+ if (deps["nuxt"])
204
+ frameworks.push("nuxt");
177
205
  // Python frameworks - check for requirements.txt or pyproject.toml
178
206
  const pyDeps = await getPythonDeps(root);
179
207
  if (pyDeps.includes("flask"))
@@ -190,6 +218,59 @@ async function detectFrameworks(root, pkg) {
190
218
  frameworks.push("gin");
191
219
  if (goDeps.includes("gofiber/fiber"))
192
220
  frameworks.push("fiber");
221
+ if (goDeps.some((d) => d.includes("labstack/echo")))
222
+ frameworks.push("echo");
223
+ if (goDeps.some((d) => d.includes("go-chi/chi")))
224
+ frameworks.push("chi");
225
+ // Ruby on Rails
226
+ const hasGemfile = await fileExists(join(root, "Gemfile"));
227
+ if (hasGemfile) {
228
+ try {
229
+ const gemfile = await readFile(join(root, "Gemfile"), "utf-8");
230
+ if (gemfile.includes("rails"))
231
+ frameworks.push("rails");
232
+ }
233
+ catch { }
234
+ }
235
+ // Phoenix (Elixir)
236
+ const hasMixFile = await fileExists(join(root, "mix.exs"));
237
+ if (hasMixFile) {
238
+ try {
239
+ const mix = await readFile(join(root, "mix.exs"), "utf-8");
240
+ if (mix.includes("phoenix"))
241
+ frameworks.push("phoenix");
242
+ }
243
+ catch { }
244
+ }
245
+ // Spring Boot (Java/Kotlin)
246
+ const hasPomXml = await fileExists(join(root, "pom.xml"));
247
+ const hasBuildGradle = await fileExists(join(root, "build.gradle")) || await fileExists(join(root, "build.gradle.kts"));
248
+ if (hasPomXml || hasBuildGradle) {
249
+ try {
250
+ const buildFile = hasPomXml
251
+ ? await readFile(join(root, "pom.xml"), "utf-8")
252
+ : await readFile(join(root, hasBuildGradle ? "build.gradle.kts" : "build.gradle"), "utf-8");
253
+ if (buildFile.includes("spring"))
254
+ frameworks.push("spring");
255
+ }
256
+ catch { }
257
+ }
258
+ // Rust web frameworks
259
+ const hasCargoToml = await fileExists(join(root, "Cargo.toml"));
260
+ if (hasCargoToml) {
261
+ try {
262
+ const cargo = await readFile(join(root, "Cargo.toml"), "utf-8");
263
+ if (cargo.includes("actix-web"))
264
+ frameworks.push("actix");
265
+ else if (cargo.includes("axum"))
266
+ frameworks.push("axum");
267
+ }
268
+ catch { }
269
+ }
270
+ // Fallback: detect raw http.createServer if no other frameworks found
271
+ if (frameworks.length === 0) {
272
+ frameworks.push("raw-http");
273
+ }
193
274
  return frameworks;
194
275
  }
195
276
  async function detectORMs(root, pkg) {
@@ -201,12 +282,36 @@ async function detectORMs(root, pkg) {
201
282
  orms.push("prisma");
202
283
  if (deps["typeorm"])
203
284
  orms.push("typeorm");
285
+ if (deps["mongoose"])
286
+ orms.push("mongoose");
287
+ if (deps["sequelize"])
288
+ orms.push("sequelize");
204
289
  const pyDeps = await getPythonDeps(root);
205
290
  if (pyDeps.includes("sqlalchemy"))
206
291
  orms.push("sqlalchemy");
207
292
  const goDeps = await getGoDeps(root);
208
293
  if (goDeps.some((d) => d.includes("gorm")))
209
294
  orms.push("gorm");
295
+ // Rails ActiveRecord
296
+ const hasGemfile = await fileExists(join(root, "Gemfile"));
297
+ if (hasGemfile) {
298
+ try {
299
+ const gemfile = await readFile(join(root, "Gemfile"), "utf-8");
300
+ if (gemfile.includes("activerecord") || gemfile.includes("rails"))
301
+ orms.push("activerecord");
302
+ }
303
+ catch { }
304
+ }
305
+ // Phoenix Ecto
306
+ const hasMixFile = await fileExists(join(root, "mix.exs"));
307
+ if (hasMixFile) {
308
+ try {
309
+ const mix = await readFile(join(root, "mix.exs"), "utf-8");
310
+ if (mix.includes("ecto"))
311
+ orms.push("ecto");
312
+ }
313
+ catch { }
314
+ }
210
315
  return orms;
211
316
  }
212
317
  function detectComponentFramework(deps) {
@@ -223,6 +328,12 @@ async function detectLanguage(root, deps) {
223
328
  const hasPyProject = await fileExists(join(root, "pyproject.toml")) || await fileExists(join(root, "backend/pyproject.toml"));
224
329
  const hasGoMod = await fileExists(join(root, "go.mod"));
225
330
  const hasRequirements = await fileExists(join(root, "requirements.txt")) || await fileExists(join(root, "backend/requirements.txt"));
331
+ const hasGemfile = await fileExists(join(root, "Gemfile"));
332
+ const hasMixExs = await fileExists(join(root, "mix.exs"));
333
+ const hasPomXml = await fileExists(join(root, "pom.xml"));
334
+ const hasBuildGradle = await fileExists(join(root, "build.gradle")) || await fileExists(join(root, "build.gradle.kts"));
335
+ const hasCargoToml = await fileExists(join(root, "Cargo.toml"));
336
+ const hasComposerJson = await fileExists(join(root, "composer.json"));
226
337
  const langs = [];
227
338
  if (hasTsConfig || deps["typescript"])
228
339
  langs.push("typescript");
@@ -230,14 +341,22 @@ async function detectLanguage(root, deps) {
230
341
  langs.push("python");
231
342
  if (hasGoMod)
232
343
  langs.push("go");
344
+ if (hasGemfile)
345
+ langs.push("ruby");
346
+ if (hasMixExs)
347
+ langs.push("elixir");
348
+ if (hasBuildGradle)
349
+ langs.push("kotlin");
350
+ else if (hasPomXml)
351
+ langs.push("java");
352
+ if (hasCargoToml)
353
+ langs.push("rust");
354
+ if (hasComposerJson)
355
+ langs.push("php");
233
356
  if (langs.length > 1)
234
357
  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";
358
+ if (langs.length === 1)
359
+ return langs[0];
241
360
  return "javascript";
242
361
  }
243
362
  async function getWorkspacePatterns(root, pkg) {
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
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";
1
+ export type Framework = "next-app" | "next-pages" | "hono" | "express" | "fastify" | "koa" | "nestjs" | "elysia" | "adonis" | "trpc" | "sveltekit" | "remix" | "nuxt" | "flask" | "fastapi" | "django" | "go-net-http" | "gin" | "fiber" | "echo" | "chi" | "rails" | "phoenix" | "spring" | "actix" | "axum" | "raw-http" | "unknown";
2
+ export type ORM = "drizzle" | "prisma" | "typeorm" | "sqlalchemy" | "gorm" | "mongoose" | "sequelize" | "activerecord" | "ecto" | "unknown";
3
3
  export type ComponentFramework = "react" | "vue" | "svelte" | "unknown";
4
4
  export interface ProjectInfo {
5
5
  root: string;
@@ -9,7 +9,7 @@ export interface ProjectInfo {
9
9
  componentFramework: ComponentFramework;
10
10
  isMonorepo: boolean;
11
11
  workspaces: WorkspaceInfo[];
12
- language: "typescript" | "javascript" | "python" | "go" | "mixed";
12
+ language: "typescript" | "javascript" | "python" | "go" | "ruby" | "elixir" | "java" | "kotlin" | "rust" | "php" | "mixed";
13
13
  }
14
14
  export interface WorkspaceInfo {
15
15
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codesight",
3
- "version": "1.0.0",
3
+ "version": "1.1.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": {
@@ -10,6 +10,7 @@
10
10
  "scripts": {
11
11
  "build": "tsc",
12
12
  "dev": "tsx src/index.ts",
13
+ "test": "pnpm build && node --test tests/detectors.test.ts",
13
14
  "prepublishOnly": "pnpm build"
14
15
  },
15
16
  "keywords": [