gitnexus 1.6.8-rc.2 → 1.6.8-rc.21

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 (193) hide show
  1. package/README.md +20 -0
  2. package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
  3. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  4. package/dist/_shared/scope-resolution/symbol-definition.d.ts +4 -0
  5. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  6. package/dist/cli/ai-context.js +1 -0
  7. package/dist/cli/analyze-config.js +40 -0
  8. package/dist/cli/analyze.d.ts +22 -0
  9. package/dist/cli/analyze.js +36 -6
  10. package/dist/cli/clean.d.ts +1 -0
  11. package/dist/cli/clean.js +43 -1
  12. package/dist/cli/eval-server.js +43 -0
  13. package/dist/cli/help-i18n.js +11 -0
  14. package/dist/cli/i18n/en.d.ts +13 -0
  15. package/dist/cli/i18n/en.js +13 -0
  16. package/dist/cli/i18n/resources.d.ts +26 -0
  17. package/dist/cli/i18n/zh-CN.d.ts +13 -0
  18. package/dist/cli/i18n/zh-CN.js +13 -0
  19. package/dist/cli/index.js +19 -0
  20. package/dist/cli/list.js +12 -0
  21. package/dist/cli/optional-grammars.d.ts +6 -8
  22. package/dist/cli/optional-grammars.js +8 -11
  23. package/dist/cli/skill-gen.js +1 -0
  24. package/dist/cli/status.js +26 -5
  25. package/dist/cli/tool.d.ts +12 -1
  26. package/dist/cli/tool.js +41 -1
  27. package/dist/core/embeddings/embedder.js +4 -0
  28. package/dist/core/embeddings/embedding-pipeline.js +27 -16
  29. package/dist/core/embeddings/onnxruntime-common-resolver.d.ts +6 -0
  30. package/dist/core/embeddings/onnxruntime-common-resolver.js +130 -0
  31. package/dist/core/graph/import-cycles.d.ts +10 -0
  32. package/dist/core/graph/import-cycles.js +103 -0
  33. package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
  34. package/dist/core/group/extractors/http-patterns/java.js +3 -50
  35. package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
  36. package/dist/core/group/extractors/include-extractor.js +7 -7
  37. package/dist/core/ingestion/cfg/cfg-builder.d.ts +64 -0
  38. package/dist/core/ingestion/cfg/cfg-builder.js +129 -0
  39. package/dist/core/ingestion/cfg/collect.d.ts +30 -0
  40. package/dist/core/ingestion/cfg/collect.js +34 -0
  41. package/dist/core/ingestion/cfg/control-flow-context.d.ts +97 -0
  42. package/dist/core/ingestion/cfg/control-flow-context.js +113 -0
  43. package/dist/core/ingestion/cfg/emit.d.ts +144 -0
  44. package/dist/core/ingestion/cfg/emit.js +315 -0
  45. package/dist/core/ingestion/cfg/reaching-defs.d.ts +90 -0
  46. package/dist/core/ingestion/cfg/reaching-defs.js +364 -0
  47. package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
  48. package/dist/core/ingestion/cfg/traversal-result.js +2 -0
  49. package/dist/core/ingestion/cfg/types.d.ts +231 -0
  50. package/dist/core/ingestion/cfg/types.js +13 -0
  51. package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +144 -0
  52. package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1032 -0
  53. package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
  54. package/dist/core/ingestion/cfg/visitors/typescript.js +584 -0
  55. package/dist/core/ingestion/language-provider.d.ts +36 -2
  56. package/dist/core/ingestion/languages/c-cpp.js +11 -4
  57. package/dist/core/ingestion/languages/cpp/arity-metadata.js +6 -2
  58. package/dist/core/ingestion/languages/cpp/captures.js +24 -1
  59. package/dist/core/ingestion/languages/cpp/query.js +23 -0
  60. package/dist/core/ingestion/languages/java.js +3 -0
  61. package/dist/core/ingestion/languages/kotlin/query.js +3 -2
  62. package/dist/core/ingestion/languages/kotlin.js +5 -1
  63. package/dist/core/ingestion/languages/typescript.js +5 -0
  64. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
  65. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  66. package/dist/core/ingestion/method-types.d.ts +2 -0
  67. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  68. package/dist/core/ingestion/model/symbol-table.js +1 -0
  69. package/dist/core/ingestion/parsing-processor.js +22 -0
  70. package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
  71. package/dist/core/ingestion/pipeline-phases/routes.js +64 -14
  72. package/dist/core/ingestion/pipeline.d.ts +57 -0
  73. package/dist/core/ingestion/route-extractors/spring-shared.d.ts +50 -0
  74. package/dist/core/ingestion/route-extractors/spring-shared.js +80 -0
  75. package/dist/core/ingestion/route-extractors/spring.d.ts +35 -0
  76. package/dist/core/ingestion/route-extractors/spring.js +136 -0
  77. package/dist/core/ingestion/scope-extractor.js +3 -0
  78. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +12 -0
  79. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +145 -24
  80. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +6 -0
  81. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
  82. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +21 -0
  83. package/dist/core/ingestion/scope-resolution/pipeline/run.js +207 -0
  84. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  85. package/dist/core/ingestion/taint/emit.d.ts +124 -0
  86. package/dist/core/ingestion/taint/emit.js +204 -0
  87. package/dist/core/ingestion/taint/match.d.ts +153 -0
  88. package/dist/core/ingestion/taint/match.js +278 -0
  89. package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
  90. package/dist/core/ingestion/taint/path-codec.js +190 -0
  91. package/dist/core/ingestion/taint/propagate.d.ts +216 -0
  92. package/dist/core/ingestion/taint/propagate.js +664 -0
  93. package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
  94. package/dist/core/ingestion/taint/site-safety.js +98 -0
  95. package/dist/core/ingestion/taint/source-sink-config.d.ts +94 -23
  96. package/dist/core/ingestion/taint/source-sink-config.js +11 -11
  97. package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
  98. package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
  99. package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
  100. package/dist/core/ingestion/taint/typescript-model.js +102 -0
  101. package/dist/core/ingestion/utils/method-props.js +1 -0
  102. package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
  103. package/dist/core/ingestion/workers/clone-safety.js +465 -0
  104. package/dist/core/ingestion/workers/parse-worker.d.ts +11 -0
  105. package/dist/core/ingestion/workers/parse-worker.js +70 -53
  106. package/dist/core/ingestion/workers/post-result.d.ts +22 -0
  107. package/dist/core/ingestion/workers/post-result.js +87 -0
  108. package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
  109. package/dist/core/ingestion/workers/result-merge.js +43 -0
  110. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -0
  111. package/dist/core/ingestion/workers/worker-pool.js +33 -16
  112. package/dist/core/lbug/lbug-adapter.d.ts +19 -0
  113. package/dist/core/lbug/lbug-adapter.js +56 -1
  114. package/dist/core/run-analyze.d.ts +87 -0
  115. package/dist/core/run-analyze.js +280 -25
  116. package/dist/core/tree-sitter/parser-loader.js +5 -4
  117. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  118. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  119. package/dist/mcp/core/embedder.js +4 -0
  120. package/dist/mcp/local/local-backend.d.ts +86 -2
  121. package/dist/mcp/local/local-backend.js +657 -27
  122. package/dist/mcp/resources.js +1 -0
  123. package/dist/mcp/tools.d.ts +9 -0
  124. package/dist/mcp/tools.js +109 -0
  125. package/dist/server/analyze-launch.d.ts +29 -0
  126. package/dist/server/analyze-launch.js +137 -0
  127. package/dist/server/analyze-upload.d.ts +33 -0
  128. package/dist/server/analyze-upload.js +123 -0
  129. package/dist/server/analyze-worker-ipc.d.ts +58 -0
  130. package/dist/server/analyze-worker-ipc.js +16 -0
  131. package/dist/server/analyze-worker.d.ts +17 -1
  132. package/dist/server/analyze-worker.js +7 -1
  133. package/dist/server/api.js +46 -140
  134. package/dist/server/git-clone.d.ts +1 -0
  135. package/dist/server/git-clone.js +1 -1
  136. package/dist/server/middleware.d.ts +11 -0
  137. package/dist/server/middleware.js +27 -0
  138. package/dist/server/upload-ingest.d.ts +56 -0
  139. package/dist/server/upload-ingest.js +276 -0
  140. package/dist/server/upload-paths.d.ts +31 -0
  141. package/dist/server/upload-paths.js +51 -0
  142. package/dist/server/upload-sweep.d.ts +20 -0
  143. package/dist/server/upload-sweep.js +57 -0
  144. package/dist/storage/branch-index.d.ts +52 -0
  145. package/dist/storage/branch-index.js +65 -0
  146. package/dist/storage/git.d.ts +11 -0
  147. package/dist/storage/git.js +28 -0
  148. package/dist/storage/parse-cache.d.ts +22 -1
  149. package/dist/storage/parse-cache.js +32 -10
  150. package/dist/storage/repo-manager.d.ts +122 -10
  151. package/dist/storage/repo-manager.js +162 -21
  152. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +42 -8
  153. package/hooks/claude/gitnexus-hook.cjs +36 -8
  154. package/hooks/claude/hook-db-lock-probe.cjs +123 -2
  155. package/package.json +4 -2
  156. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  157. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  158. package/skills/gitnexus-guide.md +11 -0
  159. package/vendor/tree-sitter-c/package.json +1 -1
  160. package/vendor/tree-sitter-dart/package.json +1 -1
  161. package/vendor/tree-sitter-kotlin/package.json +1 -1
  162. package/vendor/tree-sitter-proto/package.json +1 -1
  163. package/vendor/tree-sitter-swift/package.json +1 -1
  164. package/web/assets/{agent-CKPMqImC.js → agent-ay4LD70X.js} +1 -1
  165. package/web/assets/{architectureDiagram-UL44E2DR-D1EXI0zA.js → architectureDiagram-UL44E2DR-Dc-viYhd.js} +1 -1
  166. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-4rpojOyj.js} +1 -1
  167. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-BnOy944n.js} +1 -1
  168. package/web/assets/{classDiagram-KGZ6W3CR-Bv93af_b.js → classDiagram-KGZ6W3CR-Bsgpy98Q.js} +1 -1
  169. package/web/assets/{classDiagram-v2-72OJOZXJ-CLfEqHUa.js → classDiagram-v2-72OJOZXJ-D5atDGjc.js} +1 -1
  170. package/web/assets/{diagram-3NCE3AQN-BqAtKUpW.js → diagram-3NCE3AQN-Cz1OEMVi.js} +1 -1
  171. package/web/assets/{diagram-GF46GFSD-CaBG6n6o.js → diagram-GF46GFSD-CWYwzfP8.js} +1 -1
  172. package/web/assets/{diagram-QXG6HAR7-CZ-O3rcV.js → diagram-QXG6HAR7-DtBObr8L.js} +1 -1
  173. package/web/assets/{diagram-WEQXMOUZ-P4lSL4GH.js → diagram-WEQXMOUZ-BUV44Ov_.js} +1 -1
  174. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-Ds9s-sRF.js} +1 -1
  175. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-CupStHQb.js} +1 -1
  176. package/web/assets/index-COMMmbxW.css +2 -0
  177. package/web/assets/{index-CG6q8eTs.js → index-Do8AE5yF.js} +85 -85
  178. package/web/assets/{infoDiagram-3YFTVSEB-DmLICZx1.js → infoDiagram-3YFTVSEB-DPTXSbgu.js} +1 -1
  179. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CeK-Qhet.js} +1 -1
  180. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-D4tx6QQ-.js} +1 -1
  181. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-Bcto_kGa.js} +1 -1
  182. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-DPIeBTG6.js} +1 -1
  183. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-DDGXjVKO.js} +1 -1
  184. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-BzDqpcVW.js} +1 -1
  185. package/web/assets/{stateDiagram-7D4R322I-CB2nABwH.js → stateDiagram-7D4R322I-Bx__als3.js} +1 -1
  186. package/web/assets/{stateDiagram-v2-36443NZ5-COBGd2RL.js → stateDiagram-v2-36443NZ5-QqOh2yO-.js} +1 -1
  187. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-C1eogTOG.js} +1 -1
  188. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-D20F4rSW.js} +1 -1
  189. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-BeBHg7ST.js} +1 -1
  190. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-CdOWeoNI.js} +1 -1
  191. package/web/index.html +2 -2
  192. package/scripts/materialize-vendor-grammars.cjs +0 -97
  193. package/web/assets/index-BKWA-m7o.css +0 -2
