gitnexus 1.4.0 → 1.4.1

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 (131) hide show
  1. package/README.md +194 -214
  2. package/dist/cli/ai-context.d.ts +1 -2
  3. package/dist/cli/ai-context.js +90 -117
  4. package/dist/cli/analyze.d.ts +0 -2
  5. package/dist/cli/analyze.js +2 -20
  6. package/dist/cli/index.js +25 -17
  7. package/dist/cli/setup.js +19 -17
  8. package/dist/core/augmentation/engine.js +20 -20
  9. package/dist/core/embeddings/embedding-pipeline.js +26 -26
  10. package/dist/core/graph/types.d.ts +2 -5
  11. package/dist/core/ingestion/ast-cache.js +2 -3
  12. package/dist/core/ingestion/call-processor.d.ts +5 -5
  13. package/dist/core/ingestion/call-processor.js +258 -173
  14. package/dist/core/ingestion/cluster-enricher.js +16 -16
  15. package/dist/core/ingestion/entry-point-scoring.d.ts +1 -2
  16. package/dist/core/ingestion/entry-point-scoring.js +22 -81
  17. package/dist/core/ingestion/framework-detection.d.ts +1 -5
  18. package/dist/core/ingestion/framework-detection.js +8 -39
  19. package/dist/core/ingestion/heritage-processor.d.ts +4 -13
  20. package/dist/core/ingestion/heritage-processor.js +28 -92
  21. package/dist/core/ingestion/import-processor.d.ts +19 -17
  22. package/dist/core/ingestion/import-processor.js +695 -170
  23. package/dist/core/ingestion/parsing-processor.d.ts +10 -1
  24. package/dist/core/ingestion/parsing-processor.js +177 -41
  25. package/dist/core/ingestion/pipeline.js +26 -49
  26. package/dist/core/ingestion/process-processor.js +1 -2
  27. package/dist/core/ingestion/symbol-table.d.ts +1 -12
  28. package/dist/core/ingestion/symbol-table.js +12 -19
  29. package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -11
  30. package/dist/core/ingestion/tree-sitter-queries.js +485 -590
  31. package/dist/core/ingestion/utils.d.ts +0 -67
  32. package/dist/core/ingestion/utils.js +9 -692
  33. package/dist/core/ingestion/workers/parse-worker.d.ts +3 -20
  34. package/dist/core/ingestion/workers/parse-worker.js +345 -84
  35. package/dist/core/ingestion/workers/worker-pool.js +0 -8
  36. package/dist/core/kuzu/csv-generator.js +3 -19
  37. package/dist/core/kuzu/kuzu-adapter.js +19 -14
  38. package/dist/core/kuzu/schema.d.ts +3 -3
  39. package/dist/core/kuzu/schema.js +288 -303
  40. package/dist/core/search/bm25-index.js +6 -7
  41. package/dist/core/search/hybrid-search.js +3 -3
  42. package/dist/core/wiki/diagrams.d.ts +27 -0
  43. package/dist/core/wiki/diagrams.js +163 -0
  44. package/dist/core/wiki/generator.d.ts +50 -2
  45. package/dist/core/wiki/generator.js +548 -49
  46. package/dist/core/wiki/graph-queries.d.ts +42 -0
  47. package/dist/core/wiki/graph-queries.js +276 -97
  48. package/dist/core/wiki/html-viewer.js +192 -192
  49. package/dist/core/wiki/llm-client.js +73 -11
  50. package/dist/core/wiki/prompts.d.ts +52 -8
  51. package/dist/core/wiki/prompts.js +200 -86
  52. package/dist/mcp/core/kuzu-adapter.d.ts +3 -1
  53. package/dist/mcp/core/kuzu-adapter.js +44 -13
  54. package/dist/mcp/local/local-backend.js +128 -128
  55. package/dist/mcp/resources.js +42 -42
  56. package/dist/mcp/server.js +19 -18
  57. package/dist/mcp/tools.js +104 -103
  58. package/hooks/claude/gitnexus-hook.cjs +155 -238
  59. package/hooks/claude/pre-tool-use.sh +79 -79
  60. package/hooks/claude/session-start.sh +42 -42
  61. package/package.json +96 -96
  62. package/scripts/patch-tree-sitter-swift.cjs +74 -74
  63. package/skills/gitnexus-cli.md +82 -82
  64. package/skills/gitnexus-debugging.md +89 -89
  65. package/skills/gitnexus-exploring.md +78 -78
  66. package/skills/gitnexus-guide.md +64 -64
  67. package/skills/gitnexus-impact-analysis.md +97 -97
  68. package/skills/gitnexus-pr-review.md +163 -163
  69. package/skills/gitnexus-refactoring.md +121 -121
  70. package/vendor/leiden/index.cjs +355 -355
  71. package/vendor/leiden/utils.cjs +392 -392
  72. package/dist/cli/lazy-action.d.ts +0 -6
  73. package/dist/cli/lazy-action.js +0 -18
  74. package/dist/cli/skill-gen.d.ts +0 -26
  75. package/dist/cli/skill-gen.js +0 -549
  76. package/dist/core/ingestion/constants.d.ts +0 -16
  77. package/dist/core/ingestion/constants.js +0 -16
  78. package/dist/core/ingestion/export-detection.d.ts +0 -18
  79. package/dist/core/ingestion/export-detection.js +0 -230
  80. package/dist/core/ingestion/language-config.d.ts +0 -46
  81. package/dist/core/ingestion/language-config.js +0 -167
  82. package/dist/core/ingestion/mro-processor.d.ts +0 -45
  83. package/dist/core/ingestion/mro-processor.js +0 -369
  84. package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
  85. package/dist/core/ingestion/named-binding-extraction.js +0 -363
  86. package/dist/core/ingestion/resolvers/csharp.d.ts +0 -22
  87. package/dist/core/ingestion/resolvers/csharp.js +0 -109
  88. package/dist/core/ingestion/resolvers/go.d.ts +0 -19
  89. package/dist/core/ingestion/resolvers/go.js +0 -42
  90. package/dist/core/ingestion/resolvers/index.d.ts +0 -16
  91. package/dist/core/ingestion/resolvers/index.js +0 -11
  92. package/dist/core/ingestion/resolvers/jvm.d.ts +0 -23
  93. package/dist/core/ingestion/resolvers/jvm.js +0 -87
  94. package/dist/core/ingestion/resolvers/php.d.ts +0 -15
  95. package/dist/core/ingestion/resolvers/php.js +0 -35
  96. package/dist/core/ingestion/resolvers/rust.d.ts +0 -15
  97. package/dist/core/ingestion/resolvers/rust.js +0 -73
  98. package/dist/core/ingestion/resolvers/standard.d.ts +0 -28
  99. package/dist/core/ingestion/resolvers/standard.js +0 -145
  100. package/dist/core/ingestion/resolvers/utils.d.ts +0 -33
  101. package/dist/core/ingestion/resolvers/utils.js +0 -120
  102. package/dist/core/ingestion/symbol-resolver.d.ts +0 -32
  103. package/dist/core/ingestion/symbol-resolver.js +0 -83
  104. package/dist/core/ingestion/type-env.d.ts +0 -27
  105. package/dist/core/ingestion/type-env.js +0 -86
  106. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +0 -2
  107. package/dist/core/ingestion/type-extractors/c-cpp.js +0 -60
  108. package/dist/core/ingestion/type-extractors/csharp.d.ts +0 -2
  109. package/dist/core/ingestion/type-extractors/csharp.js +0 -89
  110. package/dist/core/ingestion/type-extractors/go.d.ts +0 -2
  111. package/dist/core/ingestion/type-extractors/go.js +0 -105
  112. package/dist/core/ingestion/type-extractors/index.d.ts +0 -21
  113. package/dist/core/ingestion/type-extractors/index.js +0 -29
  114. package/dist/core/ingestion/type-extractors/jvm.d.ts +0 -3
  115. package/dist/core/ingestion/type-extractors/jvm.js +0 -121
  116. package/dist/core/ingestion/type-extractors/php.d.ts +0 -2
  117. package/dist/core/ingestion/type-extractors/php.js +0 -31
  118. package/dist/core/ingestion/type-extractors/python.d.ts +0 -2
  119. package/dist/core/ingestion/type-extractors/python.js +0 -41
  120. package/dist/core/ingestion/type-extractors/rust.d.ts +0 -2
  121. package/dist/core/ingestion/type-extractors/rust.js +0 -39
  122. package/dist/core/ingestion/type-extractors/shared.d.ts +0 -17
  123. package/dist/core/ingestion/type-extractors/shared.js +0 -97
  124. package/dist/core/ingestion/type-extractors/swift.d.ts +0 -2
  125. package/dist/core/ingestion/type-extractors/swift.js +0 -43
  126. package/dist/core/ingestion/type-extractors/types.d.ts +0 -14
  127. package/dist/core/ingestion/type-extractors/types.js +0 -1
  128. package/dist/core/ingestion/type-extractors/typescript.d.ts +0 -2
  129. package/dist/core/ingestion/type-extractors/typescript.js +0 -46
  130. package/dist/mcp/compatible-stdio-transport.d.ts +0 -25
  131. package/dist/mcp/compatible-stdio-transport.js +0 -200
