milens 0.2.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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/dist/analyzer/engine.d.ts +11 -0
  4. package/dist/analyzer/engine.d.ts.map +1 -0
  5. package/dist/analyzer/engine.js +163 -0
  6. package/dist/analyzer/engine.js.map +1 -0
  7. package/dist/analyzer/resolver.d.ts +12 -0
  8. package/dist/analyzer/resolver.d.ts.map +1 -0
  9. package/dist/analyzer/resolver.js +119 -0
  10. package/dist/analyzer/resolver.js.map +1 -0
  11. package/dist/analyzer/scanner.d.ts +6 -0
  12. package/dist/analyzer/scanner.d.ts.map +1 -0
  13. package/dist/analyzer/scanner.js +73 -0
  14. package/dist/analyzer/scanner.js.map +1 -0
  15. package/dist/cli.d.ts +3 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +269 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/parser/extract.d.ts +24 -0
  20. package/dist/parser/extract.d.ts.map +1 -0
  21. package/dist/parser/extract.js +239 -0
  22. package/dist/parser/extract.js.map +1 -0
  23. package/dist/parser/lang-go.d.ts +4 -0
  24. package/dist/parser/lang-go.d.ts.map +1 -0
  25. package/dist/parser/lang-go.js +45 -0
  26. package/dist/parser/lang-go.js.map +1 -0
  27. package/dist/parser/lang-java.d.ts +4 -0
  28. package/dist/parser/lang-java.d.ts.map +1 -0
  29. package/dist/parser/lang-java.js +46 -0
  30. package/dist/parser/lang-java.js.map +1 -0
  31. package/dist/parser/lang-js.d.ts +4 -0
  32. package/dist/parser/lang-js.d.ts.map +1 -0
  33. package/dist/parser/lang-js.js +64 -0
  34. package/dist/parser/lang-js.js.map +1 -0
  35. package/dist/parser/lang-php.d.ts +4 -0
  36. package/dist/parser/lang-php.d.ts.map +1 -0
  37. package/dist/parser/lang-php.js +54 -0
  38. package/dist/parser/lang-php.js.map +1 -0
  39. package/dist/parser/lang-py.d.ts +4 -0
  40. package/dist/parser/lang-py.d.ts.map +1 -0
  41. package/dist/parser/lang-py.js +46 -0
  42. package/dist/parser/lang-py.js.map +1 -0
  43. package/dist/parser/lang-rust.d.ts +4 -0
  44. package/dist/parser/lang-rust.d.ts.map +1 -0
  45. package/dist/parser/lang-rust.js +54 -0
  46. package/dist/parser/lang-rust.js.map +1 -0
  47. package/dist/parser/lang-ts.d.ts +4 -0
  48. package/dist/parser/lang-ts.d.ts.map +1 -0
  49. package/dist/parser/lang-ts.js +88 -0
  50. package/dist/parser/lang-ts.js.map +1 -0
  51. package/dist/parser/lang-vue.d.ts +12 -0
  52. package/dist/parser/lang-vue.d.ts.map +1 -0
  53. package/dist/parser/lang-vue.js +28 -0
  54. package/dist/parser/lang-vue.js.map +1 -0
  55. package/dist/parser/languages.d.ts +6 -0
  56. package/dist/parser/languages.d.ts.map +1 -0
  57. package/dist/parser/languages.js +24 -0
  58. package/dist/parser/languages.js.map +1 -0
  59. package/dist/parser/loader.d.ts +5 -0
  60. package/dist/parser/loader.d.ts.map +1 -0
  61. package/dist/parser/loader.js +37 -0
  62. package/dist/parser/loader.js.map +1 -0
  63. package/dist/server/mcp.d.ts +5 -0
  64. package/dist/server/mcp.d.ts.map +1 -0
  65. package/dist/server/mcp.js +355 -0
  66. package/dist/server/mcp.js.map +1 -0
  67. package/dist/skills.d.ts +8 -0
  68. package/dist/skills.d.ts.map +1 -0
  69. package/dist/skills.js +178 -0
  70. package/dist/skills.js.map +1 -0
  71. package/dist/store/db.d.ts +59 -0
  72. package/dist/store/db.d.ts.map +1 -0
  73. package/dist/store/db.js +260 -0
  74. package/dist/store/db.js.map +1 -0
  75. package/dist/store/registry.d.ts +13 -0
  76. package/dist/store/registry.d.ts.map +1 -0
  77. package/dist/store/registry.js +69 -0
  78. package/dist/store/registry.js.map +1 -0
  79. package/dist/store/schema.sql +60 -0
  80. package/dist/types.d.ts +67 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +3 -0
  83. package/dist/types.js.map +1 -0
  84. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 milens contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ <p align="center">
