@zuvia-software-solutions/code-mapper 1.4.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 (213) hide show
  1. package/README.md +215 -0
  2. package/dist/cli/ai-context.d.ts +19 -0
  3. package/dist/cli/ai-context.js +168 -0
  4. package/dist/cli/analyze.d.ts +7 -0
  5. package/dist/cli/analyze.js +325 -0
  6. package/dist/cli/augment.d.ts +7 -0
  7. package/dist/cli/augment.js +27 -0
  8. package/dist/cli/clean.d.ts +5 -0
  9. package/dist/cli/clean.js +56 -0
  10. package/dist/cli/eval-server.d.ts +25 -0
  11. package/dist/cli/eval-server.js +365 -0
  12. package/dist/cli/index.d.ts +6 -0
  13. package/dist/cli/index.js +102 -0
  14. package/dist/cli/lazy-action.d.ts +6 -0
  15. package/dist/cli/lazy-action.js +19 -0
  16. package/dist/cli/list.d.ts +2 -0
  17. package/dist/cli/list.js +27 -0
  18. package/dist/cli/mcp.d.ts +8 -0
  19. package/dist/cli/mcp.js +35 -0
  20. package/dist/cli/refresh.d.ts +12 -0
  21. package/dist/cli/refresh.js +165 -0
  22. package/dist/cli/serve.d.ts +5 -0
  23. package/dist/cli/serve.js +8 -0
  24. package/dist/cli/setup.d.ts +6 -0
  25. package/dist/cli/setup.js +218 -0
  26. package/dist/cli/status.d.ts +2 -0
  27. package/dist/cli/status.js +33 -0
  28. package/dist/cli/tool.d.ts +28 -0
  29. package/dist/cli/tool.js +87 -0
  30. package/dist/config/ignore-service.d.ts +32 -0
  31. package/dist/config/ignore-service.js +282 -0
  32. package/dist/config/supported-languages.d.ts +23 -0
  33. package/dist/config/supported-languages.js +52 -0
  34. package/dist/core/augmentation/engine.d.ts +22 -0
  35. package/dist/core/augmentation/engine.js +232 -0
  36. package/dist/core/embeddings/embedder.d.ts +35 -0
  37. package/dist/core/embeddings/embedder.js +171 -0
  38. package/dist/core/embeddings/embedding-pipeline.d.ts +41 -0
  39. package/dist/core/embeddings/embedding-pipeline.js +402 -0
  40. package/dist/core/embeddings/index.d.ts +5 -0
  41. package/dist/core/embeddings/index.js +6 -0
  42. package/dist/core/embeddings/text-generator.d.ts +20 -0
  43. package/dist/core/embeddings/text-generator.js +159 -0
  44. package/dist/core/embeddings/types.d.ts +60 -0
  45. package/dist/core/embeddings/types.js +23 -0
  46. package/dist/core/graph/graph.d.ts +4 -0
  47. package/dist/core/graph/graph.js +65 -0
  48. package/dist/core/graph/types.d.ts +69 -0
  49. package/dist/core/graph/types.js +3 -0
  50. package/dist/core/incremental/child-process.d.ts +8 -0
  51. package/dist/core/incremental/child-process.js +649 -0
  52. package/dist/core/incremental/refresh-coordinator.d.ts +32 -0
  53. package/dist/core/incremental/refresh-coordinator.js +147 -0
  54. package/dist/core/incremental/types.d.ts +78 -0
  55. package/dist/core/incremental/types.js +153 -0
  56. package/dist/core/incremental/watcher.d.ts +63 -0
  57. package/dist/core/incremental/watcher.js +338 -0
  58. package/dist/core/ingestion/ast-cache.d.ts +12 -0
  59. package/dist/core/ingestion/ast-cache.js +34 -0
  60. package/dist/core/ingestion/call-processor.d.ts +34 -0
  61. package/dist/core/ingestion/call-processor.js +937 -0
  62. package/dist/core/ingestion/call-routing.d.ts +40 -0
  63. package/dist/core/ingestion/call-routing.js +97 -0
  64. package/dist/core/ingestion/cluster-enricher.d.ts +30 -0
  65. package/dist/core/ingestion/cluster-enricher.js +151 -0
  66. package/dist/core/ingestion/community-processor.d.ts +26 -0
  67. package/dist/core/ingestion/community-processor.js +272 -0
  68. package/dist/core/ingestion/constants.d.ts +5 -0
  69. package/dist/core/ingestion/constants.js +8 -0
  70. package/dist/core/ingestion/entry-point-scoring.d.ts +23 -0
  71. package/dist/core/ingestion/entry-point-scoring.js +317 -0
  72. package/dist/core/ingestion/export-detection.d.ts +11 -0
  73. package/dist/core/ingestion/export-detection.js +203 -0
  74. package/dist/core/ingestion/filesystem-walker.d.ts +18 -0
  75. package/dist/core/ingestion/filesystem-walker.js +64 -0
  76. package/dist/core/ingestion/framework-detection.d.ts +42 -0
  77. package/dist/core/ingestion/framework-detection.js +405 -0
  78. package/dist/core/ingestion/heritage-processor.d.ts +15 -0
  79. package/dist/core/ingestion/heritage-processor.js +237 -0
  80. package/dist/core/ingestion/import-processor.d.ts +31 -0
  81. package/dist/core/ingestion/import-processor.js +416 -0
  82. package/dist/core/ingestion/language-config.d.ts +32 -0
  83. package/dist/core/ingestion/language-config.js +161 -0
  84. package/dist/core/ingestion/mro-processor.d.ts +32 -0
  85. package/dist/core/ingestion/mro-processor.js +343 -0
  86. package/dist/core/ingestion/named-binding-extraction.d.ts +51 -0
  87. package/dist/core/ingestion/named-binding-extraction.js +343 -0
  88. package/dist/core/ingestion/parsing-processor.d.ts +20 -0
  89. package/dist/core/ingestion/parsing-processor.js +282 -0
  90. package/dist/core/ingestion/pipeline.d.ts +3 -0
  91. package/dist/core/ingestion/pipeline.js +416 -0
  92. package/dist/core/ingestion/process-processor.d.ts +42 -0
  93. package/dist/core/ingestion/process-processor.js +357 -0
  94. package/dist/core/ingestion/resolution-context.d.ts +40 -0
  95. package/dist/core/ingestion/resolution-context.js +171 -0
  96. package/dist/core/ingestion/resolvers/csharp.d.ts +10 -0
  97. package/dist/core/ingestion/resolvers/csharp.js +101 -0
  98. package/dist/core/ingestion/resolvers/go.d.ts +8 -0
  99. package/dist/core/ingestion/resolvers/go.js +33 -0
  100. package/dist/core/ingestion/resolvers/index.d.ts +14 -0
  101. package/dist/core/ingestion/resolvers/index.js +10 -0
  102. package/dist/core/ingestion/resolvers/jvm.d.ts +9 -0
  103. package/dist/core/ingestion/resolvers/jvm.js +74 -0
  104. package/dist/core/ingestion/resolvers/php.d.ts +7 -0
  105. package/dist/core/ingestion/resolvers/php.js +30 -0
  106. package/dist/core/ingestion/resolvers/ruby.d.ts +9 -0
  107. package/dist/core/ingestion/resolvers/ruby.js +13 -0
  108. package/dist/core/ingestion/resolvers/rust.d.ts +5 -0
  109. package/dist/core/ingestion/resolvers/rust.js +62 -0
  110. package/dist/core/ingestion/resolvers/standard.d.ts +16 -0
  111. package/dist/core/ingestion/resolvers/standard.js +144 -0
  112. package/dist/core/ingestion/resolvers/utils.d.ts +18 -0
  113. package/dist/core/ingestion/resolvers/utils.js +113 -0
  114. package/dist/core/ingestion/structure-processor.d.ts +4 -0
  115. package/dist/core/ingestion/structure-processor.js +39 -0
  116. package/dist/core/ingestion/symbol-table.d.ts +34 -0
  117. package/dist/core/ingestion/symbol-table.js +48 -0
  118. package/dist/core/ingestion/tree-sitter-queries.d.ts +20 -0
  119. package/dist/core/ingestion/tree-sitter-queries.js +691 -0
  120. package/dist/core/ingestion/type-env.d.ts +52 -0
  121. package/dist/core/ingestion/type-env.js +349 -0
  122. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +4 -0
  123. package/dist/core/ingestion/type-extractors/c-cpp.js +214 -0
  124. package/dist/core/ingestion/type-extractors/csharp.d.ts +4 -0
  125. package/dist/core/ingestion/type-extractors/csharp.js +224 -0
  126. package/dist/core/ingestion/type-extractors/go.d.ts +4 -0
  127. package/dist/core/ingestion/type-extractors/go.js +261 -0
  128. package/dist/core/ingestion/type-extractors/index.d.ts +20 -0
  129. package/dist/core/ingestion/type-extractors/index.js +30 -0
  130. package/dist/core/ingestion/type-extractors/jvm.d.ts +5 -0
  131. package/dist/core/ingestion/type-extractors/jvm.js +386 -0
  132. package/dist/core/ingestion/type-extractors/php.d.ts +4 -0
  133. package/dist/core/ingestion/type-extractors/php.js +280 -0
  134. package/dist/core/ingestion/type-extractors/python.d.ts +4 -0
  135. package/dist/core/ingestion/type-extractors/python.js +175 -0
  136. package/dist/core/ingestion/type-extractors/ruby.d.ts +12 -0
  137. package/dist/core/ingestion/type-extractors/ruby.js +218 -0
  138. package/dist/core/ingestion/type-extractors/rust.d.ts +4 -0
  139. package/dist/core/ingestion/type-extractors/rust.js +290 -0
  140. package/dist/core/ingestion/type-extractors/shared.d.ts +81 -0
  141. package/dist/core/ingestion/type-extractors/shared.js +322 -0
  142. package/dist/core/ingestion/type-extractors/swift.d.ts +4 -0
  143. package/dist/core/ingestion/type-extractors/swift.js +140 -0
  144. package/dist/core/ingestion/type-extractors/types.d.ts +111 -0
  145. package/dist/core/ingestion/type-extractors/types.js +4 -0
  146. package/dist/core/ingestion/type-extractors/typescript.d.ts +4 -0
  147. package/dist/core/ingestion/type-extractors/typescript.js +227 -0
  148. package/dist/core/ingestion/utils.d.ts +73 -0
  149. package/dist/core/ingestion/utils.js +992 -0
  150. package/dist/core/ingestion/workers/parse-worker.d.ts +99 -0
  151. package/dist/core/ingestion/workers/parse-worker.js +1055 -0
  152. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -0
  153. package/dist/core/ingestion/workers/worker-pool.js +123 -0
  154. package/dist/core/lbug/csv-generator.d.ts +28 -0
  155. package/dist/core/lbug/csv-generator.js +355 -0
  156. package/dist/core/lbug/lbug-adapter.d.ts +96 -0
  157. package/dist/core/lbug/lbug-adapter.js +753 -0
  158. package/dist/core/lbug/schema.d.ts +46 -0
  159. package/dist/core/lbug/schema.js +402 -0
  160. package/dist/core/search/bm25-index.d.ts +20 -0
  161. package/dist/core/search/bm25-index.js +123 -0
  162. package/dist/core/search/hybrid-search.d.ts +32 -0
  163. package/dist/core/search/hybrid-search.js +131 -0
  164. package/dist/core/search/query-cache.d.ts +18 -0
  165. package/dist/core/search/query-cache.js +47 -0
  166. package/dist/core/search/query-expansion.d.ts +19 -0
  167. package/dist/core/search/query-expansion.js +75 -0
  168. package/dist/core/search/reranker.d.ts +29 -0
  169. package/dist/core/search/reranker.js +122 -0
  170. package/dist/core/search/types.d.ts +154 -0
  171. package/dist/core/search/types.js +51 -0
  172. package/dist/core/semantic/tsgo-service.d.ts +67 -0
  173. package/dist/core/semantic/tsgo-service.js +355 -0
  174. package/dist/core/tree-sitter/parser-loader.d.ts +12 -0
  175. package/dist/core/tree-sitter/parser-loader.js +71 -0
  176. package/dist/lib/memory-guard.d.ts +35 -0
  177. package/dist/lib/memory-guard.js +70 -0
  178. package/dist/lib/utils.d.ts +3 -0
  179. package/dist/lib/utils.js +6 -0
  180. package/dist/mcp/compatible-stdio-transport.d.ts +32 -0
  181. package/dist/mcp/compatible-stdio-transport.js +209 -0
  182. package/dist/mcp/core/embedder.d.ts +24 -0
  183. package/dist/mcp/core/embedder.js +168 -0
  184. package/dist/mcp/core/lbug-adapter.d.ts +29 -0
  185. package/dist/mcp/core/lbug-adapter.js +330 -0
  186. package/dist/mcp/local/local-backend.d.ts +188 -0
  187. package/dist/mcp/local/local-backend.js +2759 -0
  188. package/dist/mcp/resources.d.ts +22 -0
  189. package/dist/mcp/resources.js +379 -0
  190. package/dist/mcp/server.d.ts +10 -0
  191. package/dist/mcp/server.js +217 -0
  192. package/dist/mcp/staleness.d.ts +10 -0
  193. package/dist/mcp/staleness.js +25 -0
  194. package/dist/mcp/tools.d.ts +21 -0
  195. package/dist/mcp/tools.js +202 -0
  196. package/dist/server/api.d.ts +5 -0
  197. package/dist/server/api.js +340 -0
  198. package/dist/server/mcp-http.d.ts +7 -0
  199. package/dist/server/mcp-http.js +95 -0
  200. package/dist/storage/git.d.ts +6 -0
  201. package/dist/storage/git.js +35 -0
  202. package/dist/storage/repo-manager.d.ts +87 -0
  203. package/dist/storage/repo-manager.js +249 -0
  204. package/dist/types/pipeline.d.ts +35 -0
  205. package/dist/types/pipeline.js +20 -0
  206. package/hooks/claude/code-mapper-hook.cjs +238 -0
  207. package/hooks/claude/pre-tool-use.sh +79 -0
  208. package/hooks/claude/session-start.sh +42 -0
  209. package/models/mlx-embedder.py +185 -0
  210. package/package.json +100 -0
  211. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  212. package/vendor/leiden/index.cjs +355 -0
  213. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file Singleton LSP client for tsgo (TypeScript native preview).
