@veewo/gitnexus 1.3.4

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 (231) hide show
  1. package/README.md +234 -0
  2. package/dist/benchmark/agent-context/evaluators.d.ts +9 -0
  3. package/dist/benchmark/agent-context/evaluators.js +196 -0
  4. package/dist/benchmark/agent-context/evaluators.test.d.ts +1 -0
  5. package/dist/benchmark/agent-context/evaluators.test.js +39 -0
  6. package/dist/benchmark/agent-context/io.d.ts +2 -0
  7. package/dist/benchmark/agent-context/io.js +23 -0
  8. package/dist/benchmark/agent-context/io.test.d.ts +1 -0
  9. package/dist/benchmark/agent-context/io.test.js +19 -0
  10. package/dist/benchmark/agent-context/report.d.ts +2 -0
  11. package/dist/benchmark/agent-context/report.js +59 -0
  12. package/dist/benchmark/agent-context/report.test.d.ts +1 -0
  13. package/dist/benchmark/agent-context/report.test.js +85 -0
  14. package/dist/benchmark/agent-context/runner.d.ts +46 -0
  15. package/dist/benchmark/agent-context/runner.js +111 -0
  16. package/dist/benchmark/agent-context/runner.test.d.ts +1 -0
  17. package/dist/benchmark/agent-context/runner.test.js +79 -0
  18. package/dist/benchmark/agent-context/tool-runner.d.ts +7 -0
  19. package/dist/benchmark/agent-context/tool-runner.js +18 -0
  20. package/dist/benchmark/agent-context/tool-runner.test.d.ts +1 -0
  21. package/dist/benchmark/agent-context/tool-runner.test.js +11 -0
  22. package/dist/benchmark/agent-context/types.d.ts +40 -0
  23. package/dist/benchmark/agent-context/types.js +1 -0
  24. package/dist/benchmark/analyze-runner.d.ts +16 -0
  25. package/dist/benchmark/analyze-runner.js +51 -0
  26. package/dist/benchmark/analyze-runner.test.d.ts +1 -0
  27. package/dist/benchmark/analyze-runner.test.js +37 -0
  28. package/dist/benchmark/evaluators.d.ts +6 -0
  29. package/dist/benchmark/evaluators.js +10 -0
  30. package/dist/benchmark/evaluators.test.d.ts +1 -0
  31. package/dist/benchmark/evaluators.test.js +12 -0
  32. package/dist/benchmark/io.d.ts +7 -0
  33. package/dist/benchmark/io.js +25 -0
  34. package/dist/benchmark/io.test.d.ts +1 -0
  35. package/dist/benchmark/io.test.js +35 -0
  36. package/dist/benchmark/neonspark-candidates.d.ts +19 -0
  37. package/dist/benchmark/neonspark-candidates.js +94 -0
  38. package/dist/benchmark/neonspark-candidates.test.d.ts +1 -0
  39. package/dist/benchmark/neonspark-candidates.test.js +43 -0
  40. package/dist/benchmark/neonspark-materialize.d.ts +19 -0
  41. package/dist/benchmark/neonspark-materialize.js +111 -0
  42. package/dist/benchmark/neonspark-materialize.test.d.ts +1 -0
  43. package/dist/benchmark/neonspark-materialize.test.js +124 -0
  44. package/dist/benchmark/neonspark-sync.d.ts +3 -0
  45. package/dist/benchmark/neonspark-sync.js +53 -0
  46. package/dist/benchmark/neonspark-sync.test.d.ts +1 -0
  47. package/dist/benchmark/neonspark-sync.test.js +20 -0
  48. package/dist/benchmark/report.d.ts +1 -0
  49. package/dist/benchmark/report.js +7 -0
  50. package/dist/benchmark/runner.d.ts +48 -0
  51. package/dist/benchmark/runner.js +302 -0
  52. package/dist/benchmark/runner.test.d.ts +1 -0
  53. package/dist/benchmark/runner.test.js +50 -0
  54. package/dist/benchmark/scoring.d.ts +16 -0
  55. package/dist/benchmark/scoring.js +27 -0
  56. package/dist/benchmark/scoring.test.d.ts +1 -0
  57. package/dist/benchmark/scoring.test.js +24 -0
  58. package/dist/benchmark/tool-runner.d.ts +6 -0
  59. package/dist/benchmark/tool-runner.js +17 -0
  60. package/dist/benchmark/types.d.ts +36 -0
  61. package/dist/benchmark/types.js +1 -0
  62. package/dist/cli/ai-context.d.ts +22 -0
  63. package/dist/cli/ai-context.js +184 -0
  64. package/dist/cli/ai-context.test.d.ts +1 -0
  65. package/dist/cli/ai-context.test.js +30 -0
  66. package/dist/cli/analyze-multi-scope-regression.test.d.ts +1 -0
  67. package/dist/cli/analyze-multi-scope-regression.test.js +22 -0
  68. package/dist/cli/analyze-options.d.ts +7 -0
  69. package/dist/cli/analyze-options.js +56 -0
  70. package/dist/cli/analyze-options.test.d.ts +1 -0
  71. package/dist/cli/analyze-options.test.js +36 -0
  72. package/dist/cli/analyze.d.ts +14 -0
  73. package/dist/cli/analyze.js +384 -0
  74. package/dist/cli/augment.d.ts +13 -0
  75. package/dist/cli/augment.js +33 -0
  76. package/dist/cli/benchmark-agent-context.d.ts +29 -0
  77. package/dist/cli/benchmark-agent-context.js +61 -0
  78. package/dist/cli/benchmark-agent-context.test.d.ts +1 -0
  79. package/dist/cli/benchmark-agent-context.test.js +80 -0
  80. package/dist/cli/benchmark-unity.d.ts +15 -0
  81. package/dist/cli/benchmark-unity.js +31 -0
  82. package/dist/cli/benchmark-unity.test.d.ts +1 -0
  83. package/dist/cli/benchmark-unity.test.js +18 -0
  84. package/dist/cli/claude-hooks.d.ts +22 -0
  85. package/dist/cli/claude-hooks.js +97 -0
  86. package/dist/cli/clean.d.ts +10 -0
  87. package/dist/cli/clean.js +60 -0
  88. package/dist/cli/eval-server.d.ts +30 -0
  89. package/dist/cli/eval-server.js +372 -0
  90. package/dist/cli/index.d.ts +2 -0
  91. package/dist/cli/index.js +182 -0
  92. package/dist/cli/list.d.ts +6 -0
  93. package/dist/cli/list.js +33 -0
  94. package/dist/cli/mcp.d.ts +8 -0
  95. package/dist/cli/mcp.js +34 -0
  96. package/dist/cli/repo-manager-alias.test.d.ts +1 -0
  97. package/dist/cli/repo-manager-alias.test.js +40 -0
  98. package/dist/cli/scope-filter.test.d.ts +1 -0
  99. package/dist/cli/scope-filter.test.js +49 -0
  100. package/dist/cli/serve.d.ts +4 -0
  101. package/dist/cli/serve.js +6 -0
  102. package/dist/cli/setup.d.ts +8 -0
  103. package/dist/cli/setup.js +311 -0
  104. package/dist/cli/setup.test.d.ts +1 -0
  105. package/dist/cli/setup.test.js +31 -0
  106. package/dist/cli/status.d.ts +6 -0
  107. package/dist/cli/status.js +27 -0
  108. package/dist/cli/tool.d.ts +40 -0
  109. package/dist/cli/tool.js +94 -0
  110. package/dist/cli/version.test.d.ts +1 -0
  111. package/dist/cli/version.test.js +19 -0
  112. package/dist/cli/wiki.d.ts +15 -0
  113. package/dist/cli/wiki.js +361 -0
  114. package/dist/config/ignore-service.d.ts +1 -0
  115. package/dist/config/ignore-service.js +210 -0
  116. package/dist/config/supported-languages.d.ts +12 -0
  117. package/dist/config/supported-languages.js +15 -0
  118. package/dist/core/augmentation/engine.d.ts +26 -0
  119. package/dist/core/augmentation/engine.js +213 -0
  120. package/dist/core/embeddings/embedder.d.ts +60 -0
  121. package/dist/core/embeddings/embedder.js +251 -0
  122. package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
  123. package/dist/core/embeddings/embedding-pipeline.js +329 -0
  124. package/dist/core/embeddings/index.d.ts +9 -0
  125. package/dist/core/embeddings/index.js +9 -0
  126. package/dist/core/embeddings/text-generator.d.ts +24 -0
  127. package/dist/core/embeddings/text-generator.js +182 -0
  128. package/dist/core/embeddings/types.d.ts +87 -0
  129. package/dist/core/embeddings/types.js +32 -0
  130. package/dist/core/graph/graph.d.ts +2 -0
  131. package/dist/core/graph/graph.js +66 -0
  132. package/dist/core/graph/types.d.ts +61 -0
  133. package/dist/core/graph/types.js +1 -0
  134. package/dist/core/ingestion/ast-cache.d.ts +11 -0
  135. package/dist/core/ingestion/ast-cache.js +34 -0
  136. package/dist/core/ingestion/call-processor.d.ts +15 -0
  137. package/dist/core/ingestion/call-processor.js +327 -0
  138. package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
  139. package/dist/core/ingestion/cluster-enricher.js +170 -0
  140. package/dist/core/ingestion/community-processor.d.ts +39 -0
  141. package/dist/core/ingestion/community-processor.js +312 -0
  142. package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
  143. package/dist/core/ingestion/entry-point-scoring.js +260 -0
  144. package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
  145. package/dist/core/ingestion/filesystem-walker.js +80 -0
  146. package/dist/core/ingestion/framework-detection.d.ts +39 -0
  147. package/dist/core/ingestion/framework-detection.js +235 -0
  148. package/dist/core/ingestion/heritage-processor.d.ts +20 -0
  149. package/dist/core/ingestion/heritage-processor.js +197 -0
  150. package/dist/core/ingestion/import-processor.d.ts +38 -0
  151. package/dist/core/ingestion/import-processor.js +778 -0
  152. package/dist/core/ingestion/parsing-processor.d.ts +15 -0
  153. package/dist/core/ingestion/parsing-processor.js +291 -0
  154. package/dist/core/ingestion/pipeline.d.ts +5 -0
  155. package/dist/core/ingestion/pipeline.js +323 -0
  156. package/dist/core/ingestion/process-processor.d.ts +51 -0
  157. package/dist/core/ingestion/process-processor.js +309 -0
  158. package/dist/core/ingestion/scope-filter.d.ts +25 -0
  159. package/dist/core/ingestion/scope-filter.js +100 -0
  160. package/dist/core/ingestion/structure-processor.d.ts +2 -0
  161. package/dist/core/ingestion/structure-processor.js +36 -0
  162. package/dist/core/ingestion/symbol-table.d.ts +33 -0
  163. package/dist/core/ingestion/symbol-table.js +38 -0
  164. package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -0
  165. package/dist/core/ingestion/tree-sitter-queries.js +398 -0
  166. package/dist/core/ingestion/utils.d.ts +10 -0
  167. package/dist/core/ingestion/utils.js +50 -0
  168. package/dist/core/ingestion/workers/parse-worker.d.ts +59 -0
  169. package/dist/core/ingestion/workers/parse-worker.js +672 -0
  170. package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
  171. package/dist/core/ingestion/workers/worker-pool.js +120 -0
  172. package/dist/core/kuzu/csv-generator.d.ts +29 -0
  173. package/dist/core/kuzu/csv-generator.js +336 -0
  174. package/dist/core/kuzu/kuzu-adapter.d.ts +101 -0
  175. package/dist/core/kuzu/kuzu-adapter.js +753 -0
  176. package/dist/core/kuzu/schema.d.ts +53 -0
  177. package/dist/core/kuzu/schema.js +407 -0
  178. package/dist/core/search/bm25-index.d.ts +23 -0
  179. package/dist/core/search/bm25-index.js +95 -0
  180. package/dist/core/search/hybrid-search.d.ts +49 -0
  181. package/dist/core/search/hybrid-search.js +118 -0
  182. package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
  183. package/dist/core/tree-sitter/parser-loader.js +44 -0
  184. package/dist/core/wiki/generator.d.ts +110 -0
  185. package/dist/core/wiki/generator.js +786 -0
  186. package/dist/core/wiki/graph-queries.d.ts +80 -0
  187. package/dist/core/wiki/graph-queries.js +238 -0
  188. package/dist/core/wiki/html-viewer.d.ts +10 -0
  189. package/dist/core/wiki/html-viewer.js +297 -0
  190. package/dist/core/wiki/llm-client.d.ts +40 -0
  191. package/dist/core/wiki/llm-client.js +162 -0
  192. package/dist/core/wiki/prompts.d.ts +53 -0
  193. package/dist/core/wiki/prompts.js +174 -0
  194. package/dist/lib/utils.d.ts +1 -0
  195. package/dist/lib/utils.js +3 -0
  196. package/dist/mcp/core/embedder.d.ts +27 -0
  197. package/dist/mcp/core/embedder.js +108 -0
  198. package/dist/mcp/core/kuzu-adapter.d.ts +34 -0
  199. package/dist/mcp/core/kuzu-adapter.js +231 -0
  200. package/dist/mcp/local/local-backend.d.ts +160 -0
  201. package/dist/mcp/local/local-backend.js +1646 -0
  202. package/dist/mcp/resources.d.ts +31 -0
  203. package/dist/mcp/resources.js +407 -0
  204. package/dist/mcp/server.d.ts +23 -0
  205. package/dist/mcp/server.js +251 -0
  206. package/dist/mcp/staleness.d.ts +15 -0
  207. package/dist/mcp/staleness.js +29 -0
  208. package/dist/mcp/tools.d.ts +24 -0
  209. package/dist/mcp/tools.js +195 -0
  210. package/dist/server/api.d.ts +10 -0
  211. package/dist/server/api.js +344 -0
  212. package/dist/server/mcp-http.d.ts +13 -0
  213. package/dist/server/mcp-http.js +100 -0
  214. package/dist/storage/git.d.ts +6 -0
  215. package/dist/storage/git.js +32 -0
  216. package/dist/storage/repo-manager.d.ts +125 -0
  217. package/dist/storage/repo-manager.js +257 -0
  218. package/dist/types/pipeline.d.ts +34 -0
  219. package/dist/types/pipeline.js +18 -0
  220. package/hooks/claude/gitnexus-hook.cjs +135 -0
  221. package/hooks/claude/pre-tool-use.sh +78 -0
  222. package/hooks/claude/session-start.sh +42 -0
  223. package/package.json +92 -0
  224. package/skills/gitnexus-cli.md +82 -0
  225. package/skills/gitnexus-debugging.md +89 -0
  226. package/skills/gitnexus-exploring.md +78 -0
  227. package/skills/gitnexus-guide.md +64 -0
  228. package/skills/gitnexus-impact-analysis.md +97 -0
  229. package/skills/gitnexus-refactoring.md +121 -0
  230. package/vendor/leiden/index.cjs +355 -0
  231. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,672 @@
