gitnexus 1.6.8-rc.9 → 1.6.8

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 (430) hide show
  1. package/README.md +3 -3
  2. package/dist/_shared/graph/types.d.ts +31 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.d.ts.map +1 -1
  5. package/dist/_shared/language-detection.js +11 -1
  6. package/dist/_shared/language-detection.js.map +1 -1
  7. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  8. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  9. package/dist/_shared/lbug/schema-constants.js +6 -0
  10. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  11. package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
  12. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  13. package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
  14. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  15. package/dist/cli/ai-context.d.ts +31 -1
  16. package/dist/cli/ai-context.js +18 -16
  17. package/dist/cli/analyze-config.js +11 -0
  18. package/dist/cli/analyze.d.ts +14 -0
  19. package/dist/cli/analyze.js +98 -0
  20. package/dist/cli/embedding-dims.d.ts +33 -0
  21. package/dist/cli/embedding-dims.js +39 -0
  22. package/dist/cli/eval-server.d.ts +8 -0
  23. package/dist/cli/eval-server.js +242 -2
  24. package/dist/cli/help-i18n.js +19 -0
  25. package/dist/cli/i18n/en.d.ts +15 -1
  26. package/dist/cli/i18n/en.js +15 -1
  27. package/dist/cli/i18n/resources.d.ts +29 -1
  28. package/dist/cli/i18n/zh-CN.d.ts +14 -0
  29. package/dist/cli/i18n/zh-CN.js +15 -1
  30. package/dist/cli/index.js +89 -1
  31. package/dist/cli/mcp.d.ts +6 -1
  32. package/dist/cli/mcp.js +26 -1
  33. package/dist/cli/optional-grammars.d.ts +6 -8
  34. package/dist/cli/optional-grammars.js +8 -11
  35. package/dist/cli/setup.d.ts +3 -1
  36. package/dist/cli/setup.js +67 -17
  37. package/dist/cli/skill-gen.js +2 -1
  38. package/dist/cli/tool.d.ts +19 -1
  39. package/dist/cli/tool.js +96 -3
  40. package/dist/core/embeddings/hf-env.d.ts +0 -66
  41. package/dist/core/embeddings/http-client.d.ts +7 -0
  42. package/dist/core/embeddings/http-client.js +5 -3
  43. package/dist/core/embeddings/server-mapping.d.ts +1 -1
  44. package/dist/core/embeddings/server-mapping.js +7 -3
  45. package/dist/core/graph/import-cycles.d.ts +10 -0
  46. package/dist/core/graph/import-cycles.js +103 -0
  47. package/dist/core/group/cross-impact.d.ts +2 -1
  48. package/dist/core/group/cross-impact.js +5 -1
  49. package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
  50. package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
  51. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  52. package/dist/core/group/extractors/http-route-extractor.js +22 -4
  53. package/dist/core/group/extractors/include-extractor.js +22 -13
  54. package/dist/core/group/sync.d.ts +27 -1
  55. package/dist/core/group/sync.js +0 -0
  56. package/dist/core/incremental/subgraph-extract.js +18 -1
  57. package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
  58. package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
  59. package/dist/core/ingestion/cfg/collect.d.ts +51 -0
  60. package/dist/core/ingestion/cfg/collect.js +77 -0
  61. package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
  62. package/dist/core/ingestion/cfg/control-dependence.js +182 -0
  63. package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
  64. package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
  65. package/dist/core/ingestion/cfg/emit.d.ts +293 -0
  66. package/dist/core/ingestion/cfg/emit.js +646 -0
  67. package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
  68. package/dist/core/ingestion/cfg/post-dominators.js +176 -0
  69. package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
  70. package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
  71. package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
  72. package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
  73. package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
  74. package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
  75. package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
  76. package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
  77. package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
  78. package/dist/core/ingestion/cfg/traversal-result.js +2 -0
  79. package/dist/core/ingestion/cfg/types.d.ts +274 -0
  80. package/dist/core/ingestion/cfg/types.js +13 -0
  81. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
  82. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
  83. package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
  84. package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
  85. package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
  86. package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
  87. package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
  88. package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
  89. package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
  90. package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
  91. package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
  92. package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
  93. package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
  94. package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
  95. package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
  96. package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
  97. package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
  98. package/dist/core/ingestion/cfg/visitors/go.js +638 -0
  99. package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
  100. package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
  101. package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
  102. package/dist/core/ingestion/cfg/visitors/java.js +812 -0
  103. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
  104. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
  105. package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
  106. package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
  107. package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
  108. package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
  109. package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
  110. package/dist/core/ingestion/cfg/visitors/php.js +721 -0
  111. package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
  112. package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
  113. package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
  114. package/dist/core/ingestion/cfg/visitors/python.js +558 -0
  115. package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
  116. package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
  117. package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
  118. package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
  119. package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
  120. package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
  121. package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
  122. package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
  123. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
  124. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
  125. package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
  126. package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
  127. package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
  128. package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
  129. package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
  130. package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
  131. package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
  132. package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
  133. package/dist/core/ingestion/import-resolvers/utils.js +2 -0
  134. package/dist/core/ingestion/language-provider.d.ts +11 -0
  135. package/dist/core/ingestion/languages/c-cpp.js +6 -1
  136. package/dist/core/ingestion/languages/cobol.js +4 -0
  137. package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
  138. package/dist/core/ingestion/languages/cpp/captures.js +50 -1
  139. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
  140. package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
  141. package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
  142. package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
  143. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
  144. package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
  145. package/dist/core/ingestion/languages/cpp/query.js +23 -0
  146. package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
  147. package/dist/core/ingestion/languages/csharp.js +2 -0
  148. package/dist/core/ingestion/languages/dart.js +2 -0
  149. package/dist/core/ingestion/languages/go.js +2 -0
  150. package/dist/core/ingestion/languages/java.js +3 -0
  151. package/dist/core/ingestion/languages/kotlin/query.js +3 -2
  152. package/dist/core/ingestion/languages/kotlin.js +3 -0
  153. package/dist/core/ingestion/languages/php.js +2 -0
  154. package/dist/core/ingestion/languages/python.js +2 -0
  155. package/dist/core/ingestion/languages/ruby.js +2 -0
  156. package/dist/core/ingestion/languages/rust.js +2 -0
  157. package/dist/core/ingestion/languages/swift.js +2 -0
  158. package/dist/core/ingestion/languages/typescript.js +5 -0
  159. package/dist/core/ingestion/languages/vue.js +6 -0
  160. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
  161. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  162. package/dist/core/ingestion/method-types.d.ts +2 -0
  163. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  164. package/dist/core/ingestion/model/symbol-table.js +1 -0
  165. package/dist/core/ingestion/mro-processor.js +109 -0
  166. package/dist/core/ingestion/parsing-processor.js +23 -0
  167. package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
  168. package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
  169. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  170. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  171. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
  172. package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
  173. package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
  174. package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
  175. package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
  176. package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
  177. package/dist/core/ingestion/pipeline.d.ts +92 -10
  178. package/dist/core/ingestion/pipeline.js +11 -2
  179. package/dist/core/ingestion/scope-extractor.js +12 -2
  180. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
  181. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
  182. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
  183. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
  184. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
  185. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
  186. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
  187. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
  188. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
  189. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
  190. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
  191. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
  192. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
  193. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
  194. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
  195. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
  196. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
  197. package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
  198. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  199. package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
  200. package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
  201. package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
  202. package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
  203. package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
  204. package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
  205. package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
  206. package/dist/core/ingestion/taint/call-summary-model.js +25 -0
  207. package/dist/core/ingestion/taint/emit.d.ts +125 -0
  208. package/dist/core/ingestion/taint/emit.js +208 -0
  209. package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
  210. package/dist/core/ingestion/taint/interproc-emit.js +88 -0
  211. package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
  212. package/dist/core/ingestion/taint/interproc-solver.js +312 -0
  213. package/dist/core/ingestion/taint/match.d.ts +153 -0
  214. package/dist/core/ingestion/taint/match.js +278 -0
  215. package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
  216. package/dist/core/ingestion/taint/path-codec.js +190 -0
  217. package/dist/core/ingestion/taint/propagate.d.ts +216 -0
  218. package/dist/core/ingestion/taint/propagate.js +659 -0
  219. package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
  220. package/dist/core/ingestion/taint/site-safety.js +98 -0
  221. package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
  222. package/dist/core/ingestion/taint/source-sink-config.js +35 -12
  223. package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
  224. package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
  225. package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
  226. package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
  227. package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
  228. package/dist/core/ingestion/taint/summary-harvest.js +537 -0
  229. package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
  230. package/dist/core/ingestion/taint/summary-model.js +86 -0
  231. package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
  232. package/dist/core/ingestion/taint/typescript-model.js +102 -0
  233. package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
  234. package/dist/core/ingestion/utils/env.d.ts +7 -0
  235. package/dist/core/ingestion/utils/env.js +12 -0
  236. package/dist/core/ingestion/utils/method-props.js +1 -0
  237. package/dist/core/ingestion/workers/parse-worker.d.ts +13 -0
  238. package/dist/core/ingestion/workers/parse-worker.js +76 -17
  239. package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
  240. package/dist/core/ingestion/workers/worker-pool.js +15 -2
  241. package/dist/core/lbug/csv-generator.d.ts +51 -3
  242. package/dist/core/lbug/csv-generator.js +369 -255
  243. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  244. package/dist/core/lbug/lbug-adapter.js +346 -84
  245. package/dist/core/lbug/lbug-config.d.ts +19 -0
  246. package/dist/core/lbug/lbug-config.js +29 -0
  247. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  248. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  249. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  250. package/dist/core/lbug/pool-adapter.js +90 -1
  251. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  252. package/dist/core/lbug/rel-pair-routing.js +140 -0
  253. package/dist/core/lbug/schema.d.ts +2 -2
  254. package/dist/core/lbug/schema.js +3 -0
  255. package/dist/core/logger.d.ts +0 -5
  256. package/dist/core/run-analyze.d.ts +96 -0
  257. package/dist/core/run-analyze.js +207 -3
  258. package/dist/core/tree-sitter/parser-loader.js +5 -4
  259. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  260. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  261. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  262. package/dist/core/wiki/generator.js +3 -1
  263. package/dist/core/wiki/graph-queries.d.ts +6 -0
  264. package/dist/core/wiki/graph-queries.js +9 -1
  265. package/dist/mcp/http-transport.d.ts +134 -0
  266. package/dist/mcp/http-transport.js +503 -0
  267. package/dist/mcp/local/local-backend.d.ts +110 -24
  268. package/dist/mcp/local/local-backend.js +1225 -19
  269. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  270. package/dist/mcp/local/pdg-impact.js +1972 -0
  271. package/dist/mcp/resources.js +13 -1
  272. package/dist/mcp/tools.d.ts +12 -0
  273. package/dist/mcp/tools.js +214 -7
  274. package/dist/server/analyze-launch.d.ts +29 -0
  275. package/dist/server/analyze-launch.js +137 -0
  276. package/dist/server/analyze-upload.d.ts +33 -0
  277. package/dist/server/analyze-upload.js +123 -0
  278. package/dist/server/analyze-worker.d.ts +17 -1
  279. package/dist/server/api.d.ts +17 -0
  280. package/dist/server/api.js +132 -168
  281. package/dist/server/git-clone.d.ts +43 -2
  282. package/dist/server/git-clone.js +211 -16
  283. package/dist/server/mcp-http.d.ts +5 -6
  284. package/dist/server/mcp-http.js +9 -82
  285. package/dist/server/middleware.d.ts +40 -0
  286. package/dist/server/middleware.js +92 -0
  287. package/dist/server/private-ip.d.ts +1 -0
  288. package/dist/server/private-ip.js +15 -0
  289. package/dist/server/upload-ingest.d.ts +56 -0
  290. package/dist/server/upload-ingest.js +276 -0
  291. package/dist/server/upload-paths.d.ts +37 -0
  292. package/dist/server/upload-paths.js +57 -0
  293. package/dist/server/upload-sweep.d.ts +20 -0
  294. package/dist/server/upload-sweep.js +57 -0
  295. package/dist/storage/git.js +5 -8
  296. package/dist/storage/parse-cache.d.ts +22 -1
  297. package/dist/storage/parse-cache.js +41 -10
  298. package/dist/storage/repo-manager.d.ts +121 -10
  299. package/dist/storage/repo-manager.js +43 -5
  300. package/dist/types/pipeline.d.ts +9 -0
  301. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  302. package/hooks/claude/gitnexus-hook.cjs +110 -13
  303. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  304. package/package.json +8 -2
  305. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  306. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  307. package/scripts/cross-platform-tests.ts +1 -0
  308. package/skills/gitnexus-debugging.md +16 -4
  309. package/skills/gitnexus-exploring.md +3 -3
  310. package/skills/gitnexus-guide.md +33 -0
  311. package/skills/gitnexus-pdg-query.md +89 -0
  312. package/skills/gitnexus-refactoring.md +1 -1
  313. package/skills/gitnexus-taint-analysis.md +178 -0
  314. package/vendor/tree-sitter-c/package.json +1 -1
  315. package/vendor/tree-sitter-dart/package.json +1 -1
  316. package/vendor/tree-sitter-kotlin/package.json +1 -1
  317. package/vendor/tree-sitter-proto/package.json +1 -1
  318. package/vendor/tree-sitter-swift/package.json +1 -1
  319. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  320. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  321. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  322. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  323. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  324. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  325. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  326. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  327. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  328. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  329. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  330. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  331. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  332. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  333. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  334. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  335. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  336. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  337. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  338. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  339. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  340. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  341. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  342. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  343. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  344. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  345. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  346. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  347. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  348. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  349. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  350. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  351. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  352. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  353. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  354. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  355. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  356. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  357. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  358. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  359. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  360. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  361. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  362. package/web/assets/index-BvYev1UJ.js +635 -0
  363. package/web/assets/index-_lgn7hs5.css +2 -0
  364. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  365. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  366. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  367. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  368. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  369. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  370. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  371. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  372. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  373. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  374. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  375. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  376. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  377. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  378. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  379. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  380. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  381. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  382. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  383. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  384. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  385. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  386. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  387. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  388. package/web/index.html +13 -15
  389. package/scripts/materialize-vendor-grammars.cjs +0 -97
  390. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  391. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  392. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  393. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  394. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  395. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  396. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  397. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  398. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  399. package/web/assets/chunk-CilyBKbf.js +0 -1
  400. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  401. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  402. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  403. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  404. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  405. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  406. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  407. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  408. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  409. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  410. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  411. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  412. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  413. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  414. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  415. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  416. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  417. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  418. package/web/assets/index-BKWA-m7o.css +0 -2
  419. package/web/assets/index-CG6q8eTs.js +0 -626
  420. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  421. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  422. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  423. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  424. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  425. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  426. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  427. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  428. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  429. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  430. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -234,7 +234,7 @@ async function getReposResource(backend) {
234
234
  if (repos.length > 1) {
235
235
  lines.push('');
236
236
  lines.push('# Multiple repos indexed. Use repo parameter in tool calls:');
237
- lines.push(`# query({query: "auth", repo: "${repos[0].name}"})`);
237
+ lines.push(`# query({search_query: "auth", repo: "${repos[0].name}"})`);
238
238
  }
239
239
  return lines.join('\n');
240
240
  }