@@ -1,397 +1,4 @@
1
1
  import { SupportedLanguages } from '../../config/supported-languages.js';
2
- import { generateId } from '../../lib/utils.js';
3
- /**
4
- * Ordered list of definition capture keys for tree-sitter query matches.
5
- * Used to extract the definition node from a capture map.
6
- */
7
- export const DEFINITION_CAPTURE_KEYS = [
8
- 'definition.function',
9
- 'definition.class',
10
- 'definition.interface',
11
- 'definition.method',
12
- 'definition.struct',
13
- 'definition.enum',
14
- 'definition.namespace',
15
- 'definition.module',
16
- 'definition.trait',
17
- 'definition.impl',
18
- 'definition.type',
19
- 'definition.const',
20
- 'definition.static',
21
- 'definition.typedef',
22
- 'definition.macro',
23
- 'definition.union',
24
- 'definition.property',
25
- 'definition.record',
26
- 'definition.delegate',
27
- 'definition.annotation',
28
- 'definition.constructor',
29
- 'definition.template',
30
- ];
31
- /** Extract the definition node from a tree-sitter query capture map. */
32
- export const getDefinitionNodeFromCaptures = (captureMap) => {
33
- for (const key of DEFINITION_CAPTURE_KEYS) {
34
- if (captureMap[key])
35
- return captureMap[key];
36
- }
37
- return null;
38
- };
39
- /**
40
- * Node types that represent function/method definitions across languages.
41
- * Used to find the enclosing function for a call site.
42
- */
43
- export const FUNCTION_NODE_TYPES = new Set([
44
- // TypeScript/JavaScript
45
- 'function_declaration',
46
- 'arrow_function',
47
- 'function_expression',
48
- 'method_definition',
49
- 'generator_function_declaration',
50
- // Python
51
- 'function_definition',
52
- // Common async variants
53
- 'async_function_declaration',
54
- 'async_arrow_function',
55
- // Java
56
- 'method_declaration',
57
- 'constructor_declaration',
58
- // C/C++
59
- // 'function_definition' already included above
60
- // Go
61
- // 'method_declaration' already included from Java
62
- // C#
63
- 'local_function_statement',
64
- // Rust
65
- 'function_item',
66
- 'impl_item', // Methods inside impl blocks
67
- // PHP
68
- 'anonymous_function',
69
- // Kotlin
70
- 'lambda_literal',
71
- // Swift
72
- 'init_declaration',
73
- 'deinit_declaration',
74
- ]);
75
- /**
76
- * Node types for standard function declarations that need C/C++ declarator handling.
77
- * Used by extractFunctionName to determine how to extract the function name.
78
- */
79
- export const FUNCTION_DECLARATION_TYPES = new Set([
80
- 'function_declaration',
81
- 'function_definition',
82
- 'async_function_declaration',
83
- 'generator_function_declaration',
84
- 'function_item',
85
- ]);
86
- /**
87
- * Built-in function/method names that should not be tracked as call targets.
88
- * Covers JS/TS, Python, Kotlin, C/C++, PHP, Swift standard library functions.
89
- */
90
- export const BUILT_IN_NAMES = new Set([
91
- // JavaScript/TypeScript
92
- 'console', 'log', 'warn', 'error', 'info', 'debug',
93
- 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
94
- 'parseInt', 'parseFloat', 'isNaN', 'isFinite',
95
- 'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
96
- 'JSON', 'parse', 'stringify',
97
- 'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
98
- 'Map', 'Set', 'WeakMap', 'WeakSet',
99
- 'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
100
- 'Math', 'Date', 'RegExp', 'Error',
101
- 'require', 'import', 'export', 'fetch', 'Response', 'Request',
102
- 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
103
- 'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
104
- 'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
105
- 'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
106
- 'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
107
- 'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
108
- 'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
109
- 'hasOwnProperty', 'toString', 'valueOf',
110
- // Python
111
- 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
112
- 'append', 'extend', 'update',
113
- // NOTE: 'open', 'read', 'write', 'close' removed — these are real C POSIX syscalls
114
- 'super', 'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
115
- 'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
116
- // Kotlin stdlib
117
- 'println', 'print', 'readLine', 'require', 'requireNotNull', 'check', 'assert', 'lazy', 'error',
118
- 'listOf', 'mapOf', 'setOf', 'mutableListOf', 'mutableMapOf', 'mutableSetOf',
119
- 'arrayOf', 'sequenceOf', 'also', 'apply', 'run', 'with', 'takeIf', 'takeUnless',
120
- 'TODO', 'buildString', 'buildList', 'buildMap', 'buildSet',
121
- 'repeat', 'synchronized',
122
- // Kotlin coroutine builders & scope functions
123
- 'launch', 'async', 'runBlocking', 'withContext', 'coroutineScope',
124
- 'supervisorScope', 'delay',
125
- // Kotlin Flow operators
126
- 'flow', 'flowOf', 'collect', 'emit', 'onEach', 'catch',
127
- 'buffer', 'conflate', 'distinctUntilChanged',
128
- 'flatMapLatest', 'flatMapMerge', 'combine',
129
- 'stateIn', 'shareIn', 'launchIn',
130
- // Kotlin infix stdlib functions
131
- 'to', 'until', 'downTo', 'step',
132
- // C/C++ standard library
133
- 'printf', 'fprintf', 'sprintf', 'snprintf', 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
134
- 'scanf', 'fscanf', 'sscanf',
135
- 'malloc', 'calloc', 'realloc', 'free', 'memcpy', 'memmove', 'memset', 'memcmp',
136
- 'strlen', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strstr', 'strchr', 'strrchr',
137
- 'atoi', 'atol', 'atof', 'strtol', 'strtoul', 'strtoll', 'strtoull', 'strtod',
138
- 'sizeof', 'offsetof', 'typeof',
139
- 'assert', 'abort', 'exit', '_exit',
140
- 'fopen', 'fclose', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', 'fflush', 'fgets', 'fputs',
141
- // Linux kernel common macros/helpers (not real call targets)
142
- 'likely', 'unlikely', 'BUG', 'BUG_ON', 'WARN', 'WARN_ON', 'WARN_ONCE',
143
- 'IS_ERR', 'PTR_ERR', 'ERR_PTR', 'IS_ERR_OR_NULL',
144
- 'ARRAY_SIZE', 'container_of', 'list_for_each_entry', 'list_for_each_entry_safe',
145
- 'min', 'max', 'clamp', 'abs', 'swap',
146
- 'pr_info', 'pr_warn', 'pr_err', 'pr_debug', 'pr_notice', 'pr_crit', 'pr_emerg',
147
- 'printk', 'dev_info', 'dev_warn', 'dev_err', 'dev_dbg',
148
- 'GFP_KERNEL', 'GFP_ATOMIC',
149
- 'spin_lock', 'spin_unlock', 'spin_lock_irqsave', 'spin_unlock_irqrestore',
150
- 'mutex_lock', 'mutex_unlock', 'mutex_init',
151
- 'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
152
- 'get', 'put',
153
- // C# / .NET built-ins
154
- 'Console', 'WriteLine', 'ReadLine', 'Write',
155
- 'Task', 'Run', 'Wait', 'WhenAll', 'WhenAny', 'FromResult', 'Delay', 'ContinueWith',
156
- 'ConfigureAwait', 'GetAwaiter', 'GetResult',
157
- 'ToString', 'GetType', 'Equals', 'GetHashCode', 'ReferenceEquals',
158
- 'Add', 'Remove', 'Contains', 'Clear', 'Count', 'Any', 'All',
159
- 'Where', 'Select', 'SelectMany', 'OrderBy', 'OrderByDescending', 'GroupBy',
160
- 'First', 'FirstOrDefault', 'Single', 'SingleOrDefault', 'Last', 'LastOrDefault',
161
- 'ToList', 'ToArray', 'ToDictionary', 'AsEnumerable', 'AsQueryable',
162
- 'Aggregate', 'Sum', 'Average', 'Min', 'Max', 'Distinct', 'Skip', 'Take',
163
- 'String', 'Format', 'IsNullOrEmpty', 'IsNullOrWhiteSpace', 'Concat', 'Join',
164
- 'Trim', 'TrimStart', 'TrimEnd', 'Split', 'Replace', 'StartsWith', 'EndsWith',
165
- 'Convert', 'ToInt32', 'ToDouble', 'ToBoolean', 'ToByte',
166
- 'Math', 'Abs', 'Ceiling', 'Floor', 'Round', 'Pow', 'Sqrt',
167
- 'Dispose', 'Close',
168
- 'TryParse', 'Parse',
169
- 'AddRange', 'RemoveAt', 'RemoveAll', 'FindAll', 'Exists', 'TrueForAll',
170
- 'ContainsKey', 'TryGetValue', 'AddOrUpdate',
171
- 'Throw', 'ThrowIfNull',
172
- // PHP built-ins
173
- 'echo', 'isset', 'empty', 'unset', 'list', 'array', 'compact', 'extract',
174
- 'count', 'strlen', 'strpos', 'strrpos', 'substr', 'strtolower', 'strtoupper', 'trim',
175
- 'ltrim', 'rtrim', 'str_replace', 'str_contains', 'str_starts_with', 'str_ends_with',
176
- 'sprintf', 'vsprintf', 'printf', 'number_format',
177
- 'array_map', 'array_filter', 'array_reduce', 'array_push', 'array_pop', 'array_shift',
178
- 'array_unshift', 'array_slice', 'array_splice', 'array_merge', 'array_keys', 'array_values',
179
- 'array_key_exists', 'in_array', 'array_search', 'array_unique', 'usort', 'rsort',
180
- 'json_encode', 'json_decode', 'serialize', 'unserialize',
181
- 'intval', 'floatval', 'strval', 'boolval', 'is_null', 'is_string', 'is_int', 'is_array',
182
- 'is_object', 'is_numeric', 'is_bool', 'is_float',
183
- 'var_dump', 'print_r', 'var_export',
184
- 'date', 'time', 'strtotime', 'mktime', 'microtime',
185
- 'file_exists', 'file_get_contents', 'file_put_contents', 'is_file', 'is_dir',
186
- 'preg_match', 'preg_match_all', 'preg_replace', 'preg_split',
187
- 'header', 'session_start', 'session_destroy', 'ob_start', 'ob_end_clean', 'ob_get_clean',
188
- 'dd', 'dump',
189
- // Swift/iOS built-ins and standard library
190
- 'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
191
- 'assert', 'assertionFailure', 'NSLog',
192
- 'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
193
- 'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
194
- 'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
195
- 'type', 'MemoryLayout',
196
- // Swift collection/string methods (common noise)
197
- 'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
198
- 'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
199
- 'sorted', 'reversed', 'enumerated', 'joined', 'split',
200
- 'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
201
- 'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
202
- // UIKit/Foundation common methods (noise in call graph)
203
- 'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
204
- 'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
205
- 'addTarget', 'removeTarget', 'addGestureRecognizer',
206
- 'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
207
- 'NSLocalizedString', 'Bundle',
208
- 'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
209
- 'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
210
- 'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
211
- 'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
212
- 'performSegue', 'prepare',
213
- // GCD / async
214
- 'DispatchQueue', 'async', 'sync', 'asyncAfter',
215
- 'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
216
- // Combine
217
- 'sink', 'store', 'assign', 'receive', 'subscribe',
218
- // Notification / KVO
219
- 'addObserver', 'removeObserver', 'post', 'NotificationCenter',
220
- // Rust standard library (common noise in call graphs)
221
- 'unwrap', 'expect', 'unwrap_or', 'unwrap_or_else', 'unwrap_or_default',
222
- 'ok', 'err', 'is_ok', 'is_err', 'map', 'map_err', 'and_then', 'or_else',
223
- 'clone', 'to_string', 'to_owned', 'into', 'from', 'as_ref', 'as_mut',
224
- 'iter', 'into_iter', 'collect', 'map', 'filter', 'fold', 'for_each',
225
- 'len', 'is_empty', 'push', 'pop', 'insert', 'remove', 'contains',
226
- 'format', 'write', 'writeln', 'panic', 'unreachable', 'todo', 'unimplemented',
227
- 'vec', 'println', 'eprintln', 'dbg',
228
- 'lock', 'read', 'write', 'try_lock',
229
- 'spawn', 'join', 'sleep',
230
- 'Some', 'None', 'Ok', 'Err',
231
- ]);
232
- /** Check if a name is a built-in function or common noise that should be filtered out */
233
- export const isBuiltInOrNoise = (name) => BUILT_IN_NAMES.has(name);
234
- /** AST node types that represent a class-like container (for HAS_METHOD edge extraction) */
235
- export const CLASS_CONTAINER_TYPES = new Set([
236
- 'class_declaration', 'abstract_class_declaration',
237
- 'interface_declaration', 'struct_declaration', 'record_declaration',
238
- 'class_specifier', 'struct_specifier',
239
- 'impl_item', 'trait_item',
240
- 'class_definition',
241
- 'trait_declaration',
242
- 'protocol_declaration',
243
- ]);
244
- export const CONTAINER_TYPE_TO_LABEL = {
245
- class_declaration: 'Class',
246
- abstract_class_declaration: 'Class',
247
- interface_declaration: 'Interface',
248
- struct_declaration: 'Struct',
249
- struct_specifier: 'Struct',
250
- class_specifier: 'Class',
251
- class_definition: 'Class',
252
- impl_item: 'Impl',
253
- trait_item: 'Trait',
254
- trait_declaration: 'Trait',
255
- record_declaration: 'Record',
256
- protocol_declaration: 'Interface',
257
- };
258
- /** Walk up AST to find enclosing class/struct/interface/impl, return its generateId or null.
259
- * For Go method_declaration nodes, extracts receiver type (e.g. `func (u *User) Save()` → User struct). */
260
- export const findEnclosingClassId = (node, filePath) => {
261
- let current = node.parent;
262
- while (current) {
263
- // Go: method_declaration has a receiver parameter with the struct type
264
- if (current.type === 'method_declaration') {
265
- const receiver = current.childForFieldName?.('receiver');
266
- if (receiver) {
267
- // receiver is a parameter_list: (u *User) or (u User)
268
- const paramDecl = receiver.namedChildren?.find?.((c) => c.type === 'parameter_declaration');
269
- if (paramDecl) {
270
- const typeNode = paramDecl.childForFieldName?.('type');
271
- if (typeNode) {
272
- // Unwrap pointer_type (*User → User)
273
- const inner = typeNode.type === 'pointer_type' ? typeNode.firstNamedChild : typeNode;
274
- if (inner && (inner.type === 'type_identifier' || inner.type === 'identifier')) {
275
- return generateId('Struct', `${filePath}:${inner.text}`);
276
- }
277
- }
278
- }
279
- }
280
- }
281
- if (CLASS_CONTAINER_TYPES.has(current.type)) {
282
- // Rust impl_item: for `impl Trait for Struct {}`, pick the type after `for`
283
- if (current.type === 'impl_item') {
284
- const children = current.children ?? [];
285
- const forIdx = children.findIndex((c) => c.text === 'for');
286
- if (forIdx !== -1) {
287
- const nameNode = children.slice(forIdx + 1).find((c) => c.type === 'type_identifier' || c.type === 'identifier');
288
- if (nameNode) {
289
- return generateId('Impl', `${filePath}:${nameNode.text}`);
290
- }
291
- }
292
- // Fall through: plain `impl Struct {}` — use first type_identifier below
293
- }
294
- const nameNode = current.childForFieldName?.('name')
295
- ?? current.children?.find((c) => c.type === 'type_identifier' || c.type === 'identifier' || c.type === 'name');
296
- if (nameNode) {
297
- const label = CONTAINER_TYPE_TO_LABEL[current.type] || 'Class';
298
- return generateId(label, `${filePath}:${nameNode.text}`);
299
- }
300
- }
301
- current = current.parent;
302
- }
303
- return null;
304
- };
305
- /**
306
- * Extract function name and label from a function_definition or similar AST node.
307
- * Handles C/C++ qualified_identifier (ClassName::MethodName) and other language patterns.
308
- */
309
- export const extractFunctionName = (node) => {
310
- let funcName = null;
311
- let label = 'Function';
312
- // Swift init/deinit
313
- if (node.type === 'init_declaration' || node.type === 'deinit_declaration') {
314
- return {
315
- funcName: node.type === 'init_declaration' ? 'init' : 'deinit',
316
- label: 'Constructor',
317
- };
318
- }
319
- if (FUNCTION_DECLARATION_TYPES.has(node.type)) {
320
- // C/C++: function_definition -> [pointer_declarator ->] function_declarator -> qualified_identifier/identifier
321
- // Unwrap pointer_declarator / reference_declarator wrappers to reach function_declarator
322
- let declarator = node.childForFieldName?.('declarator') ||
323
- node.children?.find((c) => c.type === 'function_declarator');
324
- while (declarator && (declarator.type === 'pointer_declarator' || declarator.type === 'reference_declarator')) {
325
- declarator = declarator.childForFieldName?.('declarator') ||
326
- declarator.children?.find((c) => c.type === 'function_declarator' || c.type === 'pointer_declarator' || c.type === 'reference_declarator');
327
- }
328
- if (declarator) {
329
- const innerDeclarator = declarator.childForFieldName?.('declarator') ||
330
- declarator.children?.find((c) => c.type === 'qualified_identifier' || c.type === 'identifier' || c.type === 'parenthesized_declarator');
331
- if (innerDeclarator?.type === 'qualified_identifier') {
332
- const nameNode = innerDeclarator.childForFieldName?.('name') ||
333
- innerDeclarator.children?.find((c) => c.type === 'identifier');
334
- if (nameNode?.text) {
335
- funcName = nameNode.text;
336
- label = 'Method';
337
- }
338
- }
339
- else if (innerDeclarator?.type === 'identifier') {
340
- funcName = innerDeclarator.text;
341
- }
342
- else if (innerDeclarator?.type === 'parenthesized_declarator') {
343
- const nestedId = innerDeclarator.children?.find((c) => c.type === 'qualified_identifier' || c.type === 'identifier');
344
- if (nestedId?.type === 'qualified_identifier') {
345
- const nameNode = nestedId.childForFieldName?.('name') ||
346
- nestedId.children?.find((c) => c.type === 'identifier');
347
- if (nameNode?.text) {
348
- funcName = nameNode.text;
349
- label = 'Method';
350
- }
351
- }
352
- else if (nestedId?.type === 'identifier') {
353
- funcName = nestedId.text;
354
- }
355
- }
356
- }
357
- // Fallback for other languages (Kotlin uses simple_identifier, Swift uses simple_identifier)
358
- if (!funcName) {
359
- const nameNode = node.childForFieldName?.('name') ||
360
- node.children?.find((c) => c.type === 'identifier' || c.type === 'property_identifier' || c.type === 'simple_identifier');
361
- funcName = nameNode?.text;
362
- }
363
- }
364
- else if (node.type === 'impl_item') {
365
- const funcItem = node.children?.find((c) => c.type === 'function_item');
366
- if (funcItem) {
367
- const nameNode = funcItem.childForFieldName?.('name') ||
368
- funcItem.children?.find((c) => c.type === 'identifier');
369
- funcName = nameNode?.text;
370
- label = 'Method';
371
- }
372
- }
373
- else if (node.type === 'method_definition') {
374
- const nameNode = node.childForFieldName?.('name') ||
375
- node.children?.find((c) => c.type === 'property_identifier');
376
- funcName = nameNode?.text;
377
- label = 'Method';
378
- }
379
- else if (node.type === 'method_declaration' || node.type === 'constructor_declaration') {
380
- const nameNode = node.childForFieldName?.('name') ||
381
- node.children?.find((c) => c.type === 'identifier');
382
- funcName = nameNode?.text;
383
- label = 'Method';
384
- }
385
- else if (node.type === 'arrow_function' || node.type === 'function_expression') {
386
- const parent = node.parent;
387
- if (parent?.type === 'variable_declarator') {
388
- const nameNode = parent.childForFieldName?.('name') ||
389
- parent.children?.find((c) => c.type === 'identifier');
390
- funcName = nameNode?.text;
391
- }
392
- }
393
- return { funcName, label };
394
- };
395
2
  /**
396
3
  * Yield control to the event loop so spinners/progress can render.
397
4
  * Call periodically in hot loops to prevent UI freezes.
@@ -423,25 +30,27 @@ export const getLanguageFromFilename = (filename) => {
423
30
  return SupportedLanguages.TypeScript;
424
31
  if (filename.endsWith('.ts'))
425
32
  return SupportedLanguages.TypeScript;
426
- // JavaScript (including JSX)
33
+ // JavaScript (including JSX, CJS, MJS)
427
34
  if (filename.endsWith('.jsx'))
428
35
  return SupportedLanguages.JavaScript;
429
36
  if (filename.endsWith('.js'))
430
37
  return SupportedLanguages.JavaScript;
38
+ if (filename.endsWith('.cjs'))
39
+ return SupportedLanguages.JavaScript;
40
+ if (filename.endsWith('.mjs'))
41
+ return SupportedLanguages.JavaScript;
431
42
  // Python
432
43
  if (filename.endsWith('.py'))
433
44
  return SupportedLanguages.Python;
434
45
  // Java
435
46
  if (filename.endsWith('.java'))
436
47
  return SupportedLanguages.Java;
437
- // C source files
438
- if (filename.endsWith('.c'))
48
+ // C (source and headers)
49
+ if (filename.endsWith('.c') || filename.endsWith('.h'))
439
50
  return SupportedLanguages.C;
440
- // C++ (all common extensions, including .h)
441
- // .h is parsed as C++ because tree-sitter-cpp is a strict superset of C, so pure-C
442
- // headers parse correctly, and C++ headers (classes, templates) are handled properly.
51
+ // C++ (all common extensions)
443
52
  if (filename.endsWith('.cpp') || filename.endsWith('.cc') || filename.endsWith('.cxx') ||
444
- filename.endsWith('.h') || filename.endsWith('.hpp') || filename.endsWith('.hxx') || filename.endsWith('.hh'))
53
+ filename.endsWith('.hpp') || filename.endsWith('.hxx') || filename.endsWith('.hh'))
445
54
  return SupportedLanguages.CPlusPlus;
446
55
  // C#
447
56
  if (filename.endsWith('.cs'))
@@ -465,295 +74,3 @@ export const getLanguageFromFilename = (filename) => {
465
74
  return SupportedLanguages.Swift;
466
75
  return null;
467
76
  };
468
- const CALL_ARGUMENT_LIST_TYPES = new Set([
469
- 'arguments',
470
- 'argument_list',
471
- 'value_arguments',
472
- ]);
473
- /**
474
- * Extract parameter count and return type text from an AST method/function node.
475
- * Works across languages by looking for common AST patterns.
476
- */
477
- export const extractMethodSignature = (node) => {
478
- let parameterCount = 0;
479
- let returnType;
480
- let isVariadic = false;
481
- if (!node)
482
- return { parameterCount, returnType };
483
- const paramListTypes = new Set([
484
- 'formal_parameters', 'parameters', 'parameter_list',
485
- 'function_parameters', 'method_parameters', 'function_value_parameters',
486
- ]);
487
- // Node types that indicate variadic/rest parameters
488
- const VARIADIC_PARAM_TYPES = new Set([
489
- 'variadic_parameter_declaration', // Go: ...string
490
- 'variadic_parameter', // Rust: extern "C" fn(...)
491
- 'spread_parameter', // Java: Object... args
492
- 'list_splat_pattern', // Python: *args
493
- 'dictionary_splat_pattern', // Python: **kwargs
494
- ]);
495
- const findParameterList = (current) => {
496
- for (const child of current.children) {
497
- if (paramListTypes.has(child.type))
498
- return child;
499
- }
500
- for (const child of current.children) {
501
- const nested = findParameterList(child);
502
- if (nested)
503
- return nested;
504
- }
505
- return null;
506
- };
507
- const parameterList = (paramListTypes.has(node.type) ? node // node itself IS the parameter list (e.g. C# primary constructors)
508
- : node.childForFieldName?.('parameters')
509
- ?? findParameterList(node));
510
- if (parameterList && paramListTypes.has(parameterList.type)) {
511
- for (const param of parameterList.namedChildren) {
512
- if (param.type === 'comment')
513
- continue;
514
- if (param.text === 'self' || param.text === '&self' || param.text === '&mut self' ||
515
- param.type === 'self_parameter') {
516
- continue;
517
- }
518
- // Check for variadic parameter types
519
- if (VARIADIC_PARAM_TYPES.has(param.type)) {
520
- isVariadic = true;
521
- continue;
522
- }
523
- // TypeScript/JavaScript: rest parameter — required_parameter containing rest_pattern
524
- if (param.type === 'required_parameter' || param.type === 'optional_parameter') {
525
- for (const child of param.children) {
526
- if (child.type === 'rest_pattern') {
527
- isVariadic = true;
528
- break;
529
- }
530
- }
531
- if (isVariadic)
532
- continue;
533
- }
534
- // Kotlin: vararg modifier on a regular parameter
535
- if (param.type === 'parameter' || param.type === 'formal_parameter') {
536
- const prev = param.previousSibling;
537
- if (prev?.type === 'parameter_modifiers' && prev.text.includes('vararg')) {
538
- isVariadic = true;
539
- }
540
- }
541
- parameterCount++;
542
- }
543
- // C/C++: bare `...` token in parameter list (not a named child — check all children)
544
- if (!isVariadic) {
545
- for (const child of parameterList.children) {
546
- if (!child.isNamed && child.text === '...') {
547
- isVariadic = true;
548
- break;
549
- }
550
- }
551
- }
552
- }
553
- // Return type extraction — language-specific field names
554
- // Go: 'result' field is either a type_identifier or parameter_list (multi-return)
555
- const goResult = node.childForFieldName?.('result');
556
- if (goResult) {
557
- returnType = goResult.type === 'parameter_list'
558
- ? goResult.text // multi-return: "(string, error)"
559
- : goResult.text; // single return: "int"
560
- }
561
- // Rust: 'return_type' field — the value IS the type node (e.g. primitive_type, type_identifier).
562
- // Skip if the node is a type_annotation (TS/Python), which is handled by the generic loop below.
563
- if (!returnType) {
564
- const rustReturn = node.childForFieldName?.('return_type');
565
- if (rustReturn && rustReturn.type !== 'type_annotation') {
566
- returnType = rustReturn.text;
567
- }
568
- }
569
- // C/C++: 'type' field on function_definition
570
- if (!returnType) {
571
- const cppType = node.childForFieldName?.('type');
572
- if (cppType && cppType.text !== 'void') {
573
- returnType = cppType.text;
574
- }
575
- }
576
- // TS/Rust/Python/C#/Kotlin: type_annotation or return_type child
577
- if (!returnType) {
578
- for (const child of node.children) {
579
- if (child.type === 'type_annotation' || child.type === 'return_type') {
580
- const typeNode = child.children.find((c) => c.isNamed);
581
- if (typeNode)
582
- returnType = typeNode.text;
583
- }
584
- }
585
- }
586
- if (isVariadic)
587
- parameterCount = undefined;
588
- return { parameterCount, returnType };
589
- };
590
- /**
591
- * Count direct arguments for a call expression across common tree-sitter grammars.
592
- * Returns undefined when the argument container cannot be located cheaply.
593
- */
594
- export const countCallArguments = (callNode) => {
595
- if (!callNode)
596
- return undefined;
597
- // Direct field or direct child (most languages)
598
- let argsNode = callNode.childForFieldName('arguments')
599
- ?? callNode.children.find((child) => CALL_ARGUMENT_LIST_TYPES.has(child.type));
600
- // Kotlin/Swift: call_expression → call_suffix → value_arguments
601
- // Search one level deeper for languages that wrap arguments in a suffix node
602
- if (!argsNode) {
603
- for (const child of callNode.children) {
604
- if (!child.isNamed)
605
- continue;
606
- const nested = child.children.find((gc) => CALL_ARGUMENT_LIST_TYPES.has(gc.type));
607
- if (nested) {
608
- argsNode = nested;
609
- break;
610
- }
611
- }
612
- }
613
- if (!argsNode)
614
- return undefined;
615
- let count = 0;
616
- for (const child of argsNode.children) {
617
- if (!child.isNamed)
618
- continue;
619
- if (child.type === 'comment')
620
- continue;
621
- count++;
622
- }
623
- return count;
624
- };
625
- // ── Call-form discrimination (Phase 1, Step D) ─────────────────────────
626
- /**
627
- * AST node types that indicate a member-access wrapper around the callee name.
628
- * When nameNode.parent.type is one of these, the call is a member call.
629
- */
630
- const MEMBER_ACCESS_NODE_TYPES = new Set([
631
- 'member_expression', // TS/JS: obj.method()
632
- 'attribute', // Python: obj.method()
633
- 'member_access_expression', // C#: obj.Method()
634
- 'field_expression', // Rust/C++: obj.method() / ptr->method()
635
- 'selector_expression', // Go: obj.Method()
636
- 'navigation_suffix', // Kotlin/Swift: obj.method() — nameNode sits inside navigation_suffix
637
- ]);
638
- /**
639
- * Call node types that are inherently constructor invocations.
640
- * Only includes patterns that the tree-sitter queries already capture as @call.
641
- */
642
- const CONSTRUCTOR_CALL_NODE_TYPES = new Set([
643
- 'constructor_invocation', // Kotlin: Foo()
644
- 'new_expression', // TS/JS/C++: new Foo()
645
- 'object_creation_expression', // Java/C#/PHP: new Foo()
646
- 'implicit_object_creation_expression', // C# 9: User u = new(...)
647
- 'composite_literal', // Go: User{...}
648
- 'struct_expression', // Rust: User { ... }
649
- ]);
650
- /**
651
- * AST node types for scoped/qualified calls (e.g., Foo::new() in Rust, Foo::bar() in C++).
652
- */
653
- const SCOPED_CALL_NODE_TYPES = new Set([
654
- 'scoped_identifier', // Rust: Foo::new()
655
- 'qualified_identifier', // C++: ns::func()
656
- ]);
657
- /**
658
- * Infer whether a captured call site is a free call, member call, or constructor.
659
- * Returns undefined if the form cannot be determined.
660
- *
661
- * Works by inspecting the AST structure between callNode (@call) and nameNode (@call.name).
662
- * No tree-sitter query changes needed — the distinction is in the node types.
663
- */
664
- export const inferCallForm = (callNode, nameNode) => {
665
- // 1. Constructor: callNode itself is a constructor invocation (Kotlin)
666
- if (CONSTRUCTOR_CALL_NODE_TYPES.has(callNode.type)) {
667
- return 'constructor';
668
- }
669
- // 2. Member call: nameNode's parent is a member-access wrapper
670
- const nameParent = nameNode.parent;
671
- if (nameParent && MEMBER_ACCESS_NODE_TYPES.has(nameParent.type)) {
672
- return 'member';
673
- }
674
- // 3. PHP: the callNode itself distinguishes member vs free calls
675
- if (callNode.type === 'member_call_expression' || callNode.type === 'nullsafe_member_call_expression') {
676
- return 'member';
677
- }
678
- if (callNode.type === 'scoped_call_expression') {
679
- return 'member'; // static call Foo::bar()
680
- }
681
- // 4. Java method_invocation: member if it has an 'object' field
682
- if (callNode.type === 'method_invocation' && callNode.childForFieldName('object')) {
683
- return 'member';
684
- }
685
- // 5. Scoped calls (Rust Foo::new(), C++ ns::func()): treat as free
686
- // The receiver is a type, not an instance — handled differently in Phase 3
687
- if (nameParent && SCOPED_CALL_NODE_TYPES.has(nameParent.type)) {
688
- return 'free';
689
- }
690
- // 6. Default: if nameNode is a direct child of callNode, it's a free call
691
- if (nameNode.parent === callNode || nameParent?.parent === callNode) {
692
- return 'free';
693
- }
694
- return undefined;
695
- };
696
- /**
697
- * Extract the receiver identifier for member calls.
698
- * Only captures simple identifiers — returns undefined for complex expressions
699
- * like getUser().save() or arr[0].method().
700
- */
701
- const SIMPLE_RECEIVER_TYPES = new Set([
702
- 'identifier',
703
- 'simple_identifier',
704
- 'variable_name', // PHP $variable (tree-sitter-php)
705
- 'name', // PHP name node
706
- 'this', // TS/JS/Java/C# this.method()
707
- 'self', // Rust/Python self.method()
708
- ]);
709
- export const extractReceiverName = (nameNode) => {
710
- const parent = nameNode.parent;
711
- if (!parent)
712
- return undefined;
713
- // PHP: member_call_expression / nullsafe_member_call_expression — receiver is on the callNode
714
- // Java: method_invocation — receiver is the 'object' field on callNode
715
- // For these, parent of nameNode is the call itself, so check the call's object field
716
- const callNode = parent.parent ?? parent;
717
- let receiver = null;
718
- // Try standard field names used across grammars
719
- receiver = parent.childForFieldName('object') // TS/JS member_expression, Python attribute, PHP, Java
720
- ?? parent.childForFieldName('value') // Rust field_expression
721
- ?? parent.childForFieldName('operand') // Go selector_expression
722
- ?? parent.childForFieldName('expression') // C# member_access_expression
723
- ?? parent.childForFieldName('argument'); // C++ field_expression
724
- // Java method_invocation: 'object' field is on the callNode, not on nameNode's parent
725
- if (!receiver && callNode.type === 'method_invocation') {
726
- receiver = callNode.childForFieldName('object');
727
- }
728
- // PHP: member_call_expression has 'object' on the call node
729
- if (!receiver && (callNode.type === 'member_call_expression' || callNode.type === 'nullsafe_member_call_expression')) {
730
- receiver = callNode.childForFieldName('object');
731
- }
732
- // Kotlin/Swift: navigation_expression target is the first child
733
- if (!receiver && parent.type === 'navigation_suffix') {
734
- const navExpr = parent.parent;
735
- if (navExpr?.type === 'navigation_expression') {
736
- // First named child is the target (receiver)
737
- for (const child of navExpr.children) {
738
- if (child.isNamed && child !== parent) {
739
- receiver = child;
740
- break;
741
- }
742
- }
743
- }
744
- }
745
- if (!receiver)
746
- return undefined;
747
- // Only capture simple identifiers — refuse complex expressions
748
- if (SIMPLE_RECEIVER_TYPES.has(receiver.type)) {
749
- return receiver.text;
750
- }
751
- return undefined;
752
- };
753
- export const isVerboseIngestionEnabled = () => {
754
- const raw = process.env.GITNEXUS_VERBOSE;
755
- if (!raw)
756
- return false;
757
- const value = raw.toLowerCase();
758
- return value === '1' || value === 'true' || value === 'yes';
759
- };