2
+ <strong>milens</strong><br>
3
+ <em>Lightweight Code Intelligence Engine</em>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="#features">Features</a> •
8
+ <a href="#quick-start">Quick Start</a> •
9
+ <a href="#cli-commands">CLI</a> •
10
+ <a href="#mcp-server">MCP Server</a> •
11
+ <a href="#architecture">Architecture</a> •
12
+ <a href="#adding-a-language">Extend</a>
13
+ </p>
14
+
15
+ ---
16
+
17
+ Parse codebases into **knowledge graphs** — symbols, imports, calls, inheritance — and serve them to **AI agents** via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).
18
+
19
+ ## Features
20
+
21
+ - **8 languages** — TypeScript, JavaScript, Python, Java, Go, Rust, PHP, Vue
22
+ - **Declarative grammars** — add a new language by writing a config object, not extraction code
23
+ - **SQLite + FTS5** — full-text symbol search + recursive CTE graph traversal
24
+ - **Token-compact MCP** — 4 tools with minimal output, saving 40-60% tokens for AI agents
25
+ - **Incremental indexing** — file-hash based, only re-parses changed files
26
+ - **Multi-repo registry** — manage multiple codebases from `~/.milens/`
27
+ - **Dual transport** — MCP over stdio (VS Code / Cursor) or HTTP (remote agents)
28
+
29
+ ## Quick Start
30
+
31
+ ```bash
32
+ # Install dependencies
33
+ npm install
34
+
35
+ # Index the current project
36
+ npx tsx src/cli.ts analyze -p . --verbose
37
+
38
+ # Search for symbols
39
+ npx tsx src/cli.ts search "UserService"
40
+
41
+ # Start MCP server for AI agents
42
+ npx tsx src/cli.ts serve --http --port 3100
43
+ ```
44
+
45
+ ## CLI Commands
46
+
47
+ ### `analyze` — Index a codebase
48
+
49
+ ```bash
50
+ milens analyze -p /path/to/repo --verbose --force
51
+ ```
52
+
53
+ Scans source files, parses symbols using tree-sitter, resolves imports/calls/inheritance, and stores everything in a local SQLite database at `.milens/milens.db`.
54
+
55
+ | Flag | Description |
56
+ |---|---|
57
+ | `-p, --path` | Repository root (default: `.`) |
58
+ | `-o, --output` | Custom output directory for the database |
59
+ | `-v, --verbose` | Show detailed progress |
60
+ | `-f, --force` | Force full re-index (skip hash check) |
61
+
62
+ ### `search` — Find symbols
63
+
64
+ ```bash
65
+ milens search "createUser" --limit 10
66
+ ```
67
+
68
+ Full-text search across all indexed symbol names using FTS5.
69
+
70
+ ### `inspect` — 360° symbol context
71
+
72
+ ```bash
73
+ milens inspect "AuthService"
74
+ ```
75
+
76
+ Shows a symbol's incoming references (who calls/uses it) and outgoing dependencies (what it calls/imports/extends).
77
+
78
+ ### `impact` — Blast radius analysis
79
+
80
+ ```bash
81
+ milens impact "UserModel" --direction upstream --depth 3
82
+ ```
83
+
84
+ Answers: *"What breaks if this symbol changes?"* Uses recursive CTEs to traverse the dependency graph up to N levels deep.
85
+
86
+ | Flag | Description |
87
+ |---|---|
88
+ | `-d, --direction` | `upstream` (default) or `downstream` |
89
+ | `--depth` | Max traversal depth (default: `3`) |
90
+
91
+ ### `status` — Index stats
92
+
93
+ ```bash
94
+ milens status -p /path/to/repo
95
+ ```
96
+
97
+ Shows symbol count, link count, file count, and last indexed time.
98
+
99
+ ### `serve` — Start MCP server
100
+
101
+ ```bash
102
+ # stdio transport (for VS Code / Cursor)
103
+ milens serve -p /path/to/repo
104
+
105
+ # HTTP transport (for remote agents)
106
+ milens serve -p /path/to/repo --http --port 3100
107
+ ```
108
+
109
+ ## MCP Server
110
+
111
+ milens exposes 4 tools via the Model Context Protocol:
112
+
113
+ | Tool | Description | Key params |
114
+ |---|---|---|
115
+ | `search` | Find symbols by name/keyword (FTS5) | `query`, `limit` |
116
+ | `inspect` | Incoming refs, outgoing deps, hierarchy | `name` |
117
+ | `impact` | Blast radius with depth grouping | `target`, `direction`, `depth` |
118
+ | `status` | Index stats for a repository | `repo` |
119
+
120
+ ### VS Code / Cursor Integration
121
+
122
+ Add to your MCP settings (`mcp.json`):
123
+
124
+ ```json
125
+ {
126
+ "servers": {
127
+ "milens": {
128
+ "command": "npx",
129
+ "args": ["tsx", "/path/to/milens/src/cli.ts", "serve", "-p", "/path/to/repo"]
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### HTTP Mode
136
+
137
+ ```bash
138
+ milens serve --http --port 3100
139
+ ```
140
+
141
+ Endpoint: `POST http://localhost:3100/mcp`
142
+
143
+ ## Architecture
144
+
145
+ ```
146
+ src/
147
+ cli.ts — CLI entry point (commander)
148
+ types.ts — Shared type definitions
149
+ parser/
150
+ loader.ts — Tree-sitter WASM loading
151
+ extract.ts — Universal extractor + LangSpec interface
152
+ lang-*.ts — Declarative grammar per language
153
+ languages.ts — Language registry
154
+ analyzer/
155
+ scanner.ts — File discovery (.gitignore aware)
156
+ resolver.ts — Import + call + heritage resolution
157
+ engine.ts — Pipeline orchestrator
158
+ store/
159
+ schema.sql — SQLite schema with FTS5
160
+ db.ts — Database adapter with recursive CTE queries
161
+ registry.ts — Multi-repo registry (~/.milens/)
162
+ server/
163
+ mcp.ts — MCP server (stdio + HTTP transports)
164
+ ```
165
+
166
+ ### How It Works
167
+
168
+ 1. **Scan** — Discover source files respecting `.gitignore`
169
+ 2. **Parse** — Extract symbols (functions, classes, interfaces, ...) via tree-sitter WASM grammars
170
+ 3. **Resolve** — Link imports → symbols, calls → definitions, inheritance chains
171
+ 4. **Store** — Write symbols + links to SQLite with FTS5 search index
172
+ 5. **Serve** — Expose the knowledge graph via MCP tools or CLI
173
+
174
+ ### Design Decisions
175
+
176
+ - **Declarative `LangSpec`**: Each language is a config object with tree-sitter queries. One universal extractor processes all languages — no per-language extraction code.
177
+ - **SQLite recursive CTE**: Impact analysis traverses the graph inside the database. No need to load the full graph into memory.
178
+ - **Token-compact output**: MCP responses use minimal structured text, not verbose descriptions.
179
+ - **Incremental by default**: File content is hashed; only changed files get re-parsed on subsequent runs.
180
+
181
+ ## Adding a Language
182
+
183
+ Create `src/parser/lang-xxx.ts`:
184
+
185
+ ```typescript
186
+ import type { LangSpec } from './extract.js';
187
+
188
+ const spec: LangSpec = {
189
+ id: 'xxx',
190
+ extensions: ['.xxx'],
191
+ wasmName: 'tree-sitter-xxx',
192
+ queries: {
193
+ functions: `(function_definition name: (identifier) @name) @def`,
194
+ classes: `(class_definition name: (identifier) @name) @def`,
195
+ // add queries using tree-sitter playground
196
+ },
197
+ resolveImport(raw, fromFile, root, aliases) {
198
+ // return resolved file path or null
199
+ },
200
+ };
201
+
202
+ export default spec;
203
+ ```
204
+
205
+ Then register it in `src/parser/languages.ts`.
206
+
207
+ ## Requirements
208
+
209
+ - Node.js >= 20.0.0
210
+
211
+ ## License
212
+
213
+ [MIT](LICENSE)
@@ -0,0 +1,11 @@
1
+ import type { AnalysisStats } from '../types.js';
2
+ interface EngineOptions {
3
+ rootPath: string;
4
+ dbPath: string;
5
+ verbose?: boolean;
6
+ force?: boolean;
7
+ aliases?: Record<string, string>;
8
+ }
9
+ export declare function analyze(opts: EngineOptions): Promise<AnalysisStats>;
10
+ export {};
11
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/analyzer/engine.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAiE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIhH,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAkIzE"}
@@ -0,0 +1,163 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { scanFiles } from './scanner.js';
4
+ import { langForFile } from '../parser/languages.js';
5
+ import { getParser, loadLanguage } from '../parser/loader.js';
6
+ import { extractFromTree, clearQueryCache } from '../parser/extract.js';
7
+ import { extractVueScript } from '../parser/lang-vue.js';
8
+ import { resolveLinks } from './resolver.js';
9
+ import { Database } from '../store/db.js';
10
+ export async function analyze(opts) {
11
+ const t0 = Date.now();
12
+ const rootPath = resolve(opts.rootPath);
13
+ const db = new Database(opts.dbPath);
14
+ const aliases = opts.aliases ?? {};
15
+ if (opts.force)
16
+ db.clear();
17
+ // Phase 1: Scan files
18
+ const files = scanFiles(rootPath, opts.verbose);
19
+ if (opts.verbose)
20
+ console.log(`[scan] Found ${files.length} source files`);
21
+ // Phase 2: Group files by language for cache-friendly processing
22
+ const langGroups = new Map();
23
+ for (const file of files) {
24
+ const spec = langForFile(file.relativePath);
25
+ if (!spec)
26
+ continue;
27
+ const group = langGroups.get(spec.wasmName) ?? [];
28
+ group.push({ ...file, spec });
29
+ langGroups.set(spec.wasmName, group);
30
+ }
31
+ // Phase 3: Parse & extract — process each language group together
32
+ // This keeps the same parser/language/compiled queries hot in cache
33
+ const symbolsByFile = new Map();
34
+ const allSymbols = [];
35
+ const allImports = [];
36
+ const allCalls = [];
37
+ const allHeritage = [];
38
+ const resolvedImportPaths = new Map();
39
+ const parsedFiles = new Set();
40
+ let filesParsed = 0;
41
+ for (const [wasmName, group] of langGroups) {
42
+ // Pre-load parser + language once per group
43
+ const parser = await getParser(wasmName);
44
+ const lang = await loadLanguage(wasmName);
45
+ for (const file of group) {
46
+ const source = readFileSync(file.absolutePath, 'utf-8');
47
+ // Skip unchanged files (incremental)
48
+ if (!opts.force && db.isFileUpToDate(file.relativePath, source)) {
49
+ if (opts.verbose)
50
+ console.log(`[skip] ${file.relativePath} (unchanged)`);
51
+ continue;
52
+ }
53
+ try {
54
+ const result = parseFile(source, file.relativePath, file.spec, parser, lang);
55
+ if (!result)
56
+ continue;
57
+ symbolsByFile.set(file.relativePath, result.symbols);
58
+ allSymbols.push(...result.symbols);
59
+ allImports.push(...result.imports);
60
+ allCalls.push(...result.calls);
61
+ allHeritage.push(...result.heritage);
62
+ // Resolve import paths eagerly
63
+ for (const imp of result.imports) {
64
+ const resolved = file.spec.resolveImport(imp.modulePath, imp.filePath, rootPath, aliases);
65
+ if (resolved) {
66
+ resolvedImportPaths.set(`${imp.filePath}::${imp.modulePath}`, resolved);
67
+ }
68
+ }
69
+ db.upsertFileHash(file.relativePath, source);
70
+ parsedFiles.add(file.relativePath);
71
+ filesParsed++;
72
+ if (opts.verbose)
73
+ console.log(`[parse] ${file.relativePath}: ${result.symbols.length} symbols`);
74
+ }
75
+ catch (err) {
76
+ if (opts.verbose)
77
+ console.error(`[error] ${file.relativePath}: ${err}`);
78
+ }
79
+ }
80
+ }
81
+ // Phase 4: Load unchanged files' symbols for cross-file resolution
82
+ if (!opts.force) {
83
+ for (const [, group] of langGroups) {
84
+ for (const file of group) {
85
+ if (!parsedFiles.has(file.relativePath)) {
86
+ const existing = db.getSymbolsByFile(file.relativePath);
87
+ if (existing.length > 0) {
88
+ symbolsByFile.set(file.relativePath, existing);
89
+ allSymbols.push(...existing);
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ // Phase 5: Resolve cross-file links
96
+ const links = resolveLinks({
97
+ symbolsByFile,
98
+ allSymbols,
99
+ imports: allImports,
100
+ calls: allCalls,
101
+ heritage: allHeritage,
102
+ resolvedImportPaths,
103
+ });
104
+ if (opts.verbose)
105
+ console.log(`[link] Resolved ${links.length} relationships`);
106
+ // Phase 6: Persist to database in single transaction
107
+ db.transaction(() => {
108
+ if (opts.force) {
109
+ db.clearSymbolsAndLinks();
110
+ }
111
+ else {
112
+ for (const fp of parsedFiles)
113
+ db.deleteFileData(fp);
114
+ }
115
+ for (const sym of allSymbols) {
116
+ if (opts.force || parsedFiles.has(sym.filePath))
117
+ db.insertSymbol(sym);
118
+ }
119
+ for (const link of links)
120
+ db.insertLink(link);
121
+ db.rebuildSearch();
122
+ });
123
+ const stats = {
124
+ filesScanned: files.length,
125
+ filesParsed,
126
+ symbolCount: allSymbols.length,
127
+ linkCount: links.length,
128
+ durationMs: Date.now() - t0,
129
+ };
130
+ if (opts.verbose) {
131
+ console.log(`[done] ${stats.symbolCount} symbols, ${stats.linkCount} links in ${stats.durationMs}ms`);
132
+ }
133
+ clearQueryCache();
134
+ db.close();
135
+ return stats;
136
+ }
137
+ function parseFile(source, filePath, spec, parser, lang) {
138
+ let code = source;
139
+ let lineOffset = 0;
140
+ // Vue SFC: extract <script> block
141
+ if (spec.id === 'vue') {
142
+ const script = extractVueScript(source);
143
+ if (!script)
144
+ return null;
145
+ code = script.content;
146
+ lineOffset = script.lineOffset;
147
+ }
148
+ const tree = parser.parse(code);
149
+ const result = extractFromTree(tree, lang, spec, filePath);
150
+ // Adjust line numbers for Vue offset
151
+ if (lineOffset > 0) {
152
+ for (const sym of result.symbols) {
153
+ sym.startLine += lineOffset;
154
+ sym.endLine += lineOffset;
155
+ }
156
+ for (const imp of result.imports)
157
+ imp.line += lineOffset;
158
+ for (const call of result.calls)
159
+ call.line += lineOffset;
160
+ }
161
+ return result;
162
+ }
163
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/analyzer/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CodeSymbol, SymbolLink, RawImport, RawCall, RawHeritage } from '../types.js';
2
+ interface ResolutionInput {
3
+ symbolsByFile: Map<string, CodeSymbol[]>;
4
+ allSymbols: CodeSymbol[];
5
+ imports: RawImport[];
6
+ calls: RawCall[];
7
+ heritage: RawHeritage[];
8
+ resolvedImportPaths: Map<string, string>;
9
+ }
10
+ export declare function resolveLinks(input: ResolutionInput): SymbolLink[];
11
+ export {};
12
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/analyzer/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAY,MAAM,aAAa,CAAC;AAErG,UAAU,eAAe;IACvB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,EAAE,CA+FjE"}
@@ -0,0 +1,119 @@
1
+ export function resolveLinks(input) {
2
+ const links = [];
3
+ const symbolByName = buildNameIndex(input.allSymbols);
4
+ // Build imported names per file: file → (name → targetFile)
5
+ const importedNamesPerFile = new Map();
6
+ for (const imp of input.imports) {
7
+ const targetFile = input.resolvedImportPaths.get(`${imp.filePath}::${imp.modulePath}`);
8
+ if (!targetFile)
9
+ continue;
10
+ let fileImports = importedNamesPerFile.get(imp.filePath);
11
+ if (!fileImports) {
12
+ fileImports = new Map();
13
+ importedNamesPerFile.set(imp.filePath, fileImports);
14
+ }
15
+ for (const { name } of imp.names) {
16
+ fileImports.set(name, targetFile);
17
+ }
18
+ }
19
+ // ── Resolve imports ──
20
+ for (const imp of input.imports) {
21
+ const targetFile = input.resolvedImportPaths.get(`${imp.filePath}::${imp.modulePath}`);
22
+ if (!targetFile)
23
+ continue;
24
+ const targetSymbols = input.symbolsByFile.get(targetFile);
25
+ if (!targetSymbols)
26
+ continue;
27
+ // Find the importing symbol (file-level or specific)
28
+ const fromId = `${imp.filePath}#module:_top:0`;
29
+ if (imp.names.length > 0) {
30
+ for (const { name } of imp.names) {
31
+ const target = targetSymbols.find(s => s.name === name && s.exported);
32
+ if (target) {
33
+ links.push(makeLink(fromId, target.id, 'imports', 0.95, imp.line));
34
+ }
35
+ }
36
+ }
37
+ else {
38
+ // Wildcard or default import — link to file module
39
+ const target = targetSymbols.find(s => s.exported);
40
+ if (target) {
41
+ links.push(makeLink(fromId, target.id, 'imports', 0.7, imp.line));
42
+ }
43
+ }
44
+ }
45
+ // ── Resolve calls (import-aware) ──
46
+ for (const call of input.calls) {
47
+ const candidates = symbolByName.get(call.calleeName);
48
+ if (!candidates || candidates.length === 0)
49
+ continue;
50
+ // Priority: same file > imported symbol > unique global > ambiguous
51
+ const sameFile = candidates.filter(s => s.filePath === call.filePath);
52
+ if (sameFile.length > 0) {
53
+ links.push(makeLink(call.enclosingSymbolId, sameFile[0].id, 'calls', 0.9, call.line));
54
+ continue;
55
+ }
56
+ // Check if callee was imported into this file
57
+ const fileImports = importedNamesPerFile.get(call.filePath);
58
+ const importedFromFile = fileImports?.get(call.calleeName);
59
+ if (importedFromFile) {
60
+ const imported = candidates.find(s => s.filePath === importedFromFile);
61
+ if (imported) {
62
+ links.push(makeLink(call.enclosingSymbolId, imported.id, 'calls', 0.95, call.line));
63
+ continue;
64
+ }
65
+ }
66
+ const match = candidates[0];
67
+ const confidence = candidates.length === 1 ? 0.8 : 0.5;
68
+ links.push(makeLink(call.enclosingSymbolId, match.id, 'calls', confidence, call.line));
69
+ }
70
+ // ── Resolve heritage (extends/implements) ──
71
+ for (const h of input.heritage) {
72
+ const children = symbolByName.get(h.childName);
73
+ const parents = symbolByName.get(h.parentName);
74
+ if (!children || !parents)
75
+ continue;
76
+ const child = children.find(s => s.filePath === h.filePath) ?? children[0];
77
+ const parent = parents[0];
78
+ if (child && parent) {
79
+ links.push(makeLink(child.id, parent.id, h.type, 0.95, h.line));
80
+ }
81
+ }
82
+ // ── Containment links (method → class) ──
83
+ for (const sym of input.allSymbols) {
84
+ if (sym.parentId) {
85
+ links.push(makeLink(sym.parentId, sym.id, 'contains', 1.0));
86
+ }
87
+ }
88
+ return deduplicateLinks(links);
89
+ }
90
+ // ── Helpers ──
91
+ function buildNameIndex(symbols) {
92
+ const index = new Map();
93
+ for (const s of symbols) {
94
+ const arr = index.get(s.name) ?? [];
95
+ arr.push(s);
96
+ index.set(s.name, arr);
97
+ }
98
+ return index;
99
+ }
100
+ function makeLink(fromId, toId, type, confidence, line) {
101
+ return {
102
+ id: `${fromId}->${type}->${toId}`,
103
+ fromId,
104
+ toId,
105
+ type,
106
+ confidence,
107
+ line,
108
+ };
109
+ }
110
+ function deduplicateLinks(links) {
111
+ const seen = new Set();
112
+ return links.filter(l => {
113
+ if (seen.has(l.id))
114
+ return false;
115
+ seen.add(l.id);
116
+ return true;
117
+ });
118
+ }
119
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/analyzer/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface ScannedFile {
2
+ relativePath: string;
3
+ absolutePath: string;
4
+ }
5
+ export declare function scanFiles(rootPath: string, verbose?: boolean): ScannedFile[];
6
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/analyzer/scanner.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,WAAW,EAAE,CA0C1E"}
@@ -0,0 +1,73 @@
1
+ import { join, relative } from 'node:path';
2
+ import { readFileSync, statSync, readdirSync } from 'node:fs';
3
+ import ignore from 'ignore';
4
+ import { supportedExtensions } from '../parser/languages.js';
5
+ export function scanFiles(rootPath, verbose = false) {
6
+ const exts = new Set(supportedExtensions());
7
+ const ig = loadIgnoreRules(rootPath);
8
+ const results = [];
9
+ function walk(dir) {
10
+ let entries;
11
+ try {
12
+ entries = readdirSync(dir);
13
+ }
14
+ catch {
15
+ return;
16
+ }
17
+ for (const entry of entries) {
18
+ const abs = join(dir, entry);
19
+ const rel = relative(rootPath, abs).replace(/\\/g, '/');
20
+ // Skip hidden dirs and common non-source dirs
21
+ if (entry.startsWith('.'))
22
+ continue;
23
+ if (SKIP_DIRS.has(entry) && dir === rootPath)
24
+ continue;
25
+ if (ig.ignores(rel))
26
+ continue;
27
+ let stat;
28
+ try {
29
+ stat = statSync(abs);
30
+ }
31
+ catch {
32
+ continue;
33
+ }
34
+ if (stat.isDirectory()) {
35
+ if (SKIP_DIRS.has(entry))
36
+ continue;
37
+ walk(abs);
38
+ }
39
+ else if (stat.isFile()) {
40
+ const ext = '.' + entry.split('.').pop()?.toLowerCase();
41
+ if (exts.has(ext)) {
42
+ results.push({ relativePath: rel, absolutePath: abs });
43
+ }
44
+ else if (verbose) {
45
+ // Skip non-supported files silently
46
+ }
47
+ }
48
+ }
49
+ }
50
+ walk(rootPath);
51
+ return results;
52
+ }
53
+ function loadIgnoreRules(rootPath) {
54
+ const ig = ignore();
55
+ // Always ignore these
56
+ ig.add(['node_modules', 'dist', 'build', '.git', '__pycache__', 'vendor', 'target']);
57
+ // Read .gitignore if present
58
+ try {
59
+ const content = readFileSync(join(rootPath, '.gitignore'), 'utf-8');
60
+ ig.add(content);
61
+ }
62
+ catch { /* no .gitignore */ }
63
+ return ig;
64
+ }
65
+ const SKIP_DIRS = new Set([
66
+ 'node_modules', '.git', 'dist', 'build', 'out',
67
+ '.next', '.nuxt', '.svelte-kit',
68
+ '__pycache__', '.venv', 'venv', 'env',
69
+ 'vendor', 'target',
70
+ '.idea', '.vscode',
71
+ 'coverage', '.nyc_output',
72
+ ]);
73
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/analyzer/scanner.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}