@@ -270,6 +270,7 @@ async function getContextResource(backend, repoName) {
270
270
  lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
271
271
  lines.push(' - context: 360-degree symbol view (categorized refs, process participation)');
272
272
  lines.push(' - impact: Blast radius analysis (what breaks if you change a symbol)');
273
+ lines.push(' - explain: Persisted taint findings — source→sink data flows with per-hop variables (requires analyze --pdg)');
273
274
  lines.push(' - detect_changes: Git-diff impact analysis (what do your changes affect)');
274
275
  lines.push(' - rename: Multi-file coordinated rename with confidence tags');
275
276
  lines.push(' - cypher: Raw graph queries');
@@ -386,6 +387,12 @@ relationships:
386
387
  - MEMBER_OF: Symbol belongs to community
387
388
  - STEP_IN_PROCESS: Symbol is step N in process
388
389
 
390
+ pdg_layers: "Recorded ONLY when indexed with 'gitnexus analyze --pdg'. Intra-procedural, basic-block granular; both endpoints are BasicBlock nodes. Prefer the pdg_query tool over raw Cypher."
391
+ - BasicBlock: "Basic-block node. Columns: id, filePath, startLine, endLine, text. id = 'BasicBlock:<filePath>:<fnStartLine>:<fnStartCol>:<blockIndex>'."
392
+ - CFG: "Control-flow edge BasicBlock->BasicBlock. Edge kind (seq/cond-true/cond-false/loop-back/...) is in reason."
393
+ - CDG: "Control-DEPENDENCE edge BasicBlock->BasicBlock — the source predicate gates the target's execution. Branch sense 'T'|'F' in reason. Query via pdg_query mode:'controls'."
394
+ - REACHING_DEF: "Data-dependence (def->use) edge BasicBlock->BasicBlock. Source-level variable name is in reason. Query via pdg_query mode:'flows'."
395
+
389
396
  relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
390
397
 
391
398
  example_queries:
@@ -403,6 +410,11 @@ example_queries:
403
410
  WHERE p.heuristicLabel = "LoginFlow"
404
411
  RETURN s.name, r.step
405
412
  ORDER BY r.step
413
+
414
+ guard_clauses (--pdg only; prefer pdg_query mode:'controls'): |
415
+ MATCH (pred:BasicBlock)-[r:CodeRelation {type: 'CDG'}]->(dep:BasicBlock)
416
+ WHERE dep.text STARTS WITH 'return' OR dep.text STARTS WITH 'throw'
417
+ RETURN pred.startLine, r.reason AS branch, dep.startLine, dep.text
406
418
  `;
407
419
  }
408
420
  /**
@@ -36,4 +36,16 @@ export interface ToolDefinition {
36
36
  */
37
37
  export declare const LIST_REPOS_DEFAULT_LIMIT = 50;
38
38
  export declare const LIST_REPOS_MAX_LIMIT = 200;
39
+ /**
40
+ * Pagination bounds for the `explain` tool (#2083 M3 U6). Findings are sparse
41
+ * and capped per function at analyze time, but a large repo can still
42
+ * accumulate enough TAINTED rows to blow MCP/LLM token limits — the response
43
+ * is page-bounded like `list_repos`. Exported so the backend clamp
44
+ * (`local-backend.ts`) and the schema stay a single source of truth.
45
+ */
46
+ export declare const EXPLAIN_DEFAULT_LIMIT = 50;
47
+ export declare const EXPLAIN_MAX_LIMIT = 200;
48
+ export declare const PDG_QUERY_DEFAULT_LIMIT = 50;
49
+ export declare const PDG_QUERY_MAX_LIMIT = 200;
50
+ export declare const IMPACT_MAX_DEPTH = 32;
39
51
  export declare const GITNEXUS_TOOLS: ToolDefinition[];
package/dist/mcp/tools.js CHANGED
@@ -32,6 +32,22 @@ const DESTRUCTIVE_TOOL_ANNOTATIONS = {
32
32
  */
33
33
  export const LIST_REPOS_DEFAULT_LIMIT = 50;
34
34
  export const LIST_REPOS_MAX_LIMIT = 200;
35
+ /**
36
+ * Pagination bounds for the `explain` tool (#2083 M3 U6). Findings are sparse
37
+ * and capped per function at analyze time, but a large repo can still
38
+ * accumulate enough TAINTED rows to blow MCP/LLM token limits — the response
39
+ * is page-bounded like `list_repos`. Exported so the backend clamp
40
+ * (`local-backend.ts`) and the schema stay a single source of truth.
41
+ */
42
+ export const EXPLAIN_DEFAULT_LIMIT = 50;
43
+ export const EXPLAIN_MAX_LIMIT = 200;
44
+ // pdg_query result-page bounds (#2086 M6). Mirror the EXPLAIN_* limits — the
45
+ // no-rel-index path means every page must be anchored + LIMIT-bounded.
46
+ export const PDG_QUERY_DEFAULT_LIMIT = 50;
47
+ export const PDG_QUERY_MAX_LIMIT = 200;
48
+ // Shared impact traversal depth cap. The MCP schema advertises this bound;
49
+ // PDG direct backend callers also enforce it before running traversal.
50
+ export const IMPACT_MAX_DEPTH = 32;
35
51
  export const GITNEXUS_TOOLS = [
36
52
  {
37
53
  name: 'list_repos',
@@ -89,7 +105,14 @@ SERVICE: optional monorepo path prefix (POSIX-style, case-sensitive segments). W
89
105
  inputSchema: {
90
106
  type: 'object',
91
107
  properties: {
92
- query: { type: 'string', description: 'Natural language or keyword search query' },
108
+ // #2175: the legacy `query` key is still accepted by the handler
109
+ // (resolveAliasString in local-backend.ts), but is deliberately NOT named in the
110
+ // advertised property or its description — surfacing "query" in the schema an LLM
111
+ // reads would nudge it to send `query`, the exact argument Claude Code drops.
112
+ search_query: {
113
+ type: 'string',
114
+ description: 'Natural language or keyword search query.',
115
+ },
93
116
  task_context: {
94
117
  type: 'string',
95
118
  description: 'What you are working on (e.g., "adding OAuth support"). Helps ranking.',
@@ -127,7 +150,7 @@ SERVICE: optional monorepo path prefix (POSIX-style, case-sensitive segments). W
127
150
  description: 'Optional monorepo service root (relative path, "/" separators). In group mode (@repo), prefix-matches symbol file paths; ignored for a normal repo name. Empty string is rejected server-side.',
128
151
  },
129
152
  },
130
- required: ['query'],
153
+ required: ['search_query'],
131
154
  },
132
155
  },
133
156
  {
@@ -175,12 +198,20 @@ TIPS:
175
198
  - All relationships use single CodeRelation table — filter with {type: 'CALLS'} etc.
176
199
  - Community = auto-detected functional area (Leiden algorithm). Properties: heuristicLabel, cohesion, symbolCount, keywords, description, enrichedBy
177
200
  - Process = execution flow trace from entry point to terminal. Properties: heuristicLabel, processType, stepCount, communities, entryPointId, terminalId
178
- - Use heuristicLabel (not label) for human-readable community/process names`,
201
+ - Use heuristicLabel (not label) for human-readable community/process names
202
+ - PDG layers (only when indexed with \`--pdg\`): BasicBlock nodes + CFG / CDG (control dependence, branch sense 'T'|'F' in reason) / REACHING_DEF (def→use, variable in reason) edges, all BasicBlock→BasicBlock. Prefer the \`pdg_query\` tool — it anchors + bounds these for you (raw \`[:CDG*]\`/\`[:REACHING_DEF*]\` path scans are unindexed and unbounded).`,
179
203
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
180
204
  inputSchema: {
181
205
  type: 'object',
182
206
  properties: {
183
- query: { type: 'string', description: 'Cypher query to execute' },
207
+ // #2175: the legacy `query` key is still accepted by the handler
208
+ // (resolveAliasString in local-backend.ts), but is deliberately NOT named in the
209
+ // advertised property or its description — surfacing "query" in the schema an LLM
210
+ // reads would nudge it to send `query`, the exact argument Claude Code drops.
211
+ statement: {
212
+ type: 'string',
213
+ description: 'Cypher statement to execute.',
214
+ },
184
215
  params: {
185
216
  type: 'object',
186
217
  description: 'Optional query parameters for placeholders (e.g. $name) to execute via prepared statement binding.',
@@ -190,7 +221,7 @@ TIPS:
190
221
  description: 'Repository name or path. Omit if only one repo is indexed.',
191
222
  },
192
223
  },
193
- required: ['query'],
224
+ required: ['statement'],
194
225
  },
195
226
  },
196
227
  {
@@ -277,6 +308,29 @@ Returns: changed symbols, affected processes, and a risk summary.`,
277
308
  required: [],
278
309
  },
279
310
  },
311
+ {
312
+ name: 'check',
313
+ description: `Run read-only structural checks against the indexed graph.
314
+
315
+ Currently detects directed cycles between File nodes connected by IMPORTS edges.
316
+ Returns deterministic cycle paths and a cycle count suitable for CI automation.`,
317
+ annotations: READ_ONLY_TOOL_ANNOTATIONS,
318
+ inputSchema: {
319
+ type: 'object',
320
+ properties: {
321
+ cycles: {
322
+ type: 'boolean',
323
+ description: 'Detect circular file imports (default: true).',
324
+ default: true,
325
+ },
326
+ repo: {
327
+ type: 'string',
328
+ description: 'Repository name or path. Omit if only one repo is indexed.',
329
+ },
330
+ },
331
+ required: [],
332
+ },
333
+ },
280
334
  {
281
335
  name: 'rename',
282
336
  description: `Multi-file coordinated rename using the knowledge graph + text search.
@@ -317,11 +371,17 @@ Each edit is tagged with confidence:
317
371
  description: `Analyze the blast radius of changing a code symbol.
318
372
  Returns affected symbols grouped by depth, plus risk assessment, affected execution flows, and affected modules.
319
373
 
374
+ MODE (opt-in): "callgraph" (default) walks symbol→symbol edges (CALLS/IMPORTS/EXTENDS/IMPLEMENTS) — inter-procedural, the established comparator/default behavior. "pdg" requires an index built with \`gitnexus analyze --pdg\` and returns one unified PDG-facing result: statement-level control/data dependence from the persisted PDG plus inter-procedural symbol reach. The explicit interprocedural surface is interproceduralByDepth/pdgInterprocedural; byDepth remains the compatibility symbol bucket. pdg remains incompatible with crossDepth and @group targets; relationTypes/minConfidence filter the inter-symbol reach.
375
+
376
+ STATEMENT-ANCHORED PDG SLICE: with mode:'pdg', pass "line" (1-based source line within the target symbol) to seed the dependence slice on the statement at that line and return what depends on it in affectedStatements (line + text). Inter-procedural symbols are still reported through interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket. Without "line", pdg returns whole-symbol inter-procedural reach plus local whole-symbol PDG diagnostics.
377
+
378
+ PDG OUTPUT CONTRACT: every mode:'pdg' result (success, empty, degraded, or error) carries pdgResultVersion:1 — a stable discriminator for external consumers that bumps on any breaking change to the PDG result shape (distinct from the DB schema version). Successful PDG results include mode:'pdg', a full target envelope (id/name/type/filePath), affectedStatements, affectedStatementCount, interproceduralByDepth/pdgInterprocedural for cross-function reach, compatibility byDepth/byDepthCounts, risk:'UNKNOWN', and a note describing the unified contract. Degraded PDG results (no-layer, sub-layer-missing, unknown) keep mode:'pdg', pdgResultVersion:1, target metadata when the target resolves, risk:'UNKNOWN', note/remediation, and empty byDepth parity fields — never a false-safe zero. If depth and limit both bound the slice, truncatedByReasons reports both causes while truncatedBy remains scalar.
379
+
320
380
  WHEN TO USE: Before making code changes — especially refactoring, renaming, or modifying shared code. Shows what would break.
321
381
  AFTER THIS: Review d=1 items (WILL BREAK). Use context() on high-risk symbols.
322
382
 
323
383
  Output includes:
324
- - risk: LOW / MEDIUM / HIGH / CRITICAL
384
+ - risk: LOW / MEDIUM / HIGH / CRITICAL / UNKNOWN
325
385
  - summary: direct callers, processes affected, modules affected
326
386
  - affected_processes: which execution flows break and at which step
327
387
  - affected_modules: which functional areas are hit (direct vs indirect)
@@ -357,6 +417,17 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
357
417
  type: 'string',
358
418
  description: 'upstream (what depends on this) or downstream (what this depends on)',
359
419
  },
420
+ mode: {
421
+ type: 'string',
422
+ enum: ['callgraph', 'pdg'],
423
+ default: 'callgraph',
424
+ description: "Blast-radius engine. 'callgraph' (default) = inter-procedural symbol→symbol traversal (established comparator). 'pdg' = unified PDG-facing impact: intra-procedural statement-level affectedStatements from the persisted control/data dependence layer plus inter-procedural symbols in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket; requires `gitnexus analyze --pdg`. PDG symbol reach is labeled as a PDG evidence bridge, not pure statement-level dependence, and successful PDG results are UNKNOWN-risk. PDG is incompatible with crossDepth and @group targets; relationTypes/minConfidence filter the inter-symbol reach.",
425
+ },
426
+ line: {
427
+ type: 'integer',
428
+ minimum: 1,
429
+ description: "1-based source line — PDG statement anchor (mode:'pdg'). Seeds affectedStatements on the statement at this line; inter-procedural symbols are still returned in interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket.",
430
+ },
360
431
  file_path: {
361
432
  type: 'string',
362
433
  description: 'File path hint to disambiguate common names',
@@ -370,7 +441,7 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
370
441
  description: 'Max relationship depth (default: 3, server clamps to 1–32)',
371
442
  default: 3,
372
443
  minimum: 1,
373
- maximum: 32,
444
+ maximum: IMPACT_MAX_DEPTH,
374
445
  },
375
446
  crossDepth: {
376
447
  type: 'number',
@@ -439,6 +510,99 @@ SERVICE: optional monorepo path prefix (case-sensitive path segments). When "rep
439
510
  required: ['target', 'direction'],
440
511
  },
441
512
  },
513
+ {
514
+ name: 'explain',
515
+ description: `Explain persisted taint findings recorded by \`gitnexus analyze --pdg\`: intra-procedural source→sink data flows (TAINTED edges, statement-level hops) AND cross-function flows (TAINT_PATH edges, function-level hops, marked \`interprocedural: true\`).
516
+
517
+ Each finding carries the sink category (command-injection, code-injection, path-traversal, sql-injection, xss) and the ordered hop path. Intra-procedural findings carry source/sink lines and the variable on each hop; interprocedural findings carry the source and sink FUNCTION names and the chain of functions the taint crossed (decoded from the persisted path encoding).
518
+
519
+ WHEN TO USE: Security review — "what taint findings exist in this repo / file / function?". Requires the repo to be indexed with \`gitnexus analyze --pdg\`; without that layer the tool returns a clear "no taint layer" note, not an error.
520
+
521
+ ANCHORLESS (no "target"): enumerates all persisted findings for the repo — bounded ("limit", deterministic order), with "totalFindings" and a "truncated" flag.
522
+ ANCHORED ("target" = file path or symbol/function name): full hop detail for that anchor. A file-ish target (contains "/" or an extension) filters by file; a symbol name resolves like context() — ambiguous names return ranked candidates, unknown names return not-found. Symbol anchoring is line-range granular for intra-procedural findings; cross-function findings match when the symbol is the source OR sink function.
523
+
524
+ CONTRACT CAVEATS (absent flows are NOT proof of safety):
525
+ - Cross-function flows ARE modeled (#2084 M4): a source flowing through helper functions into a sink is found, via summary composition over the call graph (context-insensitive — return/call-site merging is accepted).
526
+ - Cross-function matching is by callee NAME (context-insensitive): when one caller invokes two distinct same-named callees, a flow into one over-attributes to both — a cross-function finding does not prove the taint reached every same-named function (sound over-report, never a missed flow).
527
+ - Closure/callback flows are invisible in both directions (e.g. arr.forEach(() => sink(y))) — the largest false-negative class.
528
+ - Property/field flows are not tracked (obj.x = taint; sink(obj.y) has no chain).
529
+ - Guard-style sanitizers (if (isValid(x))) and implicit/control-dependence flows are not modeled.
530
+ - CommonJS aliasing is partially modeled (require('<literal>') joins resolve; dynamic requires do not).
531
+ - Exception-path over-approximation can produce false-positive noise.
532
+
533
+ Findings are deliberately NOT part of impact()'s traversal or the web schema — explain is the dedicated taint consumer. SANITIZES (kill) edges are queryable via cypher.`,
534
+ annotations: READ_ONLY_TOOL_ANNOTATIONS,
535
+ inputSchema: {
536
+ type: 'object',
537
+ properties: {
538
+ target: {
539
+ type: 'string',
540
+ description: 'Optional anchor: a file path (e.g. "src/handlers/run.ts" — suffix match accepted) or a symbol/function name (resolved like context()). Omit to enumerate all findings for the repo.',
541
+ },
542
+ limit: {
543
+ type: 'integer',
544
+ description: `Max findings returned (default: ${EXPLAIN_DEFAULT_LIMIT}, max: ${EXPLAIN_MAX_LIMIT}). "totalFindings" reports the full matched count; "truncated" is set when the page is smaller.`,
545
+ default: EXPLAIN_DEFAULT_LIMIT,
546
+ minimum: 1,
547
+ maximum: EXPLAIN_MAX_LIMIT,
548
+ },
549
+ repo: {
550
+ type: 'string',
551
+ description: 'Repository name or path. Omit if only one repo is indexed.',
552
+ },
553
+ },
554
+ required: [],
555
+ },
556
+ },
557
+ {
558
+ name: 'pdg_query',
559
+ description: `Query the persisted Program Dependence Graph recorded by \`gitnexus analyze --pdg\` — control dependence (CDG) and data dependence (REACHING_DEF) at basic-block granularity. The control/data analog of \`explain\` (which is the taint consumer).
560
+
561
+ MODES:
562
+ - \`controls\` — "under what condition does X run?". Returns, for the anchored function, each control-dependence edge: the controlling predicate block, the dependent block, and the branch sense ('T' = the predicate's true/taken arm, 'F' = its false/fall-through arm). An edge into an early return/throw block is flagged \`guard: true\` (subsumes the #559 guard heuristic); the branch sense of a guard depends on its predicate — \`if (!ok) return;\` rides the 'T' arm — so don't filter guards by a fixed label.
563
+ - \`flows\` — "where does variable Y flow?". Returns REACHING_DEF def→use edges for the anchored function; pass \`variable\` to filter to one binding.
564
+
565
+ WHEN TO USE: comprehension ("what guards this statement?"), data-flow tracing within a function, guard-clause discovery. Requires \`gitnexus analyze --pdg\`; without that layer the tool returns a clear "no PDG layer" note, not an error.
566
+
567
+ ANCHORING (required): \`target\` is a file path or a symbol/function name (resolved like context()). PDG queries are ALWAYS anchored — there is no whole-repo enumeration (an unanchored basic-block path scan is unbounded; LadybugDB has no rel-property index). A symbol target is line-range granular; an ambiguous name returns ranked candidates, unknown returns not-found.
568
+
569
+ CONTRACT CAVEATS:
570
+ - CDG labels are binary 'T'/'F' in M5/M6; per-case \`switch\` arm conditions are not yet distinguished (every case dispatch is 'T').
571
+ - Granularity is basic-block, reconstructed to the function via the BasicBlock id + line span (no Function→BasicBlock edge); deeply same-line-packed functions may anchor coarsely.
572
+ - Control/data dependence is intra-procedural (per function). Cross-function flow is taint's domain (\`explain\`).
573
+ - These edges are deliberately NOT part of impact()'s traversal — \`pdg_query\` is the dedicated consumer; raw edges are also queryable via \`cypher\`.`,
574
+ annotations: READ_ONLY_TOOL_ANNOTATIONS,
575
+ inputSchema: {
576
+ type: 'object',
577
+ properties: {
578
+ mode: {
579
+ type: 'string',
580
+ enum: ['controls', 'flows'],
581
+ description: "'controls' = control dependence (CDG: what condition gates X); 'flows' = data dependence (REACHING_DEF: where variable Y flows).",
582
+ },
583
+ target: {
584
+ type: 'string',
585
+ description: 'Required anchor: a file path (e.g. "src/handlers/run.ts" — suffix match accepted) or a symbol/function name (resolved like context()).',
586
+ },
587
+ variable: {
588
+ type: 'string',
589
+ description: 'Optional (flows mode only): restrict REACHING_DEF results to this source-level variable name.',
590
+ },
591
+ limit: {
592
+ type: 'integer',
593
+ description: `Max edges returned (default: ${PDG_QUERY_DEFAULT_LIMIT}, max: ${PDG_QUERY_MAX_LIMIT}). "total" reports the full matched count; "truncated" is set when the page is smaller.`,
594
+ default: PDG_QUERY_DEFAULT_LIMIT,
595
+ minimum: 1,
596
+ maximum: PDG_QUERY_MAX_LIMIT,
597
+ },
598
+ repo: {
599
+ type: 'string',
600
+ description: 'Repository name or path. Omit if only one repo is indexed.',
601
+ },
602
+ },
603
+ required: ['mode', 'target'],
604
+ },
605
+ },
442
606
  {
443
607
  name: 'route_map',
444
608
  description: `Show API route mappings: which components/hooks fetch which API endpoints, and which handler files serve them.
@@ -559,6 +723,45 @@ WHEN TO USE: After changing group.yaml or re-indexing member repos.`,
559
723
  required: ['name'],
560
724
  },
561
725
  },