@@ -16,8 +16,8 @@ import { extractStructuralNames } from './structural-extractor.js';
16
16
  import { EMBEDDABLE_LABELS, isShortLabel, LABEL_METHOD, LABELS_WITH_EXPORTED, STRUCTURAL_LABELS, collectBestChunks, } from './types.js';
17
17
  import { resolveEmbeddingConfig } from './config.js';
18
18
  import { rankExactEmbeddingRows } from './exact-search.js';
19
- import { EMBEDDING_TABLE_NAME, EMBEDDING_INDEX_NAME, CREATE_VECTOR_INDEX_QUERY, STALE_HASH_SENTINEL, } from '../lbug/schema.js';
20
- import { loadVectorExtension } from '../lbug/lbug-adapter.js';
19
+ import { EMBEDDING_TABLE_NAME, EMBEDDING_INDEX_NAME, STALE_HASH_SENTINEL } from '../lbug/schema.js';
20
+ import { loadVectorExtension, createVectorIndex } from '../lbug/lbug-adapter.js';
21
21
  import { getExactScanLimit } from '../platform/capabilities.js';
22
22
  import { logger } from '../logger.js';
23
23
  const isDev = process.env.NODE_ENV === 'development';
@@ -153,24 +153,35 @@ export const batchInsertEmbeddings = async (executeWithReusedStatement, updates)
153
153
  await executeWithReusedStatement(cypher, paramsList);
