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 +200 -104
- package/dist/detectors/contracts.js +7 -0
- package/dist/detectors/graph.js +87 -23
- package/dist/detectors/routes.js +519 -13
- package/dist/formatter.js +20 -7
- package/dist/index.js +37 -1
- package/dist/scanner.js +125 -6
- package/dist/types.d.ts +3 -3
- package/package.json +2 -1
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.
|
|
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
|
|
236
|
-
return
|
|
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.
|
|
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": [
|