726
+ {
727
+ name: 'trace',
728
+ description: `Find the shortest directed path between two symbols over call and class-member edges.
729
+
730
+ WHEN TO USE: Debugging "how does A reach B?" — answers in one call what would take 3-8 manual context/impact hops. Shows the exact chain with file:line positions plus a per-hop edge type and confidence.
731
+
732
+ Traverses CALLS edges plus HAS_METHOD (class → member) edges, so a trace can descend from a class into its methods. Each hop's edge type is reported in edges[], so call hops and containment hops remain distinguishable.
733
+
734
+ Returns: ordered hops with file:line, and an aligned edges[] of edge type + confidence. When no path exists, reports the furthest reachable node so you know where the chain breaks (and truncated: true if a traversal cap was hit first).`,
735
+ annotations: READ_ONLY_TOOL_ANNOTATIONS,
736
+ inputSchema: {
737
+ type: 'object',
738
+ properties: {
739
+ from: { type: 'string', description: 'Source symbol name' },
740
+ from_uid: { type: 'string', description: 'Source symbol UID (zero-ambiguity)' },
741
+ from_file: { type: 'string', description: 'Source file path hint for disambiguation' },
742
+ to: { type: 'string', description: 'Target symbol name' },
743
+ to_uid: { type: 'string', description: 'Target symbol UID (zero-ambiguity)' },
744
+ to_file: { type: 'string', description: 'Target file path hint for disambiguation' },
745
+ maxDepth: {
746
+ type: 'number',
747
+ description: 'Maximum path length in hops (default: 10)',
748
+ default: 10,
749
+ minimum: 1,
750
+ maximum: 30,
751
+ },
752
+ includeTests: {
753
+ type: 'boolean',
754
+ description: 'Include test-file symbols in traversal (default: false)',
755
+ default: false,
756
+ },
757
+ repo: {
758
+ type: 'string',
759
+ description: 'Repository name or path. Omit if only one repo is indexed.',
760
+ },
761
+ },
762
+ required: [],
763
+ },
764
+ },
562
765
  ];