154
154
  };
155
155
  /**
156
- * Create the vector index for semantic search
157
-
158
- * Now indexes the separate CodeEmbedding table.
159
- * Delegates extension loading to lbug-adapter's loadVectorExtension(),
160
- * which owns the VECTOR extension lifecycle and state tracking.
161
-
156
+ * Create the vector index for semantic search (indexes the CodeEmbedding table).
157
+ *
158
+ * Keeps the embedding-specific extension-install policy gate here
159
+ * (ensureVectorExtensionAvailable resolveEmbeddingInstallPolicy, default
160
+ * `auto` for the analyze write path), then delegates the actual
161
+ * `CALL CREATE_VECTOR_INDEX(...)` to the adapter, which runs it through the
162
+ * unprepared `conn.query()` path. It must NOT go through the injected
163
+ * `executeQuery` (prepared `conn.prepare()`): LadybugDB cannot prepare that
164
+ * procedure and fails with "We do not support prepare multiple statements" —
165
+ * the silent degrade in #2114.
162
166
  */
163
- const createVectorIndex = async (executeQuery) => {
167
+ const buildVectorIndex = async () => {
168
+ // This pre-check applies the embedding-specific install policy
169
+ // (resolveEmbeddingInstallPolicy, default `auto` for analyze) before reaching
170
+ // the adapter. The adapter's createVectorIndex() calls loadVectorExtension()
171
+ // again, but that's a no-op here: once this gate loads VECTOR the module-level
172
+ // `vectorExtensionLoaded` flag is set, so the adapter's second call
173
+ // short-circuits without re-resolving the policy — no double install.
164
174
  if (!(await ensureVectorExtensionAvailable()))
165
175
  return false;
166
176
  try {
167
- await executeQuery(CREATE_VECTOR_INDEX_QUERY);
168
- return true;
177
+ return await createVectorIndex();
169
178
  }
170
179
  catch (error) {
171
- if (isDev) {
172
- logger.warn({ error }, 'Vector index creation warning:');
173
- }
180
+ // Surface this even outside dev: it silently downgrades a user-requested
181
+ // feature (semantic search) to exact scan. Log under `err` so pino's
182
+ // standard serializer captures the message/stack — logging under `error`
183
+ // serialized an Error to `{}` (the empty `{"error":{}}` reported in #2114).
184
+ logger.warn({ err: error }, 'Vector index creation failed; semantic search will use exact-scan fallback');
174
185
  return false;
175
186
  }
176
187
  };
@@ -283,7 +294,7 @@ export const runEmbeddingPipeline = async (executeQuery, executeWithReusedStatem
283
294
  // Ensure the vector index exists even when no new nodes need embedding.
284
295
  // A prior crash or first-time incremental run may have left CodeEmbedding
285
296
  // rows without ever reaching index creation.
286
- const vectorIndexReady = await createVectorIndex(executeQuery);
297
+ const vectorIndexReady = await buildVectorIndex();
287
298
  onProgress({
288
299
  phase: 'ready',
289
300
  percent: 100,
@@ -403,7 +414,7 @@ export const runEmbeddingPipeline = async (executeQuery, executeWithReusedStatem
403
414
  if (isDev) {
404
415
  logger.info('📇 Creating vector index...');
405
416
  }
406
- const vectorIndexReady = await createVectorIndex(executeQuery);
417
+ const vectorIndexReady = await buildVectorIndex();
407
418
  onProgress({
408
419
  phase: 'ready',
409
420
  percent: 100,
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Idempotently install the onnxruntime-common resolution fallback. Call once
3
+ * immediately before the dynamic `import('@huggingface/transformers')` on the
4
+ * local-embedding path.
5
+ */
6
+ export declare const ensureOnnxRuntimeCommonResolvable: () => void;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Make `@huggingface/transformers`' phantom `onnxruntime-common` import
3
+ * resolvable under strict package-manager layouts (#307, #2069).
4
+ *
5
+ * ## Why
6
+ * transformers' shipped `dist/transformers.node.mjs` does a bare
7
+ * `import 'onnxruntime-common'`, but transformers' `package.json` never declares
8
+ * onnxruntime-common (it lists onnxruntime-node / onnxruntime-web / sharp). With
9
+ * npm's flat `node_modules` — or pnpm with hoisting — the package is hoisted to
10
+ * a directory on transformers' resolution path and the import resolves by
11
+ * accident. Under pnpm's isolated store (and therefore `pnpm dlx` / `pnpx`), a
12
+ * package only sees its *declared* deps, so the import dies with
13
+ * `ERR_MODULE_NOT_FOUND` before `analyze --embeddings` can run.
14
+ *
15
+ * Declaring onnxruntime-common in gitnexus' own dependencies (#2074) does NOT
16
+ * fix this under pnpm: Node resolves the bare specifier from *transformers'*
17
+ * module scope, not ours, and overrides/resolutions can only re-version an
18
+ * existing edge, never add the missing one.
19
+ *
20
+ * ## What this does
21
+ * Install a synchronous, in-thread ESM resolution hook (`module.registerHooks`,
22
+ * Node >= 22.15) that redirects `onnxruntime-common` to a copy gitnexus can
23
+ * resolve — but only when the default resolver fails. The redirect target is
24
+ * preferentially the `onnxruntime-common` that `onnxruntime-node` (the native
25
+ * binding transformers actually loads) itself depends on, so the redirected copy
26
+ * is version-matched to that binding even under `pnpm dlx` — where gitnexus'
27
+ * npm-style `overrides` block does NOT apply, because it is honoured only from a
28
+ * root manifest and gitnexus is a transitive dependency there. It falls back to
29
+ * gitnexus' own direct `onnxruntime-common` dependency when that chain can't be
30
+ * walked. onnxruntime-common is a stable, pure-JS package whose `Tensor` surface
31
+ * is unchanged across 1.24–1.26, so either target is API-compatible. On working
32
+ * layouts the default resolver succeeds first and the hook never fires, so
33
+ * behaviour is unchanged.
34
+ *
35
+ * `registerHooks` (synchronous, in-thread) is preferred over the older
36
+ * `module.register` (async, off-thread, now deprecated — DEP0205, removed in
37
+ * Node 26): the redirect is a one-line conditional that needs no worker thread,
38
+ * no separate hook module, and no `data` marshalling.
39
+ *
40
+ * ## Safety
41
+ * Best-effort and idempotent. The hook is installed lazily, only on the
42
+ * local-embedding code path (after parsing), so it is never registered during
43
+ * analysis, in the parse workers, or in HTTP embedding mode. Once installed it
44
+ * is process-global: its resolve closure runs for every subsequent module
45
+ * resolution, but it passes all of them through untouched and only substitutes a
46
+ * result for the exact `onnxruntime-common` specifier when that specifier is
47
+ * genuinely absent — so it cannot mask an unrelated resolution error, and the
48
+ * per-resolution cost is a single string comparison.
49
+ *
50
+ * `module.registerHooks` is marked `@experimental` and requires Node >= 22.15
51
+ * (the gitnexus engines floor is >= 22.0.0). On older runtimes it is absent and
52
+ * this is a graceful no-op: embeddings then resolve onnxruntime-common exactly
53
+ * as before — fine on hoisted layouts. Any failure during installation is
54
+ * swallowed.
55
+ */
56
+ import { registerHooks, createRequire } from 'node:module';
57
+ import { pathToFileURL } from 'node:url';
58
+ import { logger } from '../logger.js';
59
+ let attempted = false;
60
+ /**
61
+ * Compute the file: URL the hook redirects `onnxruntime-common` to.
62
+ *
63
+ * Prefer the copy `onnxruntime-node` (the native binding transformers loads)
64
+ * depends on, so the redirected module is version-matched to the binding even
65
+ * under `pnpm dlx`, where transformers keeps its own pinned onnxruntime-node.
66
+ * The walk resolves transformers' MAIN entry — NOT `@huggingface/transformers/
67
+ * package.json`, which transformers' `exports` map blocks
68
+ * (`ERR_PACKAGE_PATH_NOT_EXPORTED`) — then onnxruntime-node, then its
69
+ * onnxruntime-common. Falls back to gitnexus' own direct dependency (always
70
+ * resolvable from our scope) when any step fails.
71
+ */
72
+ const resolveOnnxRuntimeCommonUrl = () => {
73
+ const require = createRequire(import.meta.url);
74
+ try {
75
+ const transformersMain = require.resolve('@huggingface/transformers');
76
+ const ortNodePkg = createRequire(transformersMain).resolve('onnxruntime-node/package.json');
77
+ const common = createRequire(ortNodePkg).resolve('onnxruntime-common');
78
+ return pathToFileURL(common).href;
79
+ }
80
+ catch {
81
+ return pathToFileURL(require.resolve('onnxruntime-common')).href;
82
+ }
83
+ };
84
+ /**
85
+ * Idempotently install the onnxruntime-common resolution fallback. Call once
86
+ * immediately before the dynamic `import('@huggingface/transformers')` on the
87
+ * local-embedding path.
88
+ */
89
+ export const ensureOnnxRuntimeCommonResolvable = () => {
90
+ if (attempted)
91
+ return;
92
+ // Mark attempted up-front: a failed attempt must not retry on every
93
+ // initEmbedder() call, and the hook is process-global — once is enough.
94
+ attempted = true;
95
+ try {
96
+ // Node < 22.15 (the gitnexus engines floor is >= 22.0.0): no synchronous
97
+ // hooks API. Degrade gracefully — the import still works on hoisted layouts.
98
+ if (typeof registerHooks !== 'function')
99
+ return;
100
+ const redirectUrl = resolveOnnxRuntimeCommonUrl();
101
+ registerHooks({
102
+ resolve(specifier, context, nextResolve) {
103
+ if (specifier !== 'onnxruntime-common')
104
+ return nextResolve(specifier, context);
105
+ // Honour a real, package-manager-provided copy when one is on the path
106
+ // (npm / hoisted pnpm); only substitute ours when the specifier is
107
+ // genuinely absent.
108
+ try {
109
+ return nextResolve(specifier, context);
110
+ }
111
+ catch (err) {
112
+ // The phantom import surfaces as ERR_MODULE_NOT_FOUND (or, for a
113
+ // present-but-exports-broken copy, ERR_PACKAGE_PATH_NOT_EXPORTED).
114
+ // Rethrow anything else so a genuinely broken install is not masked.
115
+ const code = err?.code;
116
+ if (code === 'ERR_MODULE_NOT_FOUND' || code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
117
+ return { url: redirectUrl, shortCircuit: true };
118
+ }
119
+ throw err;
120
+ }
121
+ },
122
+ });
123
+ logger.debug({ redirectUrl }, 'Installed onnxruntime-common resolution fallback (#307)');
124
+ }
125
+ catch (err) {
126
+ // Never block embeddings on the fallback. On layouts where the package
127
+ // manager already resolves onnxruntime-common this is unnecessary anyway.
128
+ logger.debug({ err: err instanceof Error ? err.message : String(err) }, 'onnxruntime-common resolution fallback not installed');
129
+ }
130
+ };
@@ -0,0 +1,10 @@
1
+ interface ImportEdge {
2
+ source: string;
3
+ target: string;
4
+ }
5
+ /**
6
+ * Return one deterministic concrete cycle for every cyclic strongly connected
7
+ * component in the file import graph.
8
+ */
9
+ export declare function findImportCycles(edges: ImportEdge[]): string[][];
10
+ export {};
@@ -0,0 +1,103 @@
1
+ function findCyclePath(component, adjacency) {
2
+ const allowed = new Set(component);
3
+ const start = component[0];
4
+ const parents = new Map([[start, null]]);
5
+ const queue = [start];
6
+ for (let index = 0; index < queue.length; index += 1) {
7
+ const node = queue[index];
8
+ for (const next of adjacency.get(node) ?? []) {
9
+ if (!allowed.has(next))
10
+ continue;
11
+ if (next === start) {
12
+ const path = [];
13
+ let cursor = node;
14
+ while (cursor !== null) {
15
+ path.push(cursor);
16
+ cursor = parents.get(cursor) ?? null;
17
+ }
18
+ path.reverse();
19
+ return [...path, start];
20
+ }
21
+ if (parents.has(next))
22
+ continue;
23
+ parents.set(next, node);
24
+ queue.push(next);
25
+ }
26
+ }
27
+ throw new Error('Invariant violation: no cycle found through SCC root.');
28
+ }
29
+ /**
30
+ * Return one deterministic concrete cycle for every cyclic strongly connected
31
+ * component in the file import graph.
32
+ */
33
+ export function findImportCycles(edges) {
34
+ const adjacency = new Map();
35
+ for (const { source, target } of edges) {
36
+ if (!source || !target)
37
+ continue;
38
+ const targets = adjacency.get(source) ?? new Set();
39
+ targets.add(target);
40
+ adjacency.set(source, targets);
41
+ if (!adjacency.has(target))
42
+ adjacency.set(target, new Set());
43
+ }
44
+ const sortedAdjacency = new Map([...adjacency].map(([node, targets]) => [node, [...targets].sort()]));
45
+ const reverseAdjacency = new Map();
46
+ for (const node of sortedAdjacency.keys())
47
+ reverseAdjacency.set(node, []);
48
+ for (const [source, targets] of sortedAdjacency) {
49
+ for (const target of targets)
50
+ reverseAdjacency.get(target).push(source);
51
+ }
52
+ for (const sources of reverseAdjacency.values())
53
+ sources.sort();
54
+ const visited = new Set();
55
+ const finishOrder = [];
56
+ const components = [];
57
+ for (const start of [...sortedAdjacency.keys()].sort()) {
58
+ if (visited.has(start))
59
+ continue;
60
+ visited.add(start);
61
+ const stack = [{ node: start, nextIndex: 0 }];
62
+ while (stack.length > 0) {
63
+ const frame = stack[stack.length - 1];
64
+ const neighbors = sortedAdjacency.get(frame.node) ?? [];
65
+ if (frame.nextIndex < neighbors.length) {
66
+ const next = neighbors[frame.nextIndex++];
67
+ if (!visited.has(next)) {
68
+ visited.add(next);
69
+ stack.push({ node: next, nextIndex: 0 });
70
+ }
71
+ }
72
+ else {
73
+ finishOrder.push(frame.node);
74
+ stack.pop();
75
+ }
76
+ }
77
+ }
78
+ visited.clear();
79
+ for (let index = finishOrder.length - 1; index >= 0; index -= 1) {
80
+ const start = finishOrder[index];
81
+ if (visited.has(start))
82
+ continue;
83
+ const component = [];
84
+ const stack = [start];
85
+ visited.add(start);
86
+ while (stack.length > 0) {
87
+ const node = stack.pop();
88
+ component.push(node);
89
+ for (const next of reverseAdjacency.get(node) ?? []) {
90
+ if (visited.has(next))
91
+ continue;
92
+ visited.add(next);
93
+ stack.push(next);
94
+ }
95
+ }
96
+ component.sort();
97
+ components.push(component);
98
+ }
99
+ return components
100
+ .filter((component) => component.length > 1 || (sortedAdjacency.get(component[0]) ?? []).includes(component[0]))
101
+ .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
102
+ .map((component) => findCyclePath(component, sortedAdjacency));
103
+ }
@@ -1,23 +1,27 @@
1
1
  import { createRequire } from 'node:module';
2
+ import { requireVendoredGrammar } from '../../../tree-sitter/vendored-grammars.js';
2
3
  import { compilePatterns, runCompiledPatterns, } from '../tree-sitter-scanner.js';
3
4
  /**
4
5
  * Protobuf (.proto) tree-sitter plugin for gRPC contract extraction.
5
6
  *
6
- * Uses `tree-sitter-proto` (coder3101/tree-sitter-proto) as an
7
- * optionalDependency if the grammar is not installed (e.g. native
8
- * compilation failed on an unusual platform), the plugin exports
9
- * `null` and the orchestrator falls back to the existing manual
10
- * string-sanitizing parser.
7
+ * Uses `tree-sitter-proto` (coder3101/tree-sitter-proto), loaded from
8
+ * `vendor/` by absolute path (NEVER copied into node_modules see
9
+ * vendored-grammars.ts / #2111). If the grammar's binding cannot be loaded
10
+ * (e.g. no prebuild for an unusual platform), the plugin exports `null` and the
11
+ * orchestrator falls back to the existing manual string-sanitizing parser.
11
12
  *
12
13
  * The grammar is vendored in `vendor/tree-sitter-proto/` with
13
14
  * parser.c regenerated against tree-sitter-cli 0.24 (ABI version 14)
14
15
  * so it is compatible with the project's tree-sitter 0.21.1 runtime
15
16
  * (which loads ABI 13–14).
16
17
  */
18
+ // Only for `tree-sitter` (a real npm dependency) in the smoke-test below;
19
+ // the vendored grammar goes through requireVendoredGrammar (never a bare
20
+ // `_require('tree-sitter-proto')`, which would force a node_modules copy — #2111).
17
21
  const _require = createRequire(import.meta.url);
18
22
  let ProtoGrammar = null;
19
23
  try {
20
- ProtoGrammar = _require('tree-sitter-proto');
24
+ ProtoGrammar = requireVendoredGrammar('tree-sitter-proto');
21
25
  }
22
26
  catch {
23
27
  // Grammar not installed — PROTO_GRPC_PLUGIN will be null.
@@ -1,31 +1,6 @@
1
1
  import Java from 'tree-sitter-java';
2
2
  import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-sitter-scanner.js';
3
- /**
4
- * Java HTTP plugin. Handles:
5
- * - Spring `@RequestMapping` class prefixes + `@(Get|Post|...)Mapping` method annotations
6
- * - Spring `RestTemplate.getForObject/...`, `exchange(...)`
7
- * - Spring `WebClient.method(HttpMethod.X, ...)`, `WebClient.get().uri(...)`
8
- * - OkHttp `new Request.Builder().url("...")`
9
- * - OpenFeign interfaces with Spring MVC method annotations or
10
- * native `@RequestLine("METHOD /path")` annotations
11
- * - Java / Apache HttpClient literal request construction
12
- *
13
- * Every route-defining annotation (class/interface `@RequestMapping`
14
- * prefixes, `@FeignClient(path)` prefixes, `@(Get|...)Mapping` method
15
- * routes and native `@RequestLine`s) is matched by a single consolidated
16
- * query (`JAVA_ROUTE_ANNOTATION_PATTERNS`) in one pass via
17
- * `scanRouteAnnotations`. The `scan` function then walks up from each
18
- * matched method to its enclosing class/interface to combine the prefix
19
- * with the method path. Call-site consumers (RestTemplate, WebClient,
20
- * OkHttp, Java/Apache HttpClient) keep their own focused queries.
21
- */
22
- const METHOD_ANNOTATION_TO_HTTP = {
23
- GetMapping: 'GET',
24
- PostMapping: 'POST',
25
- PutMapping: 'PUT',
26
- DeleteMapping: 'DELETE',
27
- PatchMapping: 'PATCH',
28
- };
3
+ import { METHOD_ANNOTATION_TO_HTTP, isRouteMemberKey, findEnclosingClass, } from '../../../ingestion/route-extractors/spring-shared.js';
29
4
  // ─── Route-defining annotations (one generic query, one pass) ─────────
30
5
  // Every Java route-mapper annotation shares one shape: an annotation carrying a
31
6
  // single string argument — positional `"..."` or named `key = "..."` — on a
@@ -300,19 +275,9 @@ const APACHE_HTTP_CLIENT_PATTERNS = compilePatterns({
300
275
  ],
301
276
  });
302
277
  /**
303
- * Find the nearest enclosing class/interface declaration ancestor for
304
- * a node, or null if the node is top-level. Tree-sitter's
305
- * SyntaxNode.parent walks one level at a time.
278
+ * Find the nearest enclosing interface declaration ancestor for a node, or
279
+ * null if the node is top-level.
306
280
  */
307
- function findEnclosingClass(node) {
308
- let cur = node.parent;
309
- while (cur) {
310
- if (cur.type === 'class_declaration')
311
- return cur;
312
- cur = cur.parent;
313
- }
314
- return null;
315
- }
316
281
  function findEnclosingInterface(node) {
317
282
  let cur = node.parent;
318
283
  while (cur) {
@@ -369,18 +334,6 @@ function hasAnnotation(node, names) {
369
334
  }
370
335
  return false;
371
336
  }
372
- /**
373
- * A named annotation argument contributes a route only when its member key is
374
- * `path` or `value`; a positional argument (no key node) always qualifies.
375
- * This is the JS-side replacement for the in-query `^(path|value)$` filter and
376
- * drops Spring's non-route string attributes (`produces`, `consumes`,
377
- * `headers`, `name`, `params`) that would otherwise be mis-read as routes.
378
- */
379
- function isRouteMemberKey(keyNode) {
380
- if (!keyNode)
381
- return true;
382
- return keyNode.text === 'path' || keyNode.text === 'value';
383
- }
384
337
  /**
385
338
  * Resolve every Java route-defining annotation in a single tree-sitter pass.
386
339
  *
@@ -1,4 +1,4 @@
1
- import { createRequire } from 'node:module';
1
+ import { requireVendoredGrammar } from '../../../tree-sitter/vendored-grammars.js';
2
2
  import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-sitter-scanner.js';
3
3
  /**
4
4
  * Kotlin HTTP plugin (Spring providers + consumers).
@@ -52,15 +52,15 @@ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-s
52
52
  * value_argument
53
53
  * string_literal ← the path
54
54
  *
55
- * tree-sitter-kotlin is an optional npm dependency when its native
56
- * binding is unavailable the plugin gracefully exports `null` and
57
- * `http-patterns/index.ts` skips registration for `.kt`/`.kts` files.
55
+ * tree-sitter-kotlin is a vendored grammar loaded from `vendor/` by absolute
56
+ * path (NEVER copied into node_modules see vendored-grammars.ts / #2111) —
57
+ * when its native binding is unavailable the plugin gracefully exports `null`
58
+ * and `http-patterns/index.ts` skips registration for `.kt`/`.kts` files.
58
59
  */
59
- const _require = createRequire(import.meta.url);
60
- /** Loaded lazily; null when the grammar binding isn't installed. */
60
+ /** Loaded lazily; null when the grammar binding isn't available. */
61
61
  let Kotlin = null;
62
62
  try {
63
- Kotlin = _require('tree-sitter-kotlin');
63
+ Kotlin = requireVendoredGrammar('tree-sitter-kotlin');
64
64
  }
65
65
  catch {
66
66
  Kotlin = null;
@@ -1,19 +1,19 @@
1
1
  import * as path from 'node:path';
2
2
  import * as fs from 'node:fs/promises';
3
- import { createRequire } from 'node:module';
4
3
  import { glob } from 'glob';
5
4
  import Parser from 'tree-sitter';
6
5
  import Cpp from 'tree-sitter-cpp';
7
- // `tree-sitter-c` is vendored prebuild-only (#2116) and may be absent on a
8
- // toolchain-less / `--ignore-scripts` install. Load it via a guarded `_require`
9
- // rather than a top-level `import C from 'tree-sitter-c'`, which would throw
10
- // ERR_MODULE_NOT_FOUND at module-load and crash analyze (#2091/#2093). When the
6
+ import { requireVendoredGrammar } from '../../tree-sitter/vendored-grammars.js';
7
+ // `tree-sitter-c` is vendored (#2116), loaded from `vendor/` by absolute path
8
+ // (NEVER copied into node_modules see vendored-grammars.ts / #2111). Load it
9
+ // via a guarded call rather than a top-level `import C from 'tree-sitter-c'`,
10
+ // which would throw ERR_MODULE_NOT_FOUND at module-load and crash analyze
11
+ // (#2091/#2093). It may be absent on a platform without a prebuild; when the
11
12
  // binding is absent, `getLanguageForFile` returns null for `.c`/`.h` so C
12
13
  // include-extraction is skipped (C++ is unaffected — its binding always ships).
13
- const _require = createRequire(import.meta.url);
14
14
  let C = null;
15
15
  try {
16
- C = _require('tree-sitter-c');
16
+ C = requireVendoredGrammar('tree-sitter-c');
17
17
  }
18
18
  catch {
19
19
  /* C grammar unavailable — C include extraction degrades to a no-op. */
@@ -0,0 +1,64 @@
1
+ /**
2
+ * CfgBuilder (issue #2081, M1) — the language-agnostic accumulator.
3
+ *
4
+ * A per-language `CfgVisitor` drives this: it creates blocks as it walks
5
+ * statements, wires edges (including back-edges and break/continue/return/throw
6
+ * targets resolved via {@link ControlFlowContext}), and calls {@link finish} to
7
+ * produce the serializable {@link FunctionCfg}. The builder owns the synthetic
8
+ * ENTRY (index 0) and EXIT blocks and de-duplicates identical edges so repeated
9
+ * `connect` calls (common when wiring a set of dangling exits) stay idempotent.
10
+ *
11
+ * It has no knowledge of any AST — it is exercised directly in unit tests with
12
+ * hand-built block sequences, which is how the classic CFG hazards are pinned
13
+ * before the tree-sitter visitor (U2) drives it.
14
+ */
15
+ import type { BasicBlockData, BindingEntry, CfgEdgeKind, FunctionCfg, StatementFacts } from './types.js';
16
+ export declare class CfgBuilder {
17
+ private readonly filePath;
18
+ private readonly functionStartLine;
19
+ private readonly functionEndLine;
20
+ /** Start column of the owning function — disambiguates same-line functions
21
+ * in the BasicBlock ids (see {@link FunctionCfg.functionStartColumn}).
22
+ * Defaults to 0 for hand-built test CFGs that don't model columns. */
23
+ private readonly functionStartColumn;
24
+ private readonly blocks;
25
+ private readonly edges;
26
+ private readonly edgeKeys;
27
+ readonly entryIndex: number;
28
+ readonly exitIndex: number;
29
+ constructor(filePath: string, functionStartLine: number, functionEndLine: number,
30
+ /** Start column of the owning function — disambiguates same-line functions
31
+ * in the BasicBlock ids (see {@link FunctionCfg.functionStartColumn}).
32
+ * Defaults to 0 for hand-built test CFGs that don't model columns. */
33
+ functionStartColumn?: number);
34
+ /** Create a block and return its index. */
35
+ newBlock(startLine: number, endLine: number, text: string, kind?: BasicBlockData['kind'], facts?: StatementFacts): number;
36
+ /** Add a single edge (idempotent on from+to+kind). */
37
+ edge(from: number, to: number, kind: CfgEdgeKind): void;
38
+ /** Wire a set of dangling exits to a single target block with one kind. */
39
+ connect(exits: readonly number[], to: number, kind?: CfgEdgeKind): void;
40
+ /** Extend a block's end line as more statements accrue to it. */
41
+ extendBlock(index: number, endLine: number, appendText?: string, facts?: StatementFacts): void;
42
+ /**
43
+ * Attach a facts-only statement record to a block WITHOUT touching its text
44
+ * or line span (#2082 M2 U1) — bench fingerprints and CFG snapshots include
45
+ * block text, so harvesting must never perturb it (ENTRY-block param defs
46
+ * are the canonical use; records that must precede a walked body get their
47
+ * own facts-only block instead, see the catch-param handling in visitTry).
48
+ */
49
+ attachFacts(index: number, facts: StatementFacts): void;
50
+ get blockCount(): number;
51
+ /** Produce the serializable CFG. Caller is responsible for having wired the
52
+ * function's dangling exits to {@link exitIndex} before calling.
53
+ *
54
+ * Pass `bindings` (the function's binding table, possibly empty) to emit
55
+ * statement facts (#2082 M2 U1) — every block then carries a `statements`
56
+ * array. Omit it (hand-built test CFGs, pre-M2 producers) and both fields
57
+ * are absent, which the reaching-defs solver reports as `no-facts`. */
58
+ finish(bindings?: readonly BindingEntry[]): FunctionCfg;
59
+ }
60
+ /**
61
+ * Block indices reachable from `entryIndex` by following edges. Backs the
62
+ * reachability property tests (R9) over hand-built and visitor-produced CFGs.
63
+ */
64
+ export declare const reachableBlocks: (cfg: FunctionCfg) => Set<number>;