3
+ *
4
+ * Spawns `tsgo --lsp --stdio` as a persistent child process and provides
5
+ * high-level async methods for semantic operations:
6
+ * - resolveDefinition(): cross-file go-to-definition (confidence 1.0 edges)
7
+ * - findReferences(): all references to a symbol
8
+ * - getHover(): type signature for a position
9
+ *
10
+ * The server stays warm for the lifetime of the MCP process. File changes
11
+ * are forwarded via didOpen/didChange so tsgo always has fresh state.
12
+ *
13
+ * Optional — only starts if the `@typescript/native-preview` package is installed.
14
+ */
15
+ export interface TsgoDefinition {
16
+ filePath: string;
17
+ line: number;
18
+ character: number;
19
+ }
20
+ export interface TsgoReference {
21
+ filePath: string;
22
+ line: number;
23
+ character: number;
24
+ }
25
+ export declare class TsgoService {
26
+ private process;
27
+ private buf;
28
+ private responses;
29
+ private nextId;
30
+ private projectRoot;
31
+ private tsgoPath;
32
+ private ready;
33
+ private initPromise;
34
+ private openFiles;
35
+ constructor(projectRoot: string);
36
+ /**
37
+ * Start the tsgo LSP server. Returns true if successful, false if
38
+ * @typescript/native-preview is not installed or tsgo fails to start.
39
+ */
40
+ start(): Promise<boolean>;
41
+ /** Whether the server is running and ready for queries */
42
+ isReady(): boolean;
43
+ /** Resolve what a symbol at a given position points to (go-to-definition) */
44
+ resolveDefinition(absFilePath: string, line: number, character: number): Promise<TsgoDefinition | null>;
45
+ /** Find all references to the symbol at the given position */
46
+ findReferences(absFilePath: string, line: number, character: number): Promise<TsgoReference[]>;
47
+ /** Get the type signature at a position (hover) */
48
+ getHover(absFilePath: string, line: number, character: number): Promise<string | null>;
49
+ /** Notify tsgo that a file changed (call after editing a file) */
50
+ notifyFileChanged(absFilePath: string): Promise<void>;
51
+ /** Notify tsgo that a file was deleted */
52
+ notifyFileDeleted(absFilePath: string): Promise<void>;
53
+ /** Stop the tsgo process */
54
+ stop(): void;
55
+ private doStart;
56
+ private findTsgoBinary;
57
+ private onData;
58
+ private send;
59
+ private request;
60
+ private ensureOpen;
61
+ private fileUri;
62
+ private uriToRelative;
63
+ }
64
+ /** Get or create the singleton TsgoService for a project root */
65
+ export declare function getTsgoService(projectRoot: string): TsgoService;
66
+ /** Stop the singleton if running */
67
+ export declare function stopTsgoService(): void;
@@ -0,0 +1,355 @@
1
+ // code-mapper/src/core/semantic/tsgo-service.ts
2
+ /**
3
+ * @file Singleton LSP client for tsgo (TypeScript native preview).
4
+ *
5
+ * Spawns `tsgo --lsp --stdio` as a persistent child process and provides
6
+ * high-level async methods for semantic operations:
7
+ * - resolveDefinition(): cross-file go-to-definition (confidence 1.0 edges)
8
+ * - findReferences(): all references to a symbol
9
+ * - getHover(): type signature for a position
10
+ *
11
+ * The server stays warm for the lifetime of the MCP process. File changes
12
+ * are forwarded via didOpen/didChange so tsgo always has fresh state.
13
+ *
14
+ * Optional — only starts if the `@typescript/native-preview` package is installed.
15
+ */
16
+ import { spawn } from 'child_process';
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+ // ---------------------------------------------------------------------------
20
+ // LSP message helpers
21
+ // ---------------------------------------------------------------------------
22
+ function encodeLSP(msg) {
23
+ const json = JSON.stringify(msg);
24
+ return `Content-Length: ${Buffer.byteLength(json)}\r\n\r\n${json}`;
25
+ }
26
+ // ---------------------------------------------------------------------------
27
+ // TsgoService
28
+ // ---------------------------------------------------------------------------
29
+ export class TsgoService {
30
+ process = null;
31
+ buf = '';
32
+ responses = new Map();
33
+ nextId = 1;
34
+ projectRoot;
35
+ tsgoPath = null;
36
+ ready = false;
37
+ initPromise = null;
38
+ openFiles = new Set();
39
+ constructor(projectRoot) {
40
+ this.projectRoot = projectRoot;
41
+ }
42
+ // ── Public API ──────────────────────────────────────────────────────
43
+ /**
44
+ * Start the tsgo LSP server. Returns true if successful, false if
45
+ * @typescript/native-preview is not installed or tsgo fails to start.
46
+ */
47
+ async start() {
48
+ if (this.ready)
49
+ return true;
50
+ if (this.initPromise)
51
+ return this.initPromise;
52
+ this.initPromise = this.doStart();
53
+ return this.initPromise;
54
+ }
55
+ /** Whether the server is running and ready for queries */
56
+ isReady() {
57
+ return this.ready;
58
+ }
59
+ /** Resolve what a symbol at a given position points to (go-to-definition) */
60
+ async resolveDefinition(absFilePath, line, character) {
61
+ if (!this.ready)
62
+ return null;
63
+ await this.ensureOpen(absFilePath);
64
+ const resp = await this.request('textDocument/definition', {
65
+ textDocument: { uri: this.fileUri(absFilePath) },
66
+ position: { line, character },
67
+ });
68
+ if (!resp)
69
+ return null;
70
+ const result = resp.result;
71
+ if (!result)
72
+ return null;
73
+ const defs = Array.isArray(result) ? result : [result];
74
+ if (defs.length === 0)
75
+ return null;
76
+ const d = defs[0];
77
+ const uri = d.uri || d.targetUri || '';
78
+ const range = d.range || d.targetSelectionRange;
79
+ if (!uri || !range)
80
+ return null;
81
+ return {
82
+ filePath: this.uriToRelative(uri),
83
+ line: range.start.line,
84
+ character: range.start.character,
85
+ };
86
+ }
87
+ /** Find all references to the symbol at the given position */
88
+ async findReferences(absFilePath, line, character) {
89
+ if (!this.ready)
90
+ return [];
91
+ await this.ensureOpen(absFilePath);
92
+ const resp = await this.request('textDocument/references', {
93
+ textDocument: { uri: this.fileUri(absFilePath) },
94
+ position: { line, character },
95
+ context: { includeDeclaration: false },
96
+ });
97
+ if (!resp?.result)
98
+ return [];
99
+ const refs = resp.result;
100
+ return refs.map((r) => ({
101
+ filePath: this.uriToRelative(r.uri),
102
+ line: r.range.start.line,
103
+ character: r.range.start.character,
104
+ }));
105
+ }
106
+ /** Get the type signature at a position (hover) */
107
+ async getHover(absFilePath, line, character) {
108
+ if (!this.ready)
109
+ return null;
110
+ await this.ensureOpen(absFilePath);
111
+ const resp = await this.request('textDocument/hover', {
112
+ textDocument: { uri: this.fileUri(absFilePath) },
113
+ position: { line, character },
114
+ });
115
+ if (!resp?.result)
116
+ return null;
117
+ const contents = resp.result.contents;
118
+ if (!contents)
119
+ return null;
120
+ if (typeof contents === 'string')
121
+ return contents;
122
+ if (contents.value)
123
+ return contents.value;
124
+ if (Array.isArray(contents))
125
+ return contents.map((c) => c.value || c).join('\n');
126
+ return null;
127
+ }
128
+ /** Notify tsgo that a file changed (call after editing a file) */
129
+ async notifyFileChanged(absFilePath) {
130
+ if (!this.ready)
131
+ return;
132
+ const uri = this.fileUri(absFilePath);
133
+ if (this.openFiles.has(uri)) {
134
+ // File was already open — send didChange with full content
135
+ const content = fs.readFileSync(absFilePath, 'utf-8');
136
+ this.send({
137
+ jsonrpc: '2.0',
138
+ method: 'textDocument/didChange',
139
+ params: {
140
+ textDocument: { uri, version: Date.now() },
141
+ contentChanges: [{ text: content }],
142
+ },
143
+ });
144
+ }
145
+ // If not open, next query will open it fresh
146
+ }
147
+ /** Notify tsgo that a file was deleted */
148
+ async notifyFileDeleted(absFilePath) {
149
+ if (!this.ready)
150
+ return;
151
+ const uri = this.fileUri(absFilePath);
152
+ if (this.openFiles.has(uri)) {
153
+ this.send({
154
+ jsonrpc: '2.0',
155
+ method: 'textDocument/didClose',
156
+ params: { textDocument: { uri } },
157
+ });
158
+ this.openFiles.delete(uri);
159
+ }
160
+ }
161
+ /** Stop the tsgo process */
162
+ stop() {
163
+ if (this.process && !this.process.killed) {
164
+ this.send({ jsonrpc: '2.0', id: this.nextId++, method: 'shutdown', params: null });
165
+ setTimeout(() => {
166
+ this.send({ jsonrpc: '2.0', method: 'exit', params: null });
167
+ setTimeout(() => {
168
+ try {
169
+ this.process?.kill();
170
+ }
171
+ catch { }
172
+ }, 500);
173
+ }, 200);
174
+ }
175
+ this.process = null;
176
+ this.ready = false;
177
+ this.initPromise = null;
178
+ this.openFiles.clear();
179
+ this.responses.clear();
180
+ }
181
+ // ── Internal ────────────────────────────────────────────────────────
182
+ async doStart() {
183
+ // Find the tsgo binary
184
+ this.tsgoPath = this.findTsgoBinary();
185
+ if (!this.tsgoPath) {
186
+ console.error('Code Mapper: tsgo not found — install @typescript/native-preview for semantic resolution');
187
+ return false;
188
+ }
189
+ try {
190
+ this.process = spawn(this.tsgoPath, ['--lsp', '--stdio'], {
191
+ stdio: ['pipe', 'pipe', 'pipe'],
192
+ cwd: this.projectRoot,
193
+ });
194
+ this.process.stdout.on('data', (chunk) => this.onData(chunk));
195
+ this.process.stderr.on('data', () => { }); // suppress
196
+ this.process.on('exit', () => {
197
+ this.ready = false;
198
+ this.process = null;
199
+ });
200
+ // Initialize LSP handshake
201
+ const initResp = await this.request('initialize', {
202
+ processId: process.pid,
203
+ capabilities: {
204
+ textDocument: {
205
+ definition: { dynamicRegistration: true },
206
+ references: { dynamicRegistration: true },
207
+ hover: { contentFormat: ['plaintext'], dynamicRegistration: true },
208
+ },
209
+ },
210
+ rootUri: `file://${this.projectRoot}`,
211
+ });
212
+ if (!initResp) {
213
+ console.error('Code Mapper: tsgo LSP initialize timed out');
214
+ this.stop();
215
+ return false;
216
+ }
217
+ // Send initialized notification
218
+ this.send({ jsonrpc: '2.0', method: 'initialized', params: {} });
219
+ this.ready = true;
220
+ console.error('Code Mapper: tsgo LSP ready (semantic resolution enabled)');
221
+ return true;
222
+ }
223
+ catch (err) {
224
+ console.error(`Code Mapper: tsgo LSP failed to start: ${err instanceof Error ? err.message : err}`);
225
+ this.stop();
226
+ return false;
227
+ }
228
+ }
229
+ findTsgoBinary() {
230
+ // Try resolving via the @typescript/native-preview package
231
+ try {
232
+ const platform = process.platform;
233
+ const arch = process.arch;
234
+ const pkgName = `@typescript/native-preview-${platform}-${arch}`;
235
+ const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
236
+ const exe = path.join(path.dirname(pkgJsonPath), 'lib', 'tsgo');
237
+ if (fs.existsSync(exe))
238
+ return exe;
239
+ }
240
+ catch { }
241
+ // Try npx tsgo path
242
+ try {
243
+ const { execFileSync } = require('child_process');
244
+ const result = execFileSync('which', ['tsgo'], { encoding: 'utf-8', timeout: 3000 }).trim();
245
+ if (result && fs.existsSync(result))
246
+ return result;
247
+ }
248
+ catch { }
249
+ return null;
250
+ }
251
+ onData(chunk) {
252
+ this.buf += chunk.toString();
253
+ while (true) {
254
+ const m = this.buf.match(/Content-Length: (\d+)\r\n\r\n([\s\S]*)/);
255
+ if (!m)
256
+ break;
257
+ const len = parseInt(m[1]);
258
+ if (m[2].length < len)
259
+ break;
260
+ const body = m[2].slice(0, len);
261
+ this.buf = m[2].slice(len);
262
+ try {
263
+ const msg = JSON.parse(body);
264
+ if (msg.id !== undefined && msg.method) {
265
+ // Server request (e.g., client/registerCapability) — acknowledge
266
+ this.send({ jsonrpc: '2.0', id: msg.id, result: null });
267
+ }
268
+ else if (msg.id !== undefined) {
269
+ // Response to our request
270
+ this.responses.set(msg.id, msg);
271
+ }
272
+ // Notifications (no id, has method) are ignored
273
+ }
274
+ catch { }
275
+ }
276
+ }
277
+ send(msg) {
278
+ if (!this.process?.stdin?.writable)
279
+ return;
280
+ try {
281
+ this.process.stdin.write(encodeLSP(msg));
282
+ }
283
+ catch { }
284
+ }
285
+ request(method, params, timeoutMs = 15000) {
286
+ const id = this.nextId++;
287
+ this.send({ jsonrpc: '2.0', id, method, params });
288
+ return new Promise((resolve) => {
289
+ const start = Date.now();
290
+ const check = () => {
291
+ if (this.responses.has(id)) {
292
+ const resp = this.responses.get(id);
293
+ this.responses.delete(id);
294
+ return resolve(resp);
295
+ }
296
+ if (Date.now() - start > timeoutMs)
297
+ return resolve(null);
298
+ setTimeout(check, 20);
299
+ };
300
+ check();
301
+ });
302
+ }
303
+ async ensureOpen(absFilePath) {
304
+ const uri = this.fileUri(absFilePath);
305
+ if (this.openFiles.has(uri))
306
+ return;
307
+ try {
308
+ const content = fs.readFileSync(absFilePath, 'utf-8');
309
+ this.send({
310
+ jsonrpc: '2.0',
311
+ method: 'textDocument/didOpen',
312
+ params: {
313
+ textDocument: {
314
+ uri,
315
+ languageId: 'typescript',
316
+ version: 1,
317
+ text: content,
318
+ },
319
+ },
320
+ });
321
+ this.openFiles.add(uri);
322
+ }
323
+ catch { }
324
+ }
325
+ fileUri(absPath) {
326
+ return `file://${absPath}`;
327
+ }
328
+ uriToRelative(uri) {
329
+ const prefix = `file://${this.projectRoot}/`;
330
+ if (uri.startsWith(prefix))
331
+ return uri.slice(prefix.length);
332
+ // Try with triple slash
333
+ const prefix2 = `file:///${this.projectRoot}/`;
334
+ if (uri.startsWith(prefix2))
335
+ return uri.slice(prefix2.length);
336
+ return uri.replace(/^file:\/\/\/?/, '');
337
+ }
338
+ }
339
+ // ---------------------------------------------------------------------------
340
+ // Singleton
341
+ // ---------------------------------------------------------------------------
342
+ let instance = null;
343
+ /** Get or create the singleton TsgoService for a project root */
344
+ export function getTsgoService(projectRoot) {
345
+ if (!instance || instance['projectRoot'] !== projectRoot) {
346
+ instance?.stop();
347
+ instance = new TsgoService(projectRoot);
348
+ }
349
+ return instance;
350
+ }
351
+ /** Stop the singleton if running */
352
+ export function stopTsgoService() {
353
+ instance?.stop();
354
+ instance = null;
355
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @file parser-loader.ts
3
+ * @description Tree-sitter parser initialization and language grammar loading
4
+ *
5
+ * Supports 14 languages via native tree-sitter bindings
6
+ * Swift and Kotlin are optional dependencies
7
+ */
8
+ import Parser from 'tree-sitter';
9
+ import { SupportedLanguages } from '../../config/supported-languages.js';
10
+ export declare const isLanguageAvailable: (language: SupportedLanguages) => boolean;
11
+ export declare const loadParser: () => Promise<Parser>;
12
+ export declare const loadLanguage: (language: SupportedLanguages, filePath?: string) => Promise<void>;
@@ -0,0 +1,71 @@
1
+ // code-mapper/src/core/tree-sitter/parser-loader.ts
2
+ /**
3
+ * @file parser-loader.ts
4
+ * @description Tree-sitter parser initialization and language grammar loading
5
+ *
6
+ * Supports 14 languages via native tree-sitter bindings
7
+ * Swift and Kotlin are optional dependencies
8
+ */
9
+ import Parser from 'tree-sitter';
10
+ import JavaScript from 'tree-sitter-javascript';
11
+ import TypeScript from 'tree-sitter-typescript';
12
+ import Python from 'tree-sitter-python';
13
+ import Java from 'tree-sitter-java';
14
+ import C from 'tree-sitter-c';
15
+ import CPP from 'tree-sitter-cpp';
16
+ import CSharp from 'tree-sitter-c-sharp';
17
+ import Go from 'tree-sitter-go';
18
+ import Rust from 'tree-sitter-rust';
19
+ import PHP from 'tree-sitter-php';
20
+ import Ruby from 'tree-sitter-ruby';
21
+ import { createRequire } from 'node:module';
22
+ import { SupportedLanguages } from '../../config/supported-languages.js';
23
+ // tree-sitter-swift is an optional dependency — may not be installed
24
+ const _require = createRequire(import.meta.url);
25
+ let Swift = null;
26
+ try {
27
+ Swift = _require('tree-sitter-swift');
28
+ }
29
+ catch { }
30
+ // tree-sitter-kotlin is an optional dependency — may not be installed
31
+ let Kotlin = null;
32
+ try {
33
+ Kotlin = _require('tree-sitter-kotlin');
34
+ }
35
+ catch { }
36
+ let parser = null;
37
+ const languageMap = {
38
+ [SupportedLanguages.JavaScript]: JavaScript,
39
+ [SupportedLanguages.TypeScript]: TypeScript.typescript,
40
+ [`${SupportedLanguages.TypeScript}:tsx`]: TypeScript.tsx,
41
+ [SupportedLanguages.Python]: Python,
42
+ [SupportedLanguages.Java]: Java,
43
+ [SupportedLanguages.C]: C,
44
+ [SupportedLanguages.CPlusPlus]: CPP,
45
+ [SupportedLanguages.CSharp]: CSharp,
46
+ [SupportedLanguages.Go]: Go,
47
+ [SupportedLanguages.Rust]: Rust,
48
+ ...(Kotlin ? { [SupportedLanguages.Kotlin]: Kotlin } : {}),
49
+ [SupportedLanguages.PHP]: PHP.php_only,
50
+ [SupportedLanguages.Ruby]: Ruby,
51
+ ...(Swift ? { [SupportedLanguages.Swift]: Swift } : {}),
52
+ };
53
+ export const isLanguageAvailable = (language) => language in languageMap;
54
+ export const loadParser = async () => {
55
+ if (parser)
56
+ return parser;
57
+ parser = new Parser();
58
+ return parser;
59
+ };
60
+ export const loadLanguage = async (language, filePath) => {
61
+ if (!parser)
62
+ await loadParser();
63
+ const key = language === SupportedLanguages.TypeScript && filePath?.endsWith('.tsx')
64
+ ? `${language}:tsx`
65
+ : language;
66
+ const lang = languageMap[key];
67
+ if (!lang) {
68
+ throw new Error(`Unsupported language: ${language}`);
69
+ }
70
+ parser.setLanguage(lang);
71
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @file Memory-aware guard that replaces static limits with adaptive behavior.
3
+ *
4
+ * Every processing loop can check isUnderPressure() or isCritical() to decide
5
+ * whether to continue, shrink batches, or flush caches. The only hard limits
6
+ * that remain are physical constraints (tree-sitter 32MB buffer).
7
+ */
8
+ declare class MemoryGuard {
9
+ private heapLimit;
10
+ constructor();
11
+ /** Re-read the heap limit (call after --max-old-space-size changes) */
12
+ refresh(): void;
13
+ /** Current heap usage in bytes */
14
+ private used;
15
+ /** True when heap usage exceeds 80% — start reducing batch sizes */
16
+ isUnderPressure(): boolean;
17
+ /** True when heap usage exceeds 92% — skip non-essential work */
18
+ isCritical(): boolean;
19
+ /** Bytes of heap still available, minus the reserved headroom */
20
+ availableBytes(): number;
21
+ /**
22
+ * Recommend a batch size based on available memory.
23
+ * @param perItemBytes Estimated memory per item in the batch
24
+ * @param defaultSize Batch size to use when memory is plentiful
25
+ * @returns A batch size between 1 and defaultSize
26
+ */
27
+ adaptiveBatchSize(perItemBytes: number, defaultSize: number): number;
28
+ /** Force garbage collection if --expose-gc is enabled, no-op otherwise */
29
+ tryGC(): void;
30
+ /** Current usage as a human-readable string (for logging) */
31
+ summary(): string;
32
+ }
33
+ /** Singleton instance */
34
+ export declare const memoryGuard: MemoryGuard;
35
+ export {};
@@ -0,0 +1,70 @@
1
+ // src/lib/memory-guard.ts
2
+ /**
3
+ * @file Memory-aware guard that replaces static limits with adaptive behavior.
4
+ *
5
+ * Every processing loop can check isUnderPressure() or isCritical() to decide
6
+ * whether to continue, shrink batches, or flush caches. The only hard limits
7
+ * that remain are physical constraints (tree-sitter 32MB buffer).
8
+ */
9
+ import v8 from 'v8';
10
+ /** Fraction of heap at which we start backing off (smaller batches, cache flushes) */
11
+ const PRESSURE_THRESHOLD = 0.80;
12
+ /** Fraction of heap at which we skip non-essential work */
13
+ const CRITICAL_THRESHOLD = 0.92;
14
+ /** Minimum headroom to reserve (200 MB) — prevents running right up to the limit */
15
+ const MIN_HEADROOM_BYTES = 200 * 1024 * 1024;
16
+ class MemoryGuard {
17
+ heapLimit;
18
+ constructor() {
19
+ this.heapLimit = v8.getHeapStatistics().heap_size_limit;
20
+ }
21
+ /** Re-read the heap limit (call after --max-old-space-size changes) */
22
+ refresh() {
23
+ this.heapLimit = v8.getHeapStatistics().heap_size_limit;
24
+ }
25
+ /** Current heap usage in bytes */
26
+ used() {
27
+ return process.memoryUsage().heapUsed;
28
+ }
29
+ /** True when heap usage exceeds 80% — start reducing batch sizes */
30
+ isUnderPressure() {
31
+ return this.used() / this.heapLimit > PRESSURE_THRESHOLD;
32
+ }
33
+ /** True when heap usage exceeds 92% — skip non-essential work */
34
+ isCritical() {
35
+ return this.used() / this.heapLimit > CRITICAL_THRESHOLD;
36
+ }
37
+ /** Bytes of heap still available, minus the reserved headroom */
38
+ availableBytes() {
39
+ return Math.max(0, this.heapLimit - this.used() - MIN_HEADROOM_BYTES);
40
+ }
41
+ /**
42
+ * Recommend a batch size based on available memory.
43
+ * @param perItemBytes Estimated memory per item in the batch
44
+ * @param defaultSize Batch size to use when memory is plentiful
45
+ * @returns A batch size between 1 and defaultSize
46
+ */
47
+ adaptiveBatchSize(perItemBytes, defaultSize) {
48
+ if (perItemBytes <= 0)
49
+ return defaultSize;
50
+ const available = this.availableBytes();
51
+ // Use at most 60% of available for the next batch (leave room for processing overhead)
52
+ const maxItems = Math.floor((available * 0.6) / perItemBytes);
53
+ return Math.max(1, Math.min(defaultSize, maxItems));
54
+ }
55
+ /** Force garbage collection if --expose-gc is enabled, no-op otherwise */
56
+ tryGC() {
57
+ if (typeof globalThis.gc === 'function') {
58
+ globalThis.gc();
59
+ }
60
+ }
61
+ /** Current usage as a human-readable string (for logging) */
62
+ summary() {
63
+ const usedMB = Math.round(this.used() / (1024 * 1024));
64
+ const limitMB = Math.round(this.heapLimit / (1024 * 1024));
65
+ const pct = Math.round((this.used() / this.heapLimit) * 100);
66
+ return `${usedMB}MB / ${limitMB}MB (${pct}%)`;
67
+ }
68
+ }
69
+ /** Singleton instance */
70
+ export const memoryGuard = new MemoryGuard();
@@ -0,0 +1,3 @@
1
+ /** @file utils.ts @description Shared utility functions for the code-mapper pipeline */
2
+ /** Generate a graph node ID from its label and name */
3
+ export declare const generateId: (label: string, name: string) => string;
@@ -0,0 +1,6 @@
1
+ // code-mapper/src/lib/utils.ts
2
+ /** @file utils.ts @description Shared utility functions for the code-mapper pipeline */
3
+ /** Generate a graph node ID from its label and name */
4
+ export const generateId = (label, name) => {
5
+ return `${label}:${name}`;
6
+ };
@@ -0,0 +1,32 @@
1
+ /** @file compatible-stdio-transport.ts
2
+ * @description MCP stdio transport that auto-detects content-length vs newline framing
3
+ * Handles both official MCP SDK clients and simpler newline-delimited JSON clients */
4
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
5
+ import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
6
+ export type StdioFraming = 'content-length' | 'newline';
7
+ export declare class CompatibleStdioServerTransport implements Transport {
8
+ private readonly _stdin;
9
+ private readonly _stdout;
10
+ private _readBuffer;
11
+ private _started;
12
+ private _framing;
13
+ /** Direct reference to the real write function, captured at construction time.
14
+ * Immune to process.stdout.write being replaced (e.g. embedder.ts silences
15
+ * stdout during ONNX model load, which would swallow MCP responses). */
16
+ private readonly _directWrite;
17
+ onmessage?: (message: JSONRPCMessage) => void;
18
+ onerror?: (error: Error) => void;
19
+ onclose?: () => void;
20
+ constructor(_stdin?: NodeJS.ReadableStream, _stdout?: NodeJS.WritableStream);
21
+ private readonly _ondata;
22
+ private readonly _onerror;
23
+ start(): Promise<void>;
24
+ private detectFraming;
25
+ private discardBufferedInput;
26
+ private readContentLengthMessage;
27
+ private readNewlineMessage;
28
+ private readMessage;
29
+ private processReadBuffer;
30
+ close(): Promise<void>;
31
+ send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
32
+ }