1
+ import { parentPort } from 'node:worker_threads';
2
+ import Parser from 'tree-sitter';
3
+ import JavaScript from 'tree-sitter-javascript';
4
+ import TypeScript from 'tree-sitter-typescript';
5
+ import Python from 'tree-sitter-python';
6
+ import Java from 'tree-sitter-java';
7
+ import C from 'tree-sitter-c';
8
+ import CPP from 'tree-sitter-cpp';
9
+ import CSharp from 'tree-sitter-c-sharp';
10
+ import Go from 'tree-sitter-go';
11
+ import Rust from 'tree-sitter-rust';
12
+ import PHP from 'tree-sitter-php';
13
+ import { SupportedLanguages } from '../../../config/supported-languages.js';
14
+ import { LANGUAGE_QUERIES } from '../tree-sitter-queries.js';
15
+ import { getLanguageFromFilename } from '../utils.js';
16
+ import { generateId } from '../../../lib/utils.js';
17
+ // ============================================================================
18
+ // Worker-local parser + language map
19
+ // ============================================================================
20
+ const parser = new Parser();
21
+ const languageMap = {
22
+ [SupportedLanguages.JavaScript]: JavaScript,
23
+ [SupportedLanguages.TypeScript]: TypeScript.typescript,
24
+ [`${SupportedLanguages.TypeScript}:tsx`]: TypeScript.tsx,
25
+ [SupportedLanguages.Python]: Python,
26
+ [SupportedLanguages.Java]: Java,
27
+ [SupportedLanguages.C]: C,
28
+ [SupportedLanguages.CPlusPlus]: CPP,
29
+ [SupportedLanguages.CSharp]: CSharp,
30
+ [SupportedLanguages.Go]: Go,
31
+ [SupportedLanguages.Rust]: Rust,
32
+ [SupportedLanguages.PHP]: PHP.php_only,
33
+ };
34
+ const setLanguage = (language, filePath) => {
35
+ const key = language === SupportedLanguages.TypeScript && filePath.endsWith('.tsx')
36
+ ? `${language}:tsx`
37
+ : language;
38
+ const lang = languageMap[key];
39
+ if (!lang)
40
+ throw new Error(`Unsupported language: ${language}`);
41
+ parser.setLanguage(lang);
42
+ };
43
+ // ============================================================================
44
+ // Export detection (copied — needs AST parent traversal, can't cross threads)
45
+ // ============================================================================
46
+ const isNodeExported = (node, name, language) => {
47
+ let current = node;
48
+ switch (language) {
49
+ case 'javascript':
50
+ case 'typescript':
51
+ while (current) {
52
+ const type = current.type;
53
+ if (type === 'export_statement' ||
54
+ type === 'export_specifier' ||
55
+ type === 'lexical_declaration' && current.parent?.type === 'export_statement') {
56
+ return true;
57
+ }
58
+ if (current.text?.startsWith('export ')) {
59
+ return true;
60
+ }
61
+ current = current.parent;
62
+ }
63
+ return false;
64
+ case 'python':
65
+ return !name.startsWith('_');
66
+ case 'java':
67
+ while (current) {
68
+ if (current.parent) {
69
+ const parent = current.parent;
70
+ for (let i = 0; i < parent.childCount; i++) {
71
+ const child = parent.child(i);
72
+ if (child?.type === 'modifiers' && child.text?.includes('public')) {
73
+ return true;
74
+ }
75
+ }
76
+ if (parent.type === 'method_declaration' || parent.type === 'constructor_declaration') {
77
+ if (parent.text?.trimStart().startsWith('public')) {
78
+ return true;
79
+ }
80
+ }
81
+ }
82
+ current = current.parent;
83
+ }
84
+ return false;
85
+ case 'csharp':
86
+ while (current) {
87
+ if (current.type === 'modifier' || current.type === 'modifiers') {
88
+ if (current.text?.includes('public'))
89
+ return true;
90
+ }
91
+ current = current.parent;
92
+ }
93
+ return false;
94
+ case 'go':
95
+ if (name.length === 0)
96
+ return false;
97
+ const first = name[0];
98
+ return first === first.toUpperCase() && first !== first.toLowerCase();
99
+ case 'rust':
100
+ while (current) {
101
+ if (current.type === 'visibility_modifier') {
102
+ if (current.text?.includes('pub'))
103
+ return true;
104
+ }
105
+ current = current.parent;
106
+ }
107
+ return false;
108
+ case 'c':
109
+ case 'cpp':
110
+ return false;
111
+ case 'php':
112
+ // Top-level classes/interfaces/traits are always accessible
113
+ // Methods/properties are exported only if they have 'public' modifier
114
+ while (current) {
115
+ if (current.type === 'class_declaration' ||
116
+ current.type === 'interface_declaration' ||
117
+ current.type === 'trait_declaration' ||
118
+ current.type === 'enum_declaration') {
119
+ return true;
120
+ }
121
+ if (current.type === 'visibility_modifier') {
122
+ return current.text === 'public';
123
+ }
124
+ current = current.parent;
125
+ }
126
+ // Top-level functions (no parent class) are globally accessible
127
+ return true;
128
+ default:
129
+ return false;
130
+ }
131
+ };
132
+ // ============================================================================
133
+ // Enclosing function detection (for call extraction)
134
+ // ============================================================================
135
+ const FUNCTION_NODE_TYPES = new Set([
136
+ 'function_declaration', 'arrow_function', 'function_expression',
137
+ 'method_definition', 'generator_function_declaration',
138
+ 'function_definition', 'async_function_declaration', 'async_arrow_function',
139
+ 'method_declaration', 'constructor_declaration',
140
+ 'local_function_statement', 'function_item', 'impl_item',
141
+ 'anonymous_function_creation_expression', // PHP anonymous functions
142
+ ]);
143
+ /** Walk up AST to find enclosing function, return its generateId or null for top-level */
144
+ const findEnclosingFunctionId = (node, filePath) => {
145
+ let current = node.parent;
146
+ while (current) {
147
+ if (FUNCTION_NODE_TYPES.has(current.type)) {
148
+ let funcName = null;
149
+ let label = 'Function';
150
+ if (['function_declaration', 'function_definition', 'async_function_declaration',
151
+ 'generator_function_declaration', 'function_item'].includes(current.type)) {
152
+ const nameNode = current.childForFieldName?.('name') ||
153
+ current.children?.find((c) => c.type === 'identifier' || c.type === 'property_identifier');
154
+ funcName = nameNode?.text;
155
+ }
156
+ else if (current.type === 'impl_item') {
157
+ const funcItem = current.children?.find((c) => c.type === 'function_item');
158
+ if (funcItem) {
159
+ const nameNode = funcItem.childForFieldName?.('name') ||
160
+ funcItem.children?.find((c) => c.type === 'identifier');
161
+ funcName = nameNode?.text;
162
+ label = 'Method';
163
+ }
164
+ }
165
+ else if (current.type === 'method_definition') {
166
+ const nameNode = current.childForFieldName?.('name') ||
167
+ current.children?.find((c) => c.type === 'property_identifier');
168
+ funcName = nameNode?.text;
169
+ label = 'Method';
170
+ }
171
+ else if (current.type === 'method_declaration' || current.type === 'constructor_declaration') {
172
+ const nameNode = current.childForFieldName?.('name') ||
173
+ current.children?.find((c) => c.type === 'identifier');
174
+ funcName = nameNode?.text;
175
+ label = 'Method';
176
+ }
177
+ else if (current.type === 'arrow_function' || current.type === 'function_expression') {
178
+ const parent = current.parent;
179
+ if (parent?.type === 'variable_declarator') {
180
+ const nameNode = parent.childForFieldName?.('name') ||
181
+ parent.children?.find((c) => c.type === 'identifier');
182
+ funcName = nameNode?.text;
183
+ }
184
+ }
185
+ if (funcName) {
186
+ return generateId(label, `${filePath}:${funcName}`);
187
+ }
188
+ }
189
+ current = current.parent;
190
+ }
191
+ return null;
192
+ };
193
+ const BUILT_INS = new Set([
194
+ // JavaScript/TypeScript
195
+ 'console', 'log', 'warn', 'error', 'info', 'debug',
196
+ 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
197
+ 'parseInt', 'parseFloat', 'isNaN', 'isFinite',
198
+ 'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
199
+ 'JSON', 'parse', 'stringify',
200
+ 'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
201
+ 'Map', 'Set', 'WeakMap', 'WeakSet',
202
+ 'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
203
+ 'Math', 'Date', 'RegExp', 'Error',
204
+ 'require', 'import', 'export', 'fetch', 'Response', 'Request',
205
+ 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
206
+ 'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
207
+ 'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
208
+ 'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
209
+ 'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
210
+ 'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
211
+ 'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
212
+ 'hasOwnProperty', 'toString', 'valueOf',
213
+ // Python
214
+ 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
215
+ 'open', 'read', 'write', 'close', 'append', 'extend', 'update',
216
+ 'super', 'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
217
+ 'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
218
+ // C/C++ standard library
219
+ 'printf', 'fprintf', 'sprintf', 'snprintf', 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
220
+ 'scanf', 'fscanf', 'sscanf',
221
+ 'malloc', 'calloc', 'realloc', 'free', 'memcpy', 'memmove', 'memset', 'memcmp',
222
+ 'strlen', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strstr', 'strchr', 'strrchr',
223
+ 'atoi', 'atol', 'atof', 'strtol', 'strtoul', 'strtoll', 'strtoull', 'strtod',
224
+ 'sizeof', 'offsetof', 'typeof',
225
+ 'assert', 'abort', 'exit', '_exit',
226
+ 'fopen', 'fclose', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', 'fflush', 'fgets', 'fputs',
227
+ // Linux kernel common macros/helpers (not real call targets)
228
+ 'likely', 'unlikely', 'BUG', 'BUG_ON', 'WARN', 'WARN_ON', 'WARN_ONCE',
229
+ 'IS_ERR', 'PTR_ERR', 'ERR_PTR', 'IS_ERR_OR_NULL',
230
+ 'ARRAY_SIZE', 'container_of', 'list_for_each_entry', 'list_for_each_entry_safe',
231
+ 'min', 'max', 'clamp', 'abs', 'swap',
232
+ 'pr_info', 'pr_warn', 'pr_err', 'pr_debug', 'pr_notice', 'pr_crit', 'pr_emerg',
233
+ 'printk', 'dev_info', 'dev_warn', 'dev_err', 'dev_dbg',
234
+ 'GFP_KERNEL', 'GFP_ATOMIC',
235
+ 'spin_lock', 'spin_unlock', 'spin_lock_irqsave', 'spin_unlock_irqrestore',
236
+ 'mutex_lock', 'mutex_unlock', 'mutex_init',
237
+ 'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
238
+ 'get', 'put',
239
+ // PHP built-ins
240
+ 'echo', 'isset', 'empty', 'unset', 'list', 'array', 'compact', 'extract',
241
+ 'count', 'strlen', 'strpos', 'strrpos', 'substr', 'strtolower', 'strtoupper', 'trim',
242
+ 'ltrim', 'rtrim', 'str_replace', 'str_contains', 'str_starts_with', 'str_ends_with',
243
+ 'sprintf', 'vsprintf', 'printf', 'number_format',
244
+ 'array_map', 'array_filter', 'array_reduce', 'array_push', 'array_pop', 'array_shift',
245
+ 'array_unshift', 'array_slice', 'array_splice', 'array_merge', 'array_keys', 'array_values',
246
+ 'array_key_exists', 'in_array', 'array_search', 'array_unique', 'usort', 'rsort',
247
+ 'json_encode', 'json_decode', 'serialize', 'unserialize',
248
+ 'intval', 'floatval', 'strval', 'boolval', 'is_null', 'is_string', 'is_int', 'is_array',
249
+ 'is_object', 'is_numeric', 'is_bool', 'is_float',
250
+ 'var_dump', 'print_r', 'var_export',
251
+ 'date', 'time', 'strtotime', 'mktime', 'microtime',
252
+ 'file_exists', 'file_get_contents', 'file_put_contents', 'is_file', 'is_dir',
253
+ 'preg_match', 'preg_match_all', 'preg_replace', 'preg_split',
254
+ 'header', 'session_start', 'session_destroy', 'ob_start', 'ob_end_clean', 'ob_get_clean',
255
+ 'dd', 'dump',
256
+ ]);
257
+ // ============================================================================
258
+ // Label detection from capture map
259
+ // ============================================================================
260
+ const getLabelFromCaptures = (captureMap) => {
261
+ // Skip imports (handled separately) and calls
262
+ if (captureMap['import'] || captureMap['call'])
263
+ return null;
264
+ if (!captureMap['name'])
265
+ return null;
266
+ if (captureMap['definition.function'])
267
+ return 'Function';
268
+ if (captureMap['definition.class'])
269
+ return 'Class';
270
+ if (captureMap['definition.interface'])
271
+ return 'Interface';
272
+ if (captureMap['definition.method'])
273
+ return 'Method';
274
+ if (captureMap['definition.struct'])
275
+ return 'Struct';
276
+ if (captureMap['definition.enum'])
277
+ return 'Enum';
278
+ if (captureMap['definition.namespace'])
279
+ return 'Namespace';
280
+ if (captureMap['definition.module'])
281
+ return 'Module';
282
+ if (captureMap['definition.trait'])
283
+ return 'Trait';
284
+ if (captureMap['definition.impl'])
285
+ return 'Impl';
286
+ if (captureMap['definition.type'])
287
+ return 'TypeAlias';
288
+ if (captureMap['definition.const'])
289
+ return 'Const';
290
+ if (captureMap['definition.static'])
291
+ return 'Static';
292
+ if (captureMap['definition.typedef'])
293
+ return 'Typedef';
294
+ if (captureMap['definition.macro'])
295
+ return 'Macro';
296
+ if (captureMap['definition.union'])
297
+ return 'Union';
298
+ if (captureMap['definition.property'])
299
+ return 'Property';
300
+ if (captureMap['definition.record'])
301
+ return 'Record';
302
+ if (captureMap['definition.delegate'])
303
+ return 'Delegate';
304
+ if (captureMap['definition.annotation'])
305
+ return 'Annotation';
306
+ if (captureMap['definition.constructor'])
307
+ return 'Constructor';
308
+ if (captureMap['definition.template'])
309
+ return 'Template';
310
+ return 'CodeElement';
311
+ };
312
+ // ============================================================================
313
+ // Process a batch of files
314
+ // ============================================================================
315
+ const processBatch = (files, onProgress) => {
316
+ const result = {
317
+ nodes: [],
318
+ relationships: [],
319
+ symbols: [],
320
+ imports: [],
321
+ calls: [],
322
+ heritage: [],
323
+ fileCount: 0,
324
+ };
325
+ // Group by language to minimize setLanguage calls
326
+ const byLanguage = new Map();
327
+ for (const file of files) {
328
+ const lang = getLanguageFromFilename(file.path);
329
+ if (!lang)
330
+ continue;
331
+ let list = byLanguage.get(lang);
332
+ if (!list) {
333
+ list = [];
334
+ byLanguage.set(lang, list);
335
+ }
336
+ list.push(file);
337
+ }
338
+ let totalProcessed = 0;
339
+ let lastReported = 0;
340
+ const PROGRESS_INTERVAL = 100; // report every 100 files
341
+ const onFileProcessed = onProgress ? () => {
342
+ totalProcessed++;
343
+ if (totalProcessed - lastReported >= PROGRESS_INTERVAL) {
344
+ lastReported = totalProcessed;
345
+ onProgress(totalProcessed);
346
+ }
347
+ } : undefined;
348
+ for (const [language, langFiles] of byLanguage) {
349
+ const queryString = LANGUAGE_QUERIES[language];
350
+ if (!queryString)
351
+ continue;
352
+ // Track if we need to handle tsx separately
353
+ const tsxFiles = [];
354
+ const regularFiles = [];
355
+ if (language === SupportedLanguages.TypeScript) {
356
+ for (const f of langFiles) {
357
+ if (f.path.endsWith('.tsx')) {
358
+ tsxFiles.push(f);
359
+ }
360
+ else {
361
+ regularFiles.push(f);
362
+ }
363
+ }
364
+ }
365
+ else {
366
+ regularFiles.push(...langFiles);
367
+ }
368
+ // Process regular files for this language
369
+ if (regularFiles.length > 0) {
370
+ setLanguage(language, regularFiles[0].path);
371
+ processFileGroup(regularFiles, language, queryString, result, onFileProcessed);
372
+ }
373
+ // Process tsx files separately (different grammar)
374
+ if (tsxFiles.length > 0) {
375
+ setLanguage(language, tsxFiles[0].path);
376
+ processFileGroup(tsxFiles, language, queryString, result, onFileProcessed);
377
+ }
378
+ }
379
+ return result;
380
+ };
381
+ // ============================================================================
382
+ // PHP Eloquent metadata extraction
383
+ // ============================================================================
384
+ /** Eloquent model properties whose array values are worth indexing */
385
+ const ELOQUENT_ARRAY_PROPS = new Set(['fillable', 'casts', 'hidden', 'guarded', 'with', 'appends']);
386
+ /** Eloquent relationship method names */
387
+ const ELOQUENT_RELATIONS = new Set([
388
+ 'hasMany', 'hasOne', 'belongsTo', 'belongsToMany',
389
+ 'morphTo', 'morphMany', 'morphOne', 'morphToMany', 'morphedByMany',
390
+ 'hasManyThrough', 'hasOneThrough',
391
+ ]);
392
+ function findDescendant(node, type) {
393
+ if (node.type === type)
394
+ return node;
395
+ for (const child of (node.children ?? [])) {
396
+ const found = findDescendant(child, type);
397
+ if (found)
398
+ return found;
399
+ }
400
+ return null;
401
+ }
402
+ function extractStringContent(node) {
403
+ if (!node)
404
+ return null;
405
+ const content = node.children?.find((c) => c.type === 'string_content');
406
+ if (content)
407
+ return content.text;
408
+ if (node.type === 'string_content')
409
+ return node.text;
410
+ return null;
411
+ }
412
+ /**
413
+ * For a PHP property_declaration node, extract array values as a description string.
414
+ * Returns null if not an Eloquent model property or no array values found.
415
+ */
416
+ function extractPhpPropertyDescription(propName, propDeclNode) {
417
+ if (!ELOQUENT_ARRAY_PROPS.has(propName))
418
+ return null;
419
+ const arrayNode = findDescendant(propDeclNode, 'array_creation_expression');
420
+ if (!arrayNode)
421
+ return null;
422
+ const items = [];
423
+ for (const child of (arrayNode.children ?? [])) {
424
+ if (child.type !== 'array_element_initializer')
425
+ continue;
426
+ const children = child.children ?? [];
427
+ const arrowIdx = children.findIndex((c) => c.type === '=>');
428
+ if (arrowIdx !== -1) {
429
+ // key => value pair (used in $casts)
430
+ const key = extractStringContent(children[arrowIdx - 1]);
431
+ const val = extractStringContent(children[arrowIdx + 1]);
432
+ if (key && val)
433
+ items.push(`${key}:${val}`);
434
+ }
435
+ else {
436
+ // Simple value (used in $fillable, $hidden, etc.)
437
+ const val = extractStringContent(children[0]);
438
+ if (val)
439
+ items.push(val);
440
+ }
441
+ }
442
+ return items.length > 0 ? items.join(', ') : null;
443
+ }
444
+ /**
445
+ * For a PHP method_declaration node, detect if it defines an Eloquent relationship.
446
+ * Returns description like "hasMany(Post)" or null.
447
+ */
448
+ function extractEloquentRelationDescription(methodNode) {
449
+ function findRelationCall(node) {
450
+ if (node.type === 'member_call_expression') {
451
+ const children = node.children ?? [];
452
+ const objectNode = children.find((c) => c.type === 'variable_name' && c.text === '$this');
453
+ const nameNode = children.find((c) => c.type === 'name');
454
+ if (objectNode && nameNode && ELOQUENT_RELATIONS.has(nameNode.text))
455
+ return node;
456
+ }
457
+ for (const child of (node.children ?? [])) {
458
+ const found = findRelationCall(child);
459
+ if (found)
460
+ return found;
461
+ }
462
+ return null;
463
+ }
464
+ const callNode = findRelationCall(methodNode);
465
+ if (!callNode)
466
+ return null;
467
+ const relType = callNode.children?.find((c) => c.type === 'name')?.text;
468
+ const argsNode = callNode.children?.find((c) => c.type === 'arguments');
469
+ let targetModel = null;
470
+ if (argsNode) {
471
+ const firstArg = argsNode.children?.find((c) => c.type === 'argument');
472
+ if (firstArg) {
473
+ const classConstant = firstArg.children?.find((c) => c.type === 'class_constant_access_expression');
474
+ if (classConstant) {
475
+ targetModel = classConstant.children?.find((c) => c.type === 'name')?.text ?? null;
476
+ }
477
+ }
478
+ }
479
+ if (relType && targetModel)
480
+ return `${relType}(${targetModel})`;
481
+ if (relType)
482
+ return relType;
483
+ return null;
484
+ }
485
+ const processFileGroup = (files, language, queryString, result, onFileProcessed) => {
486
+ let query;
487
+ try {
488
+ const lang = parser.getLanguage();
489
+ query = new Parser.Query(lang, queryString);
490
+ }
491
+ catch {
492
+ return;
493
+ }
494
+ for (const file of files) {
495
+ // Skip very large files — they can crash tree-sitter or cause OOM
496
+ if (file.content.length > 512 * 1024)
497
+ continue;
498
+ let tree;
499
+ try {
500
+ tree = parser.parse(file.content, undefined, { bufferSize: 1024 * 256 });
501
+ }
502
+ catch {
503
+ continue;
504
+ }
505
+ result.fileCount++;
506
+ onFileProcessed?.();
507
+ let matches;
508
+ try {
509
+ matches = query.matches(tree.rootNode);
510
+ }
511
+ catch {
512
+ continue;
513
+ }
514
+ for (const match of matches) {
515
+ const captureMap = {};
516
+ for (const c of match.captures) {
517
+ captureMap[c.name] = c.node;
518
+ }
519
+ // Extract import paths before skipping
520
+ if (captureMap['import'] && captureMap['import.source']) {
521
+ const rawImportPath = captureMap['import.source'].text.replace(/['"<>]/g, '');
522
+ result.imports.push({
523
+ filePath: file.path,
524
+ rawImportPath,
525
+ language: language,
526
+ });
527
+ continue;
528
+ }
529
+ // Extract call sites
530
+ if (captureMap['call']) {
531
+ const callNameNode = captureMap['call.name'];
532
+ if (callNameNode) {
533
+ const calledName = callNameNode.text;
534
+ if (!BUILT_INS.has(calledName)) {
535
+ const callNode = captureMap['call'];
536
+ const sourceId = findEnclosingFunctionId(callNode, file.path)
537
+ || generateId('File', file.path);
538
+ result.calls.push({ filePath: file.path, calledName, sourceId });
539
+ }
540
+ }
541
+ continue;
542
+ }
543
+ // Extract heritage (extends/implements)
544
+ if (captureMap['heritage.class']) {
545
+ if (captureMap['heritage.extends']) {
546
+ result.heritage.push({
547
+ filePath: file.path,
548
+ className: captureMap['heritage.class'].text,
549
+ parentName: captureMap['heritage.extends'].text,
550
+ kind: 'extends',
551
+ });
552
+ }
553
+ if (captureMap['heritage.implements']) {
554
+ result.heritage.push({
555
+ filePath: file.path,
556
+ className: captureMap['heritage.class'].text,
557
+ parentName: captureMap['heritage.implements'].text,
558
+ kind: 'implements',
559
+ });
560
+ }
561
+ if (captureMap['heritage.trait']) {
562
+ result.heritage.push({
563
+ filePath: file.path,
564
+ className: captureMap['heritage.class'].text,
565
+ parentName: captureMap['heritage.trait'].text,
566
+ kind: 'trait-impl',
567
+ });
568
+ }
569
+ if (captureMap['heritage.extends'] || captureMap['heritage.implements'] || captureMap['heritage.trait']) {
570
+ continue;
571
+ }
572
+ }
573
+ const nodeLabel = getLabelFromCaptures(captureMap);
574
+ if (!nodeLabel)
575
+ continue;
576
+ const nameNode = captureMap['name'];
577
+ const nodeName = nameNode.text;
578
+ const nodeId = generateId(nodeLabel, `${file.path}:${nodeName}`);
579
+ let description;
580
+ if (language === SupportedLanguages.PHP) {
581
+ if (nodeLabel === 'Property' && captureMap['definition.property']) {
582
+ description = extractPhpPropertyDescription(nodeName, captureMap['definition.property']) ?? undefined;
583
+ }
584
+ else if (nodeLabel === 'Method' && captureMap['definition.method']) {
585
+ description = extractEloquentRelationDescription(captureMap['definition.method']) ?? undefined;
586
+ }
587
+ }
588
+ result.nodes.push({
589
+ id: nodeId,
590
+ label: nodeLabel,
591
+ properties: {
592
+ name: nodeName,
593
+ filePath: file.path,
594
+ startLine: nameNode.startPosition.row + 1,
595
+ endLine: nameNode.endPosition.row + 1,
596
+ language: language,
597
+ isExported: isNodeExported(nameNode, nodeName, language),
598
+ ...(description !== undefined ? { description } : {}),
599
+ },
600
+ });
601
+ result.symbols.push({
602
+ filePath: file.path,
603
+ name: nodeName,
604
+ nodeId,
605
+ type: nodeLabel,
606
+ });
607
+ const fileId = generateId('File', file.path);
608
+ const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
609
+ result.relationships.push({
610
+ id: relId,
611
+ sourceId: fileId,
612
+ targetId: nodeId,
613
+ type: 'DEFINES',
614
+ confidence: 1.0,
615
+ reason: '',
616
+ });
617
+ }
618
+ }
619
+ };
620
+ // ============================================================================
621
+ // Worker message handler — supports sub-batch streaming
622
+ // ============================================================================
623
+ /** Accumulated result across sub-batches */
624
+ let accumulated = {
625
+ nodes: [], relationships: [], symbols: [],
626
+ imports: [], calls: [], heritage: [], fileCount: 0,
627
+ };
628
+ let cumulativeProcessed = 0;
629
+ const mergeResult = (target, src) => {
630
+ target.nodes.push(...src.nodes);
631
+ target.relationships.push(...src.relationships);
632
+ target.symbols.push(...src.symbols);
633
+ target.imports.push(...src.imports);
634
+ target.calls.push(...src.calls);
635
+ target.heritage.push(...src.heritage);
636
+ target.fileCount += src.fileCount;
637
+ };
638
+ parentPort.on('message', (msg) => {
639
+ try {
640
+ // Sub-batch mode: { type: 'sub-batch', files: [...] }
641
+ if (msg && msg.type === 'sub-batch') {
642
+ const result = processBatch(msg.files, (filesProcessed) => {
643
+ parentPort.postMessage({ type: 'progress', filesProcessed: cumulativeProcessed + filesProcessed });
644
+ });
645
+ cumulativeProcessed += result.fileCount;
646
+ mergeResult(accumulated, result);
647
+ // Signal ready for next sub-batch
648
+ parentPort.postMessage({ type: 'sub-batch-done' });
649
+ return;
650
+ }
651
+ // Flush: send accumulated results
652
+ if (msg && msg.type === 'flush') {
653
+ parentPort.postMessage({ type: 'result', data: accumulated });
654
+ // Reset for potential reuse
655
+ accumulated = { nodes: [], relationships: [], symbols: [], imports: [], calls: [], heritage: [], fileCount: 0 };
656
+ cumulativeProcessed = 0;
657
+ return;
658
+ }
659
+ // Legacy single-message mode (backward compat): array of files
660
+ if (Array.isArray(msg)) {
661
+ const result = processBatch(msg, (filesProcessed) => {
662
+ parentPort.postMessage({ type: 'progress', filesProcessed });
663
+ });
664
+ parentPort.postMessage({ type: 'result', data: result });
665
+ return;
666
+ }
667
+ }
668
+ catch (err) {
669
+ const message = err instanceof Error ? err.message : String(err);
670
+ parentPort.postMessage({ type: 'error', error: message });
671
+ }
672
+ });