563
766
  /**
564
767
  * Per-repo tools that accept an optional `branch` scope (#2106). Single source
@@ -572,12 +775,16 @@ const BRANCH_SCOPED_TOOLS = new Set([
572
775
  'cypher',
573
776
  'context',
574
777
  'detect_changes',
778
+ 'explain',
779
+ 'pdg_query',
780
+ 'check',
575
781
  'impact',
576
782
  'rename',
577
783
  'route_map',
578
784
  'tool_map',
579
785
  'shape_check',
580
786
  'api_impact',
787
+ 'trace',
581
788
  ]);
582
789
  for (const tool of GITNEXUS_TOOLS) {
583
790
  if (!BRANCH_SCOPED_TOOLS.has(tool.name))
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared analyze-worker launcher.
3
+ *
4
+ * Forks the analyze worker for an already-resolved repo directory and owns the
5
+ * lock + auto-retry + IPC machinery. Used by both the JSON `/api/analyze` route
6
+ * and the multipart `/api/analyze/upload` route. Dependency-injected (like
7
+ * createAnalyzeUploadHandler) so the seam is testable and api.ts stays smaller.
8
+ *
9
+ * NOTE: this module must live alongside analyze-worker.{ts,js} — the worker
10
+ * path is resolved relative to `import.meta.url`.
11
+ */
12
+ import type { JobManager } from './analyze-job.js';
13
+ export interface LaunchDeps {
14
+ jobManager: JobManager;
15
+ backend: {
16
+ init: () => Promise<unknown>;
17
+ };
18
+ acquireRepoLock: (key: string) => string | null;
19
+ releaseRepoLock: (key: string) => void;
20
+ }
21
+ export interface LaunchOptions {
22
+ force?: boolean;
23
+ embeddings?: boolean;
24
+ dropEmbeddings?: boolean;
25
+ registryName?: string;
26
+ }
27
+ export declare function createLaunchAnalysisWorker(deps: LaunchDeps): (job: {
28
+ id: string;
29
+ }, targetPath: string, opts: LaunchOptions) => void;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Shared analyze-worker launcher.
3
+ *
4
+ * Forks the analyze worker for an already-resolved repo directory and owns the
5
+ * lock + auto-retry + IPC machinery. Used by both the JSON `/api/analyze` route
6
+ * and the multipart `/api/analyze/upload` route. Dependency-injected (like
7
+ * createAnalyzeUploadHandler) so the seam is testable and api.ts stays smaller.
8
+ *
9
+ * NOTE: this module must live alongside analyze-worker.{ts,js} — the worker
10
+ * path is resolved relative to `import.meta.url`.
11
+ */
12
+ import path from 'path';
13
+ import { fork } from 'child_process';
14
+ import { fileURLToPath, pathToFileURL } from 'url';
15
+ import { createRequire } from 'node:module';
16
+ import { getStoragePath } from '../storage/repo-manager.js';
17
+ import { logger } from '../core/logger.js';
18
+ const _require = createRequire(import.meta.url);
19
+ const MAX_WORKER_RETRIES = 2;
20
+ export function createLaunchAnalysisWorker(deps) {
21
+ const { jobManager, backend, acquireRepoLock, releaseRepoLock } = deps;
22
+ return function launchAnalysisWorker(job, targetPath, opts) {
23
+ // Acquire shared repo lock (keyed on storagePath to match embed handler)
24
+ const analyzeLockKey = getStoragePath(targetPath);
25
+ const lockErr = acquireRepoLock(analyzeLockKey);
26
+ if (lockErr) {
27
+ jobManager.updateJob(job.id, { status: 'failed', error: lockErr });
28
+ return;
29
+ }
30
+ jobManager.updateJob(job.id, { repoPath: targetPath, status: 'analyzing' });
31
+ // ── Worker fork with auto-retry ──────────────────────────────
32
+ const callerPath = fileURLToPath(import.meta.url);
33
+ const isDev = callerPath.endsWith('.ts');
34
+ const workerFile = isDev ? 'analyze-worker.ts' : 'analyze-worker.js';
35
+ const workerPath = path.join(path.dirname(callerPath), workerFile);
36
+ const tsxHookArgs = isDev
37
+ ? ['--import', pathToFileURL(_require.resolve('tsx/esm')).href]
38
+ : [];
39
+ const forkWorker = () => {
40
+ const currentJob = jobManager.getJob(job.id);
41
+ if (!currentJob || currentJob.status === 'complete' || currentJob.status === 'failed')
42
+ return;
43
+ const child = fork(workerPath, [], {
44
+ execArgv: [...tsxHookArgs, '--max-old-space-size=8192'],
45
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
46
+ });
47
+ // Capture stderr for crash diagnostics
48
+ let stderrChunks = '';
49
+ child.stderr?.on('data', (chunk) => {
50
+ stderrChunks += chunk.toString();
51
+ if (stderrChunks.length > 4096)
52
+ stderrChunks = stderrChunks.slice(-4096);
53
+ });
54
+ child.on('message', (msg) => {
55
+ if (msg.type === 'progress') {
56
+ jobManager.updateJob(job.id, {
57
+ status: 'analyzing',
58
+ progress: { phase: msg.phase, percent: msg.percent, message: msg.message },
59
+ });
60
+ }
61
+ else if (msg.type === 'complete') {
62
+ releaseRepoLock(analyzeLockKey);
63
+ // Reinitialize backend BEFORE marking complete — ensures the new repo
64
+ // is queryable when the client receives the SSE complete event.
65
+ backend
66
+ .init()
67
+ .then(() => {
68
+ jobManager.updateJob(job.id, { status: 'complete', repoName: msg.result.repoName });
69
+ })
70
+ .catch((err) => {
71
+ logger.error({ err }, 'backend.init() failed after analyze:');
72
+ jobManager.updateJob(job.id, {
73
+ status: 'failed',
74
+ error: 'Server failed to reload after analysis. Try again.',
75
+ });
76
+ });
77
+ }
78
+ else if (msg.type === 'error') {
79
+ releaseRepoLock(analyzeLockKey);
80
+ jobManager.updateJob(job.id, { status: 'failed', error: msg.message });
81
+ }
82
+ });
83
+ child.on('error', (err) => {
84
+ releaseRepoLock(analyzeLockKey);
85
+ jobManager.updateJob(job.id, {
86
+ status: 'failed',
87
+ error: `Worker process error: ${err.message}`,
88
+ });
89
+ });
90
+ child.on('exit', (code) => {
91
+ const j = jobManager.getJob(job.id);
92
+ if (!j || j.status === 'complete' || j.status === 'failed')
93
+ return;
94
+ // Worker crashed — attempt retry if under the limit
95
+ if (j.retryCount < MAX_WORKER_RETRIES) {
96
+ j.retryCount++;
97
+ const delay = 1000 * Math.pow(2, j.retryCount - 1); // 1s, 2s
98
+ const lastErr = stderrChunks.trim().split('\n').pop() || '';
99
+ logger.warn(`Analyze worker crashed (code ${code}), retry ${j.retryCount}/${MAX_WORKER_RETRIES} in ${delay}ms` +
100
+ (lastErr ? `: ${lastErr}` : ''));
101
+ jobManager.updateJob(job.id, {
102
+ status: 'analyzing',
103
+ progress: {
104
+ phase: 'retrying',
105
+ percent: j.progress.percent,
106
+ message: `Worker crashed, retrying (${j.retryCount}/${MAX_WORKER_RETRIES})...`,
107
+ },
108
+ });
109
+ stderrChunks = '';
110
+ setTimeout(forkWorker, delay);
111
+ }
112
+ else {
113
+ // Exhausted retries — permanent failure
114
+ releaseRepoLock(analyzeLockKey);
115
+ jobManager.updateJob(job.id, {
116
+ status: 'failed',
117
+ error: `Worker crashed ${MAX_WORKER_RETRIES + 1} times (code ${code})${stderrChunks ? ': ' + stderrChunks.trim().split('\n').pop() : ''}`,
118
+ });
119
+ }
120
+ });
121
+ // Register child for cancellation + timeout tracking
122
+ jobManager.registerChild(job.id, child);
123
+ // Send start command to child
124
+ child.send({
125
+ type: 'start',
126
+ repoPath: targetPath,
127
+ options: {
128
+ force: !!opts.force,
129
+ embeddings: !!opts.embeddings,
130
+ dropEmbeddings: !!opts.dropEmbeddings,
131
+ ...(opts.registryName ? { registryName: opts.registryName } : {}),
132
+ },
133
+ });
134
+ };
135
+ forkWorker();
136
+ };
137
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * POST /api/analyze/upload — analyze a browser folder upload.
3
+ *
4
+ * Securely ingests the multipart upload into a sandbox (upload-ingest.ts),
5
+ * promotes it to a persistent app-controlled directory, and analyzes it via
6
+ * the same job/worker machinery as a git clone — never returning a server
7
+ * path to the client. Factored as a dependency-injected handler so the job
8
+ * machinery (createJob + the worker launcher) can be mocked in unit tests.
9
+ */
10
+ import type { Request, Response } from 'express';
11
+ import { ingestUpload } from './upload-ingest.js';
12
+ import type { AnalyzeJob } from './analyze-job.js';
13
+ /** Minimal job shape the handler needs (a subset of the real AnalyzeJob). */
14
+ export type UploadJobRef = Pick<AnalyzeJob, 'id' | 'status'>;
15
+ export interface AnalyzeUploadDeps {
16
+ /** Create (or throw on busy) an analysis job for the given upload dir. */
17
+ createJob: (params: {
18
+ repoPath: string;
19
+ }) => UploadJobRef;
20
+ /** Launch the analyze worker against an already-resolved repo directory. */
21
+ launch: (job: UploadJobRef, targetPath: string, opts: {
22
+ registryName: string;
23
+ }) => void;
24
+ /**
25
+ * Mark a created job failed. The job occupies the single analysis slot from
26
+ * createJob onward, so ANY error before launch must release it — otherwise a
27
+ * leaked non-terminal job wedges all future analyses until restart.
28
+ */
29
+ failJob: (jobId: string, error: string) => void;
30
+ /** Injectable for tests (defaults to the real ingestUpload). */
31
+ ingest?: typeof ingestUpload;
32
+ }
33
+ export declare function createAnalyzeUploadHandler(deps: AnalyzeUploadDeps): (req: Request, res: Response) => Promise<void>;