gitnexus 1.6.9 → 1.6.10-aptos.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/README.md +211 -53
  2. package/dist/_shared/graph/types.d.ts +67 -3
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js.map +1 -1
  7. package/dist/_shared/integrations/resilient-fetch.d.ts +3 -1
  8. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  9. package/dist/_shared/integrations/resilient-fetch.js +4 -3
  10. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  11. package/dist/_shared/language-detection.d.ts.map +1 -1
  12. package/dist/_shared/language-detection.js +2 -0
  13. package/dist/_shared/language-detection.js.map +1 -1
  14. package/dist/_shared/languages.d.ts +2 -0
  15. package/dist/_shared/languages.d.ts.map +1 -1
  16. package/dist/_shared/languages.js +2 -0
  17. package/dist/_shared/languages.js.map +1 -1
  18. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  19. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  20. package/dist/_shared/lbug/schema-constants.js +8 -0
  21. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  22. package/dist/_shared/pipeline.d.ts +1 -1
  23. package/dist/_shared/pipeline.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/callable-flow-site.d.ts +110 -0
  25. package/dist/_shared/scope-resolution/callable-flow-site.d.ts.map +1 -0
  26. package/dist/_shared/scope-resolution/callable-flow-site.js +11 -0
  27. package/dist/_shared/scope-resolution/callable-flow-site.js.map +1 -0
  28. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +1 -1
  29. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
  30. package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -1
  31. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  32. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  33. package/dist/_shared/scope-resolution/language-classification.js +1 -0
  34. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  35. package/dist/_shared/scope-resolution/parsed-file.d.ts +7 -0
  36. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  37. package/dist/_shared/scope-resolution/reference-site.d.ts +9 -1
  38. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  39. package/dist/_shared/scope-resolution/types.d.ts +20 -3
  40. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  41. package/dist/cli/ai-context.d.ts +1 -1
  42. package/dist/cli/ai-context.js +25 -44
  43. package/dist/cli/analyze.d.ts +5 -2
  44. package/dist/cli/analyze.js +197 -11
  45. package/dist/cli/clean.js +17 -3
  46. package/dist/cli/cli-message.d.ts +1 -1
  47. package/dist/cli/doctor.d.ts +18 -0
  48. package/dist/cli/doctor.js +96 -5
  49. package/dist/cli/editor-targets.d.ts +17 -2
  50. package/dist/cli/editor-targets.js +44 -0
  51. package/dist/cli/embeddings.d.ts +12 -0
  52. package/dist/cli/embeddings.js +49 -0
  53. package/dist/cli/eval-server.d.ts +23 -1
  54. package/dist/cli/eval-server.js +126 -8
  55. package/dist/cli/help-i18n.js +6 -0
  56. package/dist/cli/i18n/en.d.ts +18 -8
  57. package/dist/cli/i18n/en.js +18 -8
  58. package/dist/cli/i18n/resources.d.ts +28 -8
  59. package/dist/cli/i18n/zh-CN.d.ts +10 -0
  60. package/dist/cli/i18n/zh-CN.js +18 -8
  61. package/dist/cli/index.js +21 -7
  62. package/dist/cli/lazy-action.d.ts +7 -0
  63. package/dist/cli/lazy-action.js +27 -0
  64. package/dist/cli/mcp.js +6 -3
  65. package/dist/cli/move-availability.d.ts +5 -0
  66. package/dist/cli/move-availability.js +11 -0
  67. package/dist/cli/setup.d.ts +8 -0
  68. package/dist/cli/setup.js +230 -32
  69. package/dist/cli/skill-gen.js +38 -18
  70. package/dist/cli/standard-skills.d.ts +76 -0
  71. package/dist/cli/standard-skills.js +45 -0
  72. package/dist/cli/status.d.ts +4 -1
  73. package/dist/cli/status.js +57 -4
  74. package/dist/cli/tool.js +11 -0
  75. package/dist/cli/uninstall.js +77 -18
  76. package/dist/cli/wiki.d.ts +1 -0
  77. package/dist/cli/wiki.js +7 -1
  78. package/dist/config/ignore-service.d.ts +2 -0
  79. package/dist/config/ignore-service.js +27 -0
  80. package/dist/core/analysis-features.d.ts +21 -0
  81. package/dist/core/analysis-features.js +59 -0
  82. package/dist/core/analyzer-identity.d.ts +74 -0
  83. package/dist/core/analyzer-identity.js +1820 -0
  84. package/dist/core/augmentation/engine.js +13 -8
  85. package/dist/core/embeddings/embedder.d.ts +3 -2
  86. package/dist/core/embeddings/embedder.js +24 -7
  87. package/dist/core/embeddings/embedding-identity.d.ts +11 -0
  88. package/dist/core/embeddings/embedding-identity.js +24 -0
  89. package/dist/core/embeddings/embedding-pipeline.d.ts +36 -1
  90. package/dist/core/embeddings/embedding-pipeline.js +100 -9
  91. package/dist/core/embeddings/http-client.d.ts +33 -3
  92. package/dist/core/embeddings/http-client.js +237 -25
  93. package/dist/core/embeddings/node-module-compat.d.ts +25 -0
  94. package/dist/core/embeddings/node-module-compat.js +25 -0
  95. package/dist/core/embeddings/onnxruntime-common-resolver.js +8 -5
  96. package/dist/core/embeddings/onnxruntime-node-resolver.js +33 -7
  97. package/dist/core/embeddings/runtime-install.d.ts +119 -0
  98. package/dist/core/embeddings/runtime-install.js +372 -0
  99. package/dist/core/embeddings/runtime-support.d.ts +48 -17
  100. package/dist/core/embeddings/runtime-support.js +96 -0
  101. package/dist/core/git-staleness.js +1 -1
  102. package/dist/core/group/bridge-db.js +2 -0
  103. package/dist/core/group/extractors/http-patterns/python.js +246 -108
  104. package/dist/core/group/extractors/manifest-extractor.js +4 -0
  105. package/dist/core/incremental/escalation-gate.d.ts +38 -0
  106. package/dist/core/incremental/escalation-gate.js +48 -0
  107. package/dist/core/incremental/shadow-candidates.d.ts +3 -3
  108. package/dist/core/incremental/shadow-candidates.js +3 -3
  109. package/dist/core/incremental/subgraph-extract.d.ts +2 -2
  110. package/dist/core/incremental/subgraph-extract.js +2 -2
  111. package/dist/core/index-freshness.d.ts +5 -0
  112. package/dist/core/index-freshness.js +13 -0
  113. package/dist/core/ingestion/class-extractors/configs/jvm.js +29 -0
  114. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
  115. package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
  116. package/dist/core/ingestion/cobol-processor.js +27 -26
  117. package/dist/core/ingestion/community-processor.d.ts +51 -1
  118. package/dist/core/ingestion/community-processor.js +323 -64
  119. package/dist/core/ingestion/emit-references.js +7 -2
  120. package/dist/core/ingestion/filesystem-walker.js +4 -0
  121. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +3 -0
  122. package/dist/core/ingestion/frameworks/spring/analysis-features.js +7 -0
  123. package/dist/core/ingestion/frameworks/spring/bean-candidates.d.ts +30 -0
  124. package/dist/core/ingestion/frameworks/spring/bean-candidates.js +182 -0
  125. package/dist/core/ingestion/frameworks/spring/bean-catalog.d.ts +12 -0
  126. package/dist/core/ingestion/frameworks/spring/bean-catalog.js +26 -0
  127. package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +24 -0
  128. package/dist/core/ingestion/frameworks/spring/config-bindings.js +115 -0
  129. package/dist/core/ingestion/languages/c/captures.js +56 -0
  130. package/dist/core/ingestion/languages/c/query.js +17 -0
  131. package/dist/core/ingestion/languages/c/scope-resolver.js +6 -0
  132. package/dist/core/ingestion/languages/cobol/captures.js +93 -0
  133. package/dist/core/ingestion/languages/cobol/scope-resolver.js +7 -0
  134. package/dist/core/ingestion/languages/cpp/captures.js +365 -75
  135. package/dist/core/ingestion/languages/cpp/scope-resolver.js +14 -0
  136. package/dist/core/ingestion/languages/csharp/captures.js +25 -0
  137. package/dist/core/ingestion/languages/dart/captures.js +90 -2
  138. package/dist/core/ingestion/languages/dart/extension-type-preprocess.d.ts +7 -0
  139. package/dist/core/ingestion/languages/dart/extension-type-preprocess.js +30 -0
  140. package/dist/core/ingestion/languages/dart.js +2 -0
  141. package/dist/core/ingestion/languages/go/captures.js +34 -0
  142. package/dist/core/ingestion/languages/index.d.ts +1 -0
  143. package/dist/core/ingestion/languages/index.js +2 -0
  144. package/dist/core/ingestion/languages/java/analysis-features.d.ts +3 -0
  145. package/dist/core/ingestion/languages/java/analysis-features.js +13 -0
  146. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +22 -0
  147. package/dist/core/ingestion/languages/java/capture-side-channel.js +58 -0
  148. package/dist/core/ingestion/languages/java/captures.d.ts +4 -3
  149. package/dist/core/ingestion/languages/java/captures.js +193 -17
  150. package/dist/core/ingestion/languages/java/package-facts.d.ts +5 -0
  151. package/dist/core/ingestion/languages/java/package-facts.js +9 -0
  152. package/dist/core/ingestion/languages/java/package-siblings.d.ts +3 -16
  153. package/dist/core/ingestion/languages/java/package-siblings.js +8 -147
  154. package/dist/core/ingestion/languages/java/query.js +23 -0
  155. package/dist/core/ingestion/languages/java/scope-resolver.js +23 -0
  156. package/dist/core/ingestion/languages/java/spring-bean-metadata.d.ts +2 -0
  157. package/dist/core/ingestion/languages/java/spring-bean-metadata.js +8 -0
  158. package/dist/core/ingestion/languages/java/spring-config-bindings.d.ts +23 -0
  159. package/dist/core/ingestion/languages/java/spring-config-bindings.js +215 -0
  160. package/dist/core/ingestion/languages/java.js +3 -0
  161. package/dist/core/ingestion/languages/javascript/captures.js +16 -0
  162. package/dist/core/ingestion/languages/javascript/query.js +21 -0
  163. package/dist/core/ingestion/languages/jvm/package-facts.d.ts +35 -0
  164. package/dist/core/ingestion/languages/jvm/package-facts.js +40 -0
  165. package/dist/core/ingestion/languages/jvm/package-siblings.d.ts +14 -0
  166. package/dist/core/ingestion/languages/jvm/package-siblings.js +129 -0
  167. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +17 -3
  168. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +42 -8
  169. package/dist/core/ingestion/languages/kotlin/captures.js +59 -0
  170. package/dist/core/ingestion/languages/kotlin/package-facts.d.ts +5 -0
  171. package/dist/core/ingestion/languages/kotlin/package-facts.js +9 -0
  172. package/dist/core/ingestion/languages/kotlin/package-siblings.d.ts +4 -0
  173. package/dist/core/ingestion/languages/kotlin/package-siblings.js +8 -0
  174. package/dist/core/ingestion/languages/kotlin/query.js +19 -0
  175. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +9 -1
  176. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.d.ts +2 -0
  177. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.js +8 -0
  178. package/dist/core/ingestion/languages/kotlin.js +5 -6
  179. package/dist/core/ingestion/languages/move.d.ts +1 -0
  180. package/dist/core/ingestion/languages/move.js +27 -0
  181. package/dist/core/ingestion/languages/php/captures.js +40 -0
  182. package/dist/core/ingestion/languages/php/import-decomposer.js +12 -0
  183. package/dist/core/ingestion/languages/php/import-target.d.ts +2 -1
  184. package/dist/core/ingestion/languages/php/import-target.js +110 -2
  185. package/dist/core/ingestion/languages/php/interpret.js +10 -0
  186. package/dist/core/ingestion/languages/php/scope-resolver.js +1 -1
  187. package/dist/core/ingestion/languages/python/captures.d.ts +3 -4
  188. package/dist/core/ingestion/languages/python/captures.js +24 -5
  189. package/dist/core/ingestion/languages/python/interpret.js +4 -0
  190. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +15 -2
  191. package/dist/core/ingestion/languages/python/receiver-binding.js +96 -2
  192. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +5 -5
  193. package/dist/core/ingestion/languages/python/simple-hooks.js +15 -5
  194. package/dist/core/ingestion/languages/ruby/captures.js +42 -0
  195. package/dist/core/ingestion/languages/rust/captures.js +13 -0
  196. package/dist/core/ingestion/languages/rust/interpret.js +18 -0
  197. package/dist/core/ingestion/languages/rust/query.js +9 -0
  198. package/dist/core/ingestion/languages/rust/range-binding.js +6 -2
  199. package/dist/core/ingestion/languages/swift/captures.js +12 -0
  200. package/dist/core/ingestion/languages/typescript/captures.js +21 -0
  201. package/dist/core/ingestion/languages/typescript/nuxt-auto-imports.js +2 -1
  202. package/dist/core/ingestion/languages/typescript/query.js +37 -0
  203. package/dist/core/ingestion/markdown-processor.js +3 -2
  204. package/dist/core/ingestion/model/registration-table.js +1 -0
  205. package/dist/core/ingestion/parsing-processor.d.ts +3 -1
  206. package/dist/core/ingestion/parsing-processor.js +36 -1
  207. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  208. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  209. package/dist/core/ingestion/pipeline-phases/parse-impl.js +56 -2
  210. package/dist/core/ingestion/pipeline-phases/parse.d.ts +0 -2
  211. package/dist/core/ingestion/pipeline-phases/parse.js +12 -3
  212. package/dist/core/ingestion/pipeline-phases/processes.d.ts +8 -0
  213. package/dist/core/ingestion/pipeline-phases/processes.js +11 -1
  214. package/dist/core/ingestion/pipeline-phases/spring-config.d.ts +37 -0
  215. package/dist/core/ingestion/pipeline-phases/spring-config.js +433 -0
  216. package/dist/core/ingestion/pipeline-phases/standalone-ingest.d.ts +10 -0
  217. package/dist/core/ingestion/pipeline-phases/standalone-ingest.js +6 -0
  218. package/dist/core/ingestion/pipeline.d.ts +4 -2
  219. package/dist/core/ingestion/pipeline.js +5 -2
  220. package/dist/core/ingestion/resolve-references.js +12 -0
  221. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
  222. package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
  223. package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
  224. package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
  225. package/dist/core/ingestion/scope-extractor.js +306 -43
  226. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +71 -2
  227. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +7 -7
  228. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +8 -7
  229. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +3 -1
  230. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +6 -0
  231. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +1 -0
  232. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +4 -1
  233. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +7 -2
  234. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +47 -0
  235. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +1138 -0
  236. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +16 -4
  237. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +97 -1
  238. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +60 -0
  239. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +111 -0
  240. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +4 -3
  241. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +5 -0
  242. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +25 -38
  243. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +6 -0
  244. package/dist/core/ingestion/scope-resolution/pipeline/run.js +147 -35
  245. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  246. package/dist/core/ingestion/scope-resolution/scope/walkers.js +73 -44
  247. package/dist/core/ingestion/taint/typescript-model.js +34 -2
  248. package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
  249. package/dist/core/ingestion/tree-sitter-queries.js +23 -2
  250. package/dist/core/ingestion/type-extractors/jvm.js +17 -2
  251. package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
  252. package/dist/core/ingestion/utils/ast-helpers.js +153 -2
  253. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +94 -0
  254. package/dist/core/ingestion/utils/callable-flow-captures.js +878 -0
  255. package/dist/core/ingestion/utils/line-base.d.ts +20 -0
  256. package/dist/core/ingestion/utils/line-base.js +20 -0
  257. package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
  258. package/dist/core/ingestion/utils/symbol-labels.js +45 -0
  259. package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
  260. package/dist/core/ingestion/workers/parse-worker.js +40 -5
  261. package/dist/core/ingestion/workers/result-merge.js +4 -0
  262. package/dist/core/ingestion/workers/worker-pool.d.ts +28 -0
  263. package/dist/core/ingestion/workers/worker-pool.js +128 -28
  264. package/dist/core/lbug/csv-generator.d.ts +15 -0
  265. package/dist/core/lbug/csv-generator.js +124 -27
  266. package/dist/core/lbug/cypher-escape.d.ts +20 -0
  267. package/dist/core/lbug/cypher-escape.js +20 -0
  268. package/dist/core/lbug/extension-load-error.d.ts +67 -0
  269. package/dist/core/lbug/extension-load-error.js +326 -0
  270. package/dist/core/lbug/extension-loader.d.ts +17 -2
  271. package/dist/core/lbug/extension-loader.js +38 -13
  272. package/dist/core/lbug/lbug-adapter.d.ts +203 -2
  273. package/dist/core/lbug/lbug-adapter.js +527 -86
  274. package/dist/core/lbug/lbug-config.d.ts +56 -2
  275. package/dist/core/lbug/lbug-config.js +267 -7
  276. package/dist/core/lbug/move-columns.d.ts +7 -0
  277. package/dist/core/lbug/move-columns.js +86 -0
  278. package/dist/core/lbug/native-check.d.ts +40 -0
  279. package/dist/core/lbug/native-check.js +90 -0
  280. package/dist/core/lbug/node-table-layout.d.ts +29 -0
  281. package/dist/core/lbug/node-table-layout.js +119 -0
  282. package/dist/core/lbug/pool-adapter.d.ts +23 -1
  283. package/dist/core/lbug/pool-adapter.js +115 -8
  284. package/dist/core/lbug/schema.d.ts +4 -3
  285. package/dist/core/lbug/schema.js +16 -16
  286. package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
  287. package/dist/core/lbug/sidecar-recovery.js +418 -16
  288. package/dist/core/lbug/wal-checkpoint-driver.js +3 -0
  289. package/dist/core/move/artifact-download.d.ts +19 -0
  290. package/dist/core/move/artifact-download.js +179 -0
  291. package/dist/core/move/compiler-facts.d.ts +120 -0
  292. package/dist/core/move/compiler-facts.js +9 -0
  293. package/dist/core/move/consistency.d.ts +28 -0
  294. package/dist/core/move/consistency.js +98 -0
  295. package/dist/core/move/constants.d.ts +98 -0
  296. package/dist/core/move/constants.js +136 -0
  297. package/dist/core/move/discovery.d.ts +10 -0
  298. package/dist/core/move/discovery.js +22 -0
  299. package/dist/core/move/entry-points.d.ts +14 -0
  300. package/dist/core/move/entry-points.js +40 -0
  301. package/dist/core/move/facts-mapper.d.ts +75 -0
  302. package/dist/core/move/facts-mapper.js +534 -0
  303. package/dist/core/move/install-lock.d.ts +14 -0
  304. package/dist/core/move/install-lock.js +102 -0
  305. package/dist/core/move/install.d.ts +39 -0
  306. package/dist/core/move/install.js +391 -0
  307. package/dist/core/move/mcp-client.d.ts +115 -0
  308. package/dist/core/move/mcp-client.js +436 -0
  309. package/dist/core/move/move-ingest.d.ts +49 -0
  310. package/dist/core/move/move-ingest.js +320 -0
  311. package/dist/core/move/provision.d.ts +19 -0
  312. package/dist/core/move/provision.js +91 -0
  313. package/dist/core/move/release.d.ts +6 -0
  314. package/dist/core/move/release.js +10 -0
  315. package/dist/core/move/symbol-id.d.ts +35 -0
  316. package/dist/core/move/symbol-id.js +65 -0
  317. package/dist/core/move/type-parser.d.ts +11 -0
  318. package/dist/core/move/type-parser.js +38 -0
  319. package/dist/core/platform/capabilities.d.ts +0 -1
  320. package/dist/core/platform/capabilities.js +39 -8
  321. package/dist/core/run-analyze.d.ts +3 -3
  322. package/dist/core/run-analyze.js +1001 -184
  323. package/dist/core/search/fts-indexes.d.ts +31 -0
  324. package/dist/core/search/fts-indexes.js +73 -0
  325. package/dist/core/search/fts-schema.js +2 -0
  326. package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
  327. package/dist/core/tree-sitter/safe-parse.js +21 -7
  328. package/dist/core/wiki/graph-queries.js +6 -5
  329. package/dist/core/wiki/llm-client.d.ts +8 -2
  330. package/dist/core/wiki/llm-client.js +41 -5
  331. package/dist/mcp/core/embedder.js +16 -2
  332. package/dist/mcp/http-transport.d.ts +5 -0
  333. package/dist/mcp/http-transport.js +19 -5
  334. package/dist/mcp/local/bean-metadata.d.ts +2 -0
  335. package/dist/mcp/local/bean-metadata.js +25 -0
  336. package/dist/mcp/local/line-display.d.ts +22 -0
  337. package/dist/mcp/local/line-display.js +3 -0
  338. package/dist/mcp/local/local-backend.d.ts +19 -1
  339. package/dist/mcp/local/local-backend.js +402 -155
  340. package/dist/mcp/local/pdg-impact.d.ts +5 -3
  341. package/dist/mcp/local/pdg-impact.js +5 -2
  342. package/dist/mcp/output-budget.d.ts +5 -0
  343. package/dist/mcp/output-budget.js +52 -0
  344. package/dist/mcp/read-only-policy.d.ts +12 -0
  345. package/dist/mcp/read-only-policy.js +102 -0
  346. package/dist/mcp/repository-policy.d.ts +34 -0
  347. package/dist/mcp/repository-policy.js +328 -0
  348. package/dist/mcp/resources.js +32 -5
  349. package/dist/mcp/server.d.ts +5 -2
  350. package/dist/mcp/server.js +29 -9
  351. package/dist/mcp/tools.d.ts +0 -8
  352. package/dist/mcp/tools.js +102 -5
  353. package/dist/server/analyze-job.d.ts +3 -0
  354. package/dist/server/analyze-job.js +17 -0
  355. package/dist/server/analyze-launch.d.ts +6 -0
  356. package/dist/server/analyze-launch.js +82 -6
  357. package/dist/server/analyze-worker-core.d.ts +2 -1
  358. package/dist/server/analyze-worker-core.js +5 -2
  359. package/dist/server/analyze-worker.js +29 -6
  360. package/dist/server/api.d.ts +30 -0
  361. package/dist/server/api.js +120 -34
  362. package/dist/server/mcp-http.d.ts +1 -1
  363. package/dist/server/mcp-http.js +4 -2
  364. package/dist/server/upload-ingest.js +2 -1
  365. package/dist/server/validation.js +2 -1
  366. package/dist/storage/git.d.ts +31 -0
  367. package/dist/storage/git.js +111 -1
  368. package/dist/storage/parse-cache.js +7 -1
  369. package/dist/storage/parsedfile-store.d.ts +8 -0
  370. package/dist/storage/parsedfile-store.js +165 -1
  371. package/dist/storage/repo-manager.d.ts +194 -2
  372. package/dist/storage/repo-manager.js +56 -1
  373. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
  374. package/hooks/claude/gitnexus-hook.cjs +59 -9
  375. package/hooks/claude/pre-tool-use.sh +0 -0
  376. package/hooks/claude/session-start.sh +0 -0
  377. package/package.json +21 -15
  378. package/scripts/cross-platform-tests.ts +56 -0
  379. package/scripts/ensure-fts.ts +43 -0
  380. package/scripts/install-duckdb-extension.mjs +85 -24
  381. package/scripts/run-cross-platform.ts +61 -6
  382. package/scripts/shard-arg.ts +30 -0
  383. package/scripts/sync-plugin-manifests.mjs +192 -0
  384. package/skills/gitnexus-lfg/README.md +55 -0
  385. package/skills/gitnexus-lfg/SKILL.md +86 -0
  386. package/skills/gitnexus-plan/README.md +142 -0
  387. package/skills/gitnexus-plan/SKILL.md +348 -0
  388. package/skills/gitnexus-plan/references/context-ledger.md +137 -0
  389. package/skills/gitnexus-plan/references/context-pack.md +126 -0
  390. package/skills/gitnexus-plan/references/evidence-provenance.md +272 -0
  391. package/skills/gitnexus-plan/references/pdg-slice.md +109 -0
  392. package/skills/gitnexus-plan/references/plan-template.md +201 -0
  393. package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +2084 -0
  394. package/skills/gitnexus-review/SKILL.md +273 -0
  395. package/skills/gitnexus-review/ci-personas/ci-adversarial-lens.md +42 -0
  396. package/skills/gitnexus-review/ci-personas/ci-blast-radius-lens.md +39 -0
  397. package/skills/gitnexus-review/ci-personas/ci-correctness-lens.md +37 -0
  398. package/skills/gitnexus-review/ci-personas/ci-coverage-lens.md +40 -0
  399. package/skills/gitnexus-review/ci-personas/ci-critic-lens.md +42 -0
  400. package/skills/gitnexus-review/ci-personas/ci-security-lens.md +39 -0
  401. package/skills/gitnexus-work/README.md +71 -0
  402. package/skills/gitnexus-work/SKILL.md +269 -0
  403. package/skills/gitnexus-work/references/evidence-provenance.md +272 -0
  404. package/skills/gitnexus-work/scripts/evidence-provenance.mjs +2084 -0
  405. package/web/assets/ProcessFlowModal-B_bfBySy.js +22 -0
  406. package/web/assets/__vite-browser-external-bMKyYQkO.js +1 -0
  407. package/web/assets/agent-Bqxn-abU.js +626 -0
  408. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
  409. package/web/assets/architectureDiagram-UL44E2DR-CmG3uPWf.js +36 -0
  410. package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-DBefcjof.js} +7 -7
  411. package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-EjWnjEJl.js} +6 -6
  412. package/web/assets/chunk-2T2R6R2M-Bb6Sy3_j.js +4 -0
  413. package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
  414. package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
  415. package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
  416. package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
  417. package/web/assets/chunk-67TQ5CYL-CA7OhIEf.js +124 -0
  418. package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
  419. package/web/assets/chunk-7J6CGLKN-BlKwgXKs.js +10 -0
  420. package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
  421. package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
  422. package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
  423. package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-Ckl3_KkO.js} +13 -13
  424. package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
  425. package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-BZeP-55u.js} +17 -17
  426. package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
  427. package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
  428. package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-C162wE5z.js} +5 -5
  429. package/web/assets/chunk-LII3EMHJ-BL6lKJ_P.js +1 -0
  430. package/web/assets/chunk-LRIF4GLE-n59lhprL.js +1 -0
  431. package/web/assets/chunk-QA3QBVWF-DVXPOIxe.js +2 -0
  432. package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
  433. package/web/assets/chunk-RG4AUYOV-ZNgyLFq6.js +206 -0
  434. package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
  435. package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
  436. package/web/assets/chunk-T2UQINTJ-BEyXhZWe.js +1 -0
  437. package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
  438. package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
  439. package/web/assets/chunk-UY5QBCOK-ByqTVLvh.js +1 -0
  440. package/web/assets/chunk-VU6ZFW4Y-BLeasdkU.js +2 -0
  441. package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
  442. package/web/assets/chunk-ZXARS5L4-C3v-4Fsw.js +1 -0
  443. package/web/assets/classDiagram-KGZ6W3CR-olpO3fMe.js +1 -0
  444. package/web/assets/classDiagram-v2-72OJOZXJ-olpO3fMe.js +1 -0
  445. package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
  446. package/web/assets/dagre-ND4H6XIP-CY4iIF7v.js +4 -0
  447. package/web/assets/diagram-3NCE3AQN-CO6QpzEE.js +43 -0
  448. package/web/assets/diagram-GF46GFSD-B2atbzmU.js +24 -0
  449. package/web/assets/diagram-HNR7UZ2L-DVRltWbL.js +3 -0
  450. package/web/assets/diagram-QXG6HAR7-DR6AHD2h.js +24 -0
  451. package/web/assets/diagram-WEQXMOUZ-DkpoMwTL.js +10 -0
  452. package/web/assets/erDiagram-L5TCEMPS-n8g_90bc.js +85 -0
  453. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
  454. package/web/assets/flowDiagram-H6V6AXG4-SGMDiCkB.js +162 -0
  455. package/web/assets/ganttDiagram-JCBTUEKG-Cb3UBqRS.js +292 -0
  456. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
  457. package/web/assets/gitGraphDiagram-S2ZK5IYY-Bs9CR7tq.js +106 -0
  458. package/web/assets/index-CX_fADmQ.css +2 -0
  459. package/web/assets/index-D1Z3dGGz.js +575 -0
  460. package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
  461. package/web/assets/infoDiagram-3YFTVSEB-T368on4D.js +2 -0
  462. package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-XpjJRU9h.js} +6 -6
  463. package/web/assets/journeyDiagram-M6C3CM3L-C6wjooas.js +139 -0
  464. package/web/assets/kanban-definition-75IXJCU3-5_UVY79g.js +89 -0
  465. package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
  466. package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-8xDLzk2e.js} +29 -29
  467. package/web/assets/node-Ct_zna8U.js +8 -0
  468. package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
  469. package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
  470. package/web/assets/pieDiagram-CU6KROY3-Bv4LpAbr.js +30 -0
  471. package/web/assets/preload-helper-Czpn1I53.js +1 -0
  472. package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-DR54jOeR.js} +6 -6
  473. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
  474. package/web/assets/requirementDiagram-JXO7QTGE-PEkg7sKC.js +84 -0
  475. package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  476. package/web/assets/sankeyDiagram-URQDO5SZ-DDWEtjcs.js +40 -0
  477. package/web/assets/sdk-CzHHH8tD.js +37 -0
  478. package/web/assets/sequenceDiagram-VS2MUI6T-Bv-uwANx.js +162 -0
  479. package/web/assets/src-JV30wyV8.js +1 -0
  480. package/web/assets/stateDiagram-7D4R322I-DVNjmkEq.js +1 -0
  481. package/web/assets/stateDiagram-v2-36443NZ5-CyN4Fh7_.js +1 -0
  482. package/web/assets/timeline-definition-O6YCAMPW-Qmsuo7qS.js +120 -0
  483. package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
  484. package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
  485. package/web/assets/vennDiagram-MWXL3ELB-BD1iK1SX.js +34 -0
  486. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
  487. package/web/assets/wardleyDiagram-CUQ6CDDI-D6TzLVob.js +78 -0
  488. package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-CoZ_Tits.js} +6 -6
  489. package/web/index.html +18 -10
  490. package/skills/gitnexus-pr-review.md +0 -163
  491. package/web/assets/agent-Dli_x7bU.js +0 -660
  492. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
  493. package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
  494. package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
  495. package/web/assets/chunk-67TQ5CYL-4sNPJU1q.js +0 -124
  496. package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
  497. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
  498. package/web/assets/chunk-LII3EMHJ-D-jm-dLa.js +0 -1
  499. package/web/assets/chunk-QA3QBVWF-BgRW3SXd.js +0 -2
  500. package/web/assets/chunk-RG4AUYOV-CqWzWsV3.js +0 -206
  501. package/web/assets/chunk-T2UQINTJ-DSBqkzH7.js +0 -1
  502. package/web/assets/chunk-UY5QBCOK-DyF0vyGd.js +0 -1
  503. package/web/assets/chunk-ZXARS5L4-CxN8oiwI.js +0 -1
  504. package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
  505. package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
  506. package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
  507. package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
  508. package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
  509. package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
  510. package/web/assets/diagram-HNR7UZ2L-DFCfd5LI.js +0 -3
  511. package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
  512. package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
  513. package/web/assets/erDiagram-L5TCEMPS-8X1y6R4Y.js +0 -85
  514. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
  515. package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
  516. package/web/assets/ganttDiagram-JCBTUEKG-D3iL2Aet.js +0 -292
  517. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
  518. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
  519. package/web/assets/index-KctnI3Vq.js +0 -635
  520. package/web/assets/index-_lgn7hs5.css +0 -2
  521. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
  522. package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
  523. package/web/assets/journeyDiagram-M6C3CM3L-CvArszLo.js +0 -139
  524. package/web/assets/kanban-definition-75IXJCU3-CpfVLLf9.js +0 -89
  525. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
  526. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
  527. package/web/assets/pieDiagram-CU6KROY3-s27EFWgP.js +0 -30
  528. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
  529. package/web/assets/requirementDiagram-JXO7QTGE-CWhqInuf.js +0 -84
  530. package/web/assets/sankeyDiagram-URQDO5SZ-1qEjlFIB.js +0 -40
  531. package/web/assets/sequenceDiagram-VS2MUI6T-RyTlZ5cR.js +0 -162
  532. package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
  533. package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
  534. package/web/assets/timeline-definition-O6YCAMPW-DrrqLYAf.js +0 -120
  535. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
  536. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
  537. package/web/assets/vennDiagram-MWXL3ELB-B0RkWAim.js +0 -34
  538. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
  539. package/web/assets/wardleyDiagram-CUQ6CDDI-boUxiQ5F.js +0 -78
@@ -8,8 +8,10 @@
8
8
  import fs from 'fs/promises';
9
9
  import path from 'path';
10
10
  import { createHash } from 'crypto';
11
- import { initLbug, executeQuery, executeParameterized, closeLbug, isLbugReady, } from '../../core/lbug/pool-adapter.js';
11
+ import { initLbug, executeQuery, executeParameterized, closeLbug, isLbugReady, statDbIdentity, dbIdentityChanged, } from '../../core/lbug/pool-adapter.js';
12
+ import { queryClassBeanMetadata } from './bean-metadata.js';
12
13
  import { isValidQueryParams } from '../../core/lbug/query-params.js';
14
+ import { toDisplayLine } from './line-display.js';
13
15
  import { isWalCorruptionError, WAL_RECOVERY_SUGGESTION } from '../../core/lbug/lbug-config.js';
14
16
  // Embedding imports are lazy (dynamic import) to avoid loading onnxruntime-node
15
17
  // at MCP server startup — crashes on unsupported Node ABI versions (#89)
@@ -24,11 +26,13 @@ import { collectBestChunks } from '../../core/embeddings/types.js';
24
26
  import { DEFAULT_MCP_VECTOR_MAX_DISTANCE, getVectorMaxDistance, } from '../../core/embeddings/config.js';
25
27
  import { rankExactEmbeddingRows, } from '../../core/embeddings/exact-search.js';
26
28
  import { EMBEDDING_TABLE_NAME, EMBEDDING_INDEX_NAME } from '../../core/lbug/schema.js';
27
- import { getExactScanLimit, isVectorExtensionSupportedByPlatform, } from '../../core/platform/capabilities.js';
29
+ import { getExactScanLimit } from '../../core/platform/capabilities.js';
28
30
  import { PhaseTimer } from '../../core/search/phase-timer.js';
31
+ import { ftsDegradedWarning } from '../../core/search/fts-indexes.js';
29
32
  import { cjkSegmentationModeMismatch, containsSegmentableCjkRun, getSearchFTSCjkSegmentation, isSupportedCjkSegmentationMode, MAX_CJK_SEGMENTATION_QUERY_LENGTH, } from '../../core/search/cjk-segmentation.js';
30
33
  import { checkStalenessAsync, checkCwdMatch } from '../../core/git-staleness.js';
31
34
  import { logger } from '../../core/logger.js';
35
+ import { isLocalEmbeddingRuntimeBlockerMessage, isMissingLocalEmbeddingStackMessage, } from '../../core/embeddings/runtime-support.js';
32
36
  import { LIST_REPOS_DEFAULT_LIMIT, LIST_REPOS_MAX_LIMIT, EXPLAIN_DEFAULT_LIMIT, EXPLAIN_MAX_LIMIT, PDG_QUERY_DEFAULT_LIMIT, PDG_QUERY_MAX_LIMIT, } from '../tools.js';
33
37
  import { findImportCycles } from '../../core/graph/import-cycles.js';
34
38
  import { decodeTaintPath } from '../../core/ingestion/taint/path-codec.js';
@@ -64,6 +68,51 @@ function resolveAliasString(canonical, legacy) {
64
68
  }
65
69
  return undefined;
66
70
  }
71
+ const TOOL_STRING_ALIASES = {
72
+ impact: [{ canonical: 'target', aliases: ['name', 'symbol'] }],
73
+ context: [{ canonical: 'file_path', aliases: ['file'] }],
74
+ };
75
+ function normalizeToolParams(method, params) {
76
+ const input = params && typeof params === 'object' ? params : {};
77
+ const definitions = TOOL_STRING_ALIASES[method];
78
+ if (!definitions)
79
+ return { params: input };
80
+ const normalized = { ...input };
81
+ for (const { canonical, aliases } of definitions) {
82
+ const keys = [canonical, ...aliases];
83
+ const supplied = [];
84
+ for (const key of keys) {
85
+ if (!Object.prototype.hasOwnProperty.call(input, key))
86
+ continue;
87
+ const value = input[key];
88
+ // Internal CLI callers materialize omitted optional flags as undefined.
89
+ if (value === undefined)
90
+ continue;
91
+ if (typeof value !== 'string' || !value.trim()) {
92
+ return { error: `MCP parameter ${method}.${key} must be a non-empty string.` };
93
+ }
94
+ supplied.push({ key, value: value.trim() });
95
+ }
96
+ const distinctValues = new Set(supplied.map(({ value }) => value));
97
+ if (distinctValues.size > 1) {
98
+ return {
99
+ error: `Conflicting MCP parameters for ${method}.${canonical}: ${supplied
100
+ .map(({ key }) => key)
101
+ .join(', ')} must agree.`,
102
+ };
103
+ }
104
+ for (const alias of aliases)
105
+ delete normalized[alias];
106
+ if (supplied.length > 0)
107
+ normalized[canonical] = supplied[0].value;
108
+ }
109
+ if (method === 'impact' &&
110
+ typeof normalized.target !== 'string' &&
111
+ (typeof normalized.target_uid !== 'string' || !normalized.target_uid.trim())) {
112
+ return { error: 'MCP impact requires target, name, symbol, or target_uid.' };
113
+ }
114
+ return { params: normalized };
115
+ }
67
116
  // AI context generation is CLI-only (gitnexus analyze)
68
117
  // import { generateAIContextFiles } from '../../cli/ai-context.js';
69
118
  /**
@@ -71,6 +120,8 @@ function resolveAliasString(canonical, legacy) {
71
120
  * Matches common test file patterns across all supported languages.
72
121
  */
73
122
  export function isTestFilePath(filePath) {
123
+ if (!filePath)
124
+ return false;
74
125
  const p = filePath.toLowerCase().replace(/\\/g, '/');
75
126
  return (p.includes('.test.') ||
76
127
  p.includes('.spec.') ||
@@ -152,6 +203,10 @@ export const VALID_RELATION_TYPES = new Set([
152
203
  // (WRAPS/FETCHES precedent): the 0.5 unknown-type floor applies there,
153
204
  // and the edges carry their own confidence (0.8) in the graph.
154
205
  'INJECTS',
206
+ 'ACQUIRES',
207
+ 'READS_RESOURCE',
208
+ 'WRITES_RESOURCE',
209
+ 'USES_TYPE',
155
210
  ]);
156
211
  /**
157
212
  * Relation types the #1858 epistemic-boundary probe keys on. Kept as
@@ -419,6 +474,11 @@ export class LocalBackend {
419
474
  // not persist across calls and the staleness check would reinit forever
420
475
  // (#2106).
421
476
  lastObservedIndexedAt = new Map();
477
+ // #2614 F1: file identity of the lbug the pool last opened. An atomic swap or
478
+ // an in-place incremental changes the inode; reiniting on that reinit-covers
479
+ // the window where meta.indexedAt hasn't caught up (and the incremental case),
480
+ // so a rebuilt index is never served stale even when the stamp looks current.
481
+ lastObservedDbIdentity = new Map();
422
482
  groupToolSvc = null;
423
483
  /**
424
484
  * One-shot stderr warnings for sibling-clone drift, keyed by
@@ -434,6 +494,12 @@ export class LocalBackend {
434
494
  * stderr noisy per DoD §2.8.
435
495
  */
436
496
  warnedVectorUnsupported = false;
497
+ /**
498
+ * One-shot warning when a pruned or Node-unloadable optional embedding stack
499
+ * (#2370/#2372) forces semantic search to fall back to BM25 — so the
500
+ * degradation is visible once instead of silent.
501
+ */
502
+ warnedMissingEmbeddingStack = false;
437
503
  /**
438
504
  * Cross-repo group tools (CLI). Shares logic with MCP `group_*` handlers.
439
505
  */
@@ -445,7 +511,7 @@ export class LocalBackend {
445
511
  query: (r, p) => this.query(r, p),
446
512
  impactByUid: (id, uid, d, o) => this.impactByUid(id, uid, d, o),
447
513
  context: (r, p) => this.context(r, p),
448
- trace: (r, p) => this.trace(r, p),
514
+ trace: (r, p) => this.traceForGroup(r, p),
449
515
  resolveSymbol: (r, q) => this.resolveSymbolForGroup(r, q),
450
516
  pdgFlows: (r, anchor, opts) => this.pdgFlowsForGroup(r, anchor, opts),
451
517
  };
@@ -453,6 +519,23 @@ export class LocalBackend {
453
519
  }
454
520
  return this.groupToolSvc;
455
521
  }
522
+ /**
523
+ * Adapt local `trace` to the group port. The assembled group/cross-repo trace
524
+ * presents 1-based endpoints (via resolveSymbolForGroup), so convert the hop
525
+ * lines here too — otherwise one response mixes 1-based endpoints with 0-based
526
+ * hops (#2380). Single-repo `trace` dispatches directly (not through this
527
+ * port) and stays 0-based (documented full-parity follow-up).
528
+ */
529
+ async traceForGroup(repo, params) {
530
+ const result = await this.trace(repo, params);
531
+ const hops = result.hops;
532
+ if (Array.isArray(hops)) {
533
+ for (const hop of hops) {
534
+ hop.startLine = toDisplayLine(hop.startLine);
535
+ }
536
+ }
537
+ return result;
538
+ }
456
539
  /**
457
540
  * Adapt the shared symbol resolver to the GroupToolPort contract. Used by the
458
541
  * cross-repo trace path to locate which member repo an endpoint lives in and
@@ -470,8 +553,8 @@ export class LocalBackend {
470
553
  name: s.name,
471
554
  type: s.type,
472
555
  filePath: s.filePath,
473
- startLine: s.startLine,
474
- endLine: s.endLine,
556
+ startLine: toDisplayLine(s.startLine),
557
+ endLine: toDisplayLine(s.endLine),
475
558
  },
476
559
  };
477
560
  }
@@ -483,7 +566,7 @@ export class LocalBackend {
483
566
  name: c.name,
484
567
  type: c.type,
485
568
  filePath: c.filePath,
486
- startLine: c.startLine,
569
+ startLine: toDisplayLine(c.startLine),
487
570
  })),
488
571
  };
489
572
  }
@@ -681,6 +764,7 @@ export class LocalBackend {
681
764
  this.initializedRepos.delete(key);
682
765
  this.lastStalenessCheck.delete(key);
683
766
  this.lastObservedIndexedAt.delete(key);
767
+ this.lastObservedDbIdentity.delete(key);
684
768
  this.reinitPromises.delete(key);
685
769
  closeLbug(key).catch(() => { });
686
770
  }
@@ -1040,23 +1124,38 @@ export class LocalBackend {
1040
1124
  // Reading the flat meta for a branch handle would compare the branch
1041
1125
  // index's indexedAt against the primary's and thrash the pool (#2106).
1042
1126
  const meta = await loadMeta(path.dirname(repo.lbugPath));
1043
- if (!meta)
1044
- return;
1045
1127
  // Compare against the last indexedAt OBSERVED for this pool (keyed by
1046
1128
  // lbugPath), not the handle's — branch handles are fresh spreads so a
1047
1129
  // handle mutation would not persist and would reinit on every check.
1048
1130
  const observed = this.lastObservedIndexedAt.get(poolKey) ?? repo.indexedAt;
1049
- if (meta.indexedAt && meta.indexedAt !== observed) {
1050
- // Index was rebuilt — close stale connection and re-init.
1051
- // Wrap in reinitPromises to prevent TOCTOU race where concurrent
1052
- // callers both detect staleness and double-close the pool.
1131
+ const stampChanged = !!meta?.indexedAt && meta.indexedAt !== observed;
1132
+ // #2614 F1: also reinit on a file-identity change. An atomic swap (or an
1133
+ // in-place incremental) changes the lbug inode; keying only on
1134
+ // meta.indexedAt let a reader that reinited inside the pre-swap window
1135
+ // latch on the old inode forever (its stamp already == meta.indexedAt).
1136
+ const currentIdentity = await statDbIdentity(repo.lbugPath);
1137
+ const identityChanged = dbIdentityChanged(this.lastObservedDbIdentity.get(poolKey) ?? null, currentIdentity);
1138
+ if (stampChanged || identityChanged) {
1139
+ // Index was rebuilt/swapped — DELEGATE the close/reopen to the pool's
1140
+ // initLbug, which refuses to evict (and close the shared Database)
1141
+ // while a query is in flight (its checkedOut>0 guard). Calling
1142
+ // closeLbug directly here bypassed that guard and could close a
1143
+ // Database mid-query — a native use-after-free (#2614). Wrap in
1144
+ // reinitPromises to serialize concurrent detectors.
1053
1145
  const reinit = (async () => {
1054
1146
  try {
1055
- await closeLbug(poolKey);
1056
- this.initializedRepos.delete(poolKey);
1057
- this.lastObservedIndexedAt.set(poolKey, meta.indexedAt);
1058
- await initLbug(poolKey, repo.lbugPath);
1059
- this.initializedRepos.add(poolKey);
1147
+ // Advance the observed stamp regardless: a stamp change with an
1148
+ // unchanged file must not re-trigger on every check.
1149
+ if (meta?.indexedAt)
1150
+ this.lastObservedIndexedAt.set(poolKey, meta.indexedAt);
1151
+ const reopened = await initLbug(poolKey, repo.lbugPath);
1152
+ // Advance the observed IDENTITY only when the pool actually rolled
1153
+ // over. If a query was in flight, initLbug served the current
1154
+ // handle and returned false; leaving the identity divergent
1155
+ // re-triggers the reopen on a later idle check instead of latching.
1156
+ if (reopened) {
1157
+ this.lastObservedDbIdentity.set(poolKey, await statDbIdentity(repo.lbugPath));
1158
+ }
1060
1159
  }
1061
1160
  finally {
1062
1161
  this.reinitPromises.delete(poolKey);
@@ -1077,6 +1176,7 @@ export class LocalBackend {
1077
1176
  await initLbug(poolKey, repo.lbugPath);
1078
1177
  this.initializedRepos.add(poolKey);
1079
1178
  this.lastObservedIndexedAt.set(poolKey, repo.indexedAt);
1179
+ this.lastObservedDbIdentity.set(poolKey, await statDbIdentity(repo.lbugPath));
1080
1180
  }
1081
1181
  catch (err) {
1082
1182
  // If lock error, mark as not initialized so next call retries
@@ -1278,7 +1378,10 @@ export class LocalBackend {
1278
1378
  if (method.startsWith('group_')) {
1279
1379
  return this.handleGroupTool(method, params || {});
1280
1380
  }
1281
- const p = params && typeof params === 'object' ? params : {};
1381
+ const normalized = normalizeToolParams(method, params);
1382
+ if ('error' in normalized)
1383
+ return { error: normalized.error };
1384
+ const p = normalized.params;
1282
1385
  // #2175: Claude Code drops a tool-call argument named exactly "query", so the
1283
1386
  // query/cypher tools advertise "search_query"/"statement" while still accepting the
1284
1387
  // legacy "query" key for backward compat. The alias is resolved with `?? ` (new name
@@ -1295,46 +1398,59 @@ export class LocalBackend {
1295
1398
  }
1296
1399
  // Resolve repo from optional param (re-reads registry on miss). An optional
1297
1400
  // `branch` param scopes the resolved handle to that branch's index (#2106).
1298
- const repoParams = params;
1299
- const repo = await this.resolveRepo(repoParams?.repo, repoParams?.branch);
1401
+ const repo = await this.resolveRepo(p.repo, p.branch);
1300
1402
  switch (method) {
1301
1403
  case 'query':
1302
- return this.query(repo, params);
1404
+ return this.query(repo, p);
1303
1405
  case 'cypher': {
1304
- const raw = await this.cypher(repo, params);
1406
+ const raw = await this.cypher(repo, p);
1305
1407
  return this.formatCypherAsMarkdown(raw);
1306
1408
  }
1307
1409
  case 'context':
1308
- return this.context(repo, params);
1410
+ return this.context(repo, p);
1309
1411
  case 'explain':
1310
- return this.explain(repo, params);
1412
+ return this.explain(repo, p);
1311
1413
  case 'pdg_query':
1312
- return this.pdgQuery(repo, params);
1414
+ return this.pdgQuery(repo, p);
1313
1415
  case 'impact':
1314
- return this.impact(repo, params);
1416
+ return this.impact(repo, p);
1315
1417
  case 'detect_changes':
1316
- return this.detectChanges(repo, params);
1418
+ return this.detectChanges(repo, p);
1317
1419
  case 'check':
1318
- return this.check(repo, params);
1420
+ return this.check(repo, p);
1319
1421
  case 'rename':
1320
- return this.rename(repo, params);
1422
+ return this.rename(repo, p);
1321
1423
  // Legacy aliases for backwards compatibility
1322
1424
  case 'search':
1323
- return this.query(repo, params);
1425
+ return this.query(repo, p);
1324
1426
  case 'explore':
1325
- return this.context(repo, { name: params?.name, ...params });
1427
+ return this.context(repo, {
1428
+ name: typeof p.name === 'string' ? p.name : undefined,
1429
+ ...p,
1430
+ });
1326
1431
  case 'overview':
1327
- return this.overview(repo, params);
1432
+ return this.overview(repo, p);
1328
1433
  case 'route_map':
1329
- return this.routeMap(repo, params);
1434
+ return this.routeMap(repo, p);
1330
1435
  case 'shape_check':
1331
- return this.shapeCheck(repo, params);
1436
+ return this.shapeCheck(repo, p);
1332
1437
  case 'tool_map':
1333
- return this.toolMap(repo, params);
1438
+ return this.toolMap(repo, p);
1334
1439
  case 'api_impact':
1335
- return this.apiImpact(repo, params);
1440
+ return this.apiImpact(repo, p);
1441
+ // Move/Aptos tools (graph-property/Cypher only — no move-flow shell-out).
1442
+ case 'move_entries':
1443
+ return this.moveEntries(repo, p);
1444
+ case 'move_resources':
1445
+ return this.moveResources(repo, p);
1446
+ case 'move_impact':
1447
+ return this.moveImpact(repo, {
1448
+ target: typeof p.target === 'string' ? p.target : '',
1449
+ direction: p.direction === 'upstream' || p.direction === 'downstream' ? p.direction : undefined,
1450
+ maxDepth: typeof p.maxDepth === 'number' ? p.maxDepth : undefined,
1451
+ });
1336
1452
  case 'trace':
1337
- return this.trace(repo, params);
1453
+ return this.trace(repo, p);
1338
1454
  default:
1339
1455
  throw new Error(`Unknown tool: ${method}`);
1340
1456
  }
@@ -1564,8 +1680,8 @@ export class LocalBackend {
1564
1680
  name: sym.name,
1565
1681
  type: sym.type,
1566
1682
  filePath: sym.filePath,
1567
- startLine: sym.startLine,
1568
- endLine: sym.endLine,
1683
+ startLine: toDisplayLine(sym.startLine),
1684
+ endLine: toDisplayLine(sym.endLine),
1569
1685
  ...(module ? { module } : {}),
1570
1686
  ...(includeContent && content ? { content } : {}),
1571
1687
  };
@@ -1652,7 +1768,7 @@ export class LocalBackend {
1652
1768
  // path, leaving the success-path response shape byte-identical.
1653
1769
  const warnings = [];
1654
1770
  if (!ftsUsed) {
1655
- warnings.push('FTS indexes missing — keyword search degraded. Run: gitnexus analyze --repair-fts (or gitnexus analyze --force) to rebuild indexes.');
1771
+ warnings.push(ftsDegradedWarning());
1656
1772
  }
1657
1773
  // #2331: a CJK query against a server process resolving
1658
1774
  // GITNEXUS_FTS_CJK_SEGMENTATION to 'none' silently misses sub-phrase
@@ -1791,8 +1907,11 @@ export class LocalBackend {
1791
1907
  name: sym.name || sym[1],
1792
1908
  type: sym.type || sym[2],
1793
1909
  filePath: sym.filePath || sym[3],
1794
- startLine: sym.startLine || sym[4],
1795
- endLine: sym.endLine || sym[5],
1910
+ // Raw 0-based here — `bm25Search` is only called from `query()`,
1911
+ // whose aggregation loop applies `toDisplayLine` once (see below).
1912
+ // Converting here too would double-shift BM25-matched lines (#2380).
1913
+ startLine: sym.startLine ?? sym[4],
1914
+ endLine: sym.endLine ?? sym[5],
1796
1915
  bm25Score: bm25Result.score,
1797
1916
  });
1798
1917
  }
@@ -1834,10 +1953,16 @@ export class LocalBackend {
1834
1953
  const queryVecStr = `[${queryVec.join(',')}]`;
1835
1954
  const maxDistance = getVectorMaxDistance(DEFAULT_MCP_VECTOR_MAX_DISTANCE);
1836
1955
  let bestChunks = new Map();
1837
- if (isVectorExtensionSupportedByPlatform()) {
1838
- try {
1839
- bestChunks = await collectBestChunks(limit, async (fetchLimit) => {
1840
- const vectorQuery = `
1956
+ // Always TRY the vector lane — no platform gate. LadybugDB ships the
1957
+ // VECTOR extension for every supported platform, Windows included
1958
+ // (#2623 follow-up; the old `platform !== 'win32'` gate was stale), so
1959
+ // whether the index is queryable is a per-machine runtime fact. The
1960
+ // catch below is the fallback: any failure (extension unloadable, index
1961
+ // absent, older DB) degrades to the exact scan with a once-per-backend
1962
+ // diagnostic instead of being silently swallowed.
1963
+ try {
1964
+ bestChunks = await collectBestChunks(limit, async (fetchLimit) => {
1965
+ const vectorQuery = `
1841
1966
  CALL QUERY_VECTOR_INDEX('${EMBEDDING_TABLE_NAME}', '${EMBEDDING_INDEX_NAME}',
1842
1967
  CAST(${queryVecStr} AS FLOAT[${dims}]), ${fetchLimit})
1843
1968
  YIELD node AS emb, distance
@@ -1847,27 +1972,25 @@ export class LocalBackend {
1847
1972
  emb.startLine AS startLine, emb.endLine AS endLine, distance
1848
1973
  ORDER BY distance
1849
1974
  `;
1850
- const embResults = await executeQuery(repo.lbugPath, vectorQuery);
1851
- return embResults.map((row) => ({
1852
- nodeId: row.nodeId ?? row[0],
1853
- chunkIndex: row.chunkIndex ?? row[1] ?? 0,
1854
- startLine: row.startLine ?? row[2] ?? 0,
1855
- endLine: row.endLine ?? row[3] ?? 0,
1856
- distance: row.distance ?? row[4],
1857
- }));
1858
- });
1859
- }
1860
- catch {
1861
- bestChunks = new Map();
1862
- }
1975
+ const embResults = await executeQuery(repo.lbugPath, vectorQuery);
1976
+ return embResults.map((row) => ({
1977
+ nodeId: row.nodeId ?? row[0],
1978
+ chunkIndex: row.chunkIndex ?? row[1] ?? 0,
1979
+ startLine: row.startLine ?? row[2] ?? 0,
1980
+ endLine: row.endLine ?? row[3] ?? 0,
1981
+ distance: row.distance ?? row[4],
1982
+ }));
1983
+ });
1863
1984
  }
1864
- else if (!this.warnedVectorUnsupported) {
1865
- // Rare diagnostic: surface why we fell back to the exact scan path so
1866
- // operators can see at a glance that VECTOR is disabled by platform
1867
- // policy. Emitted once per `LocalBackend` instance lifetime to avoid
1868
- // noisy stderr on hot semantic-search paths (DoD §2.8).
1869
- this.warnedVectorUnsupported = true;
1870
- logger.warn('GitNexus [query:vector]: VECTOR extension not supported on this platform; using exact scan fallback');
1985
+ catch (err) {
1986
+ bestChunks = new Map();
1987
+ if (!this.warnedVectorUnsupported) {
1988
+ // Rare diagnostic: surface why semantic search fell back to the
1989
+ // exact scan. Emitted once per `LocalBackend` instance lifetime to
1990
+ // avoid noisy stderr on hot semantic-search paths (DoD §2.8).
1991
+ this.warnedVectorUnsupported = true;
1992
+ logger.warn({ err }, 'GitNexus [query:vector]: vector index query failed; using exact scan fallback');
1993
+ }
1871
1994
  }
1872
1995
  if (bestChunks.size === 0) {
1873
1996
  const embeddingCount = Number(tableCheck[0].cnt ?? tableCheck[0][0] ?? 0);
@@ -1927,8 +2050,20 @@ export class LocalBackend {
1927
2050
  }
1928
2051
  return results;
1929
2052
  }
1930
- catch {
1931
- // Expected when embeddings are disabled — silently fall back to BM25-only
2053
+ catch (err) {
2054
+ // Embeddings disabled is the common, silent case. But a pruned or
2055
+ // Node-unloadable optional stack (#2370/#2372) also lands here — surface it
2056
+ // once so semantic search doesn't silently degrade to BM25 with no hint
2057
+ // (the exact silent-degradation mode #2370 exists to fix). Emitted once per
2058
+ // LocalBackend instance to keep stderr quiet on hot paths (like the VECTOR
2059
+ // fallback above). All other errors stay silent, as before.
2060
+ const message = err instanceof Error ? err.message : '';
2061
+ if (!this.warnedMissingEmbeddingStack &&
2062
+ (isMissingLocalEmbeddingStackMessage(message) ||
2063
+ isLocalEmbeddingRuntimeBlockerMessage(message))) {
2064
+ this.warnedMissingEmbeddingStack = true;
2065
+ logger.warn(`GitNexus [query:vector]: ${message}`);
2066
+ }
1932
2067
  return [];
1933
2068
  }
1934
2069
  }
@@ -2376,7 +2511,7 @@ export class LocalBackend {
2376
2511
  name: c.name,
2377
2512
  kind: c.type,
2378
2513
  filePath: c.filePath,
2379
- line: c.startLine,
2514
+ line: toDisplayLine(c.startLine),
2380
2515
  score: Number(c.score.toFixed(2)),
2381
2516
  })),
2382
2517
  };
@@ -2540,6 +2675,7 @@ export class LocalBackend {
2540
2675
  // "fix" enrichment ordering; F3 depends on enrichment-before-early-return.
2541
2676
  const epistemicSymType = (resolvedLabel || sym.type || symKind || '');
2542
2677
  const epistemicPromise = this.computeEpistemicBoundary(repo, symId, epistemicSymType, (sym.name || sym[1]));
2678
+ const beanMetadataPromise = queryClassBeanMetadata(repo.lbugPath, symId, epistemicSymType);
2543
2679
  let methodMetadata;
2544
2680
  if (isMethodLike) {
2545
2681
  try {
@@ -2575,7 +2711,7 @@ export class LocalBackend {
2575
2711
  // dynamic dispatch are not reflected in `incoming`, so the view is a lower
2576
2712
  // bound. Additive; never suppresses a field. Resolved from the probe started
2577
2713
  // above (concurrent with methodMetadata).
2578
- const epistemic = await epistemicPromise;
2714
+ const [epistemic, beanMetadata] = await Promise.all([epistemicPromise, beanMetadataPromise]);
2579
2715
  return {
2580
2716
  status: 'found',
2581
2717
  symbol: {
@@ -2583,10 +2719,11 @@ export class LocalBackend {
2583
2719
  name: sym.name || sym[1],
2584
2720
  kind: symKind,
2585
2721
  filePath: sym.filePath || sym[3],
2586
- startLine: sym.startLine || sym[4],
2587
- endLine: sym.endLine || sym[5],
2722
+ startLine: toDisplayLine(sym.startLine ?? sym[4]),
2723
+ endLine: toDisplayLine(sym.endLine ?? sym[5]),
2588
2724
  ...(include_content && (sym.content || sym[6]) ? { content: sym.content || sym[6] } : {}),
2589
2725
  ...(methodMetadata ? { methodMetadata } : {}),
2726
+ ...(beanMetadata ? { bean: beanMetadata } : {}),
2590
2727
  },
2591
2728
  ...epistemic,
2592
2729
  incoming: categorize(incomingRows),
@@ -2660,7 +2797,7 @@ export class LocalBackend {
2660
2797
  name: c.name,
2661
2798
  kind: c.type,
2662
2799
  filePath: c.filePath,
2663
- line: c.startLine,
2800
+ line: toDisplayLine(c.startLine),
2664
2801
  score: Number(c.score.toFixed(2)),
2665
2802
  })),
2666
2803
  },
@@ -2678,11 +2815,14 @@ export class LocalBackend {
2678
2815
  return {
2679
2816
  anchorClause: 'a.id STARTS WITH $idPrefix AND a.startLine >= $symStart AND a.startLine <= $symEnd',
2680
2817
  queryParams: { idPrefix, symStart: sym.startLine + 1, symEnd: sym.endLine + 1 },
2818
+ // Display anchor is 1-based, matching the ambiguous-candidate branch and
2819
+ // the context/query/impact tools (#2380). This is display-only — the
2820
+ // BasicBlock join above uses the raw `sym.startLine + 1` in `symStart`.
2681
2821
  anchor: {
2682
2822
  file: sym.filePath,
2683
2823
  symbol: sym.name,
2684
- startLine: sym.startLine,
2685
- endLine: sym.endLine,
2824
+ startLine: toDisplayLine(sym.startLine),
2825
+ endLine: toDisplayLine(sym.endLine),
2686
2826
  },
2687
2827
  };
2688
2828
  }
@@ -3425,7 +3565,10 @@ export class LocalBackend {
3425
3565
  /** Guard: ensure a file path resolves within the repo root (prevents path traversal) */
3426
3566
  const assertSafePath = (filePath) => {
3427
3567
  const full = path.resolve(repo.repoPath, filePath);
3428
- if (!full.startsWith(repo.repoPath + path.sep) && full !== repo.repoPath) {
3568
+ const safePrefix = repo.repoPath.endsWith(path.sep)
3569
+ ? repo.repoPath
3570
+ : repo.repoPath + path.sep;
3571
+ if (!full.startsWith(safePrefix) && full !== repo.repoPath) {
3429
3572
  throw new Error(`Path traversal blocked: ${filePath}`);
3430
3573
  }
3431
3574
  return full;
@@ -3447,28 +3590,13 @@ export class LocalBackend {
3447
3590
  if (oldName === new_name) {
3448
3591
  return { error: 'New name is the same as the current name.' };
3449
3592
  }
3450
- // Step 2: Collect edits from graph (high confidence)
3451
- const changes = new Map();
3452
- const addEdit = (filePath, line, oldText, newText, confidence) => {
3453
- if (!changes.has(filePath)) {
3454
- changes.set(filePath, { file_path: filePath, edits: [] });
3455
- }
3456
- changes.get(filePath).edits.push({ line, old_text: oldText, new_text: newText, confidence });
3457
- };
3458
- // The definition itself
3459
- if (sym.filePath && sym.startLine) {
3460
- try {
3461
- const content = await fs.readFile(assertSafePath(sym.filePath), 'utf-8');
3462
- const lines = content.split('\n');
3463
- const lineIdx = sym.startLine - 1;
3464
- if (lineIdx >= 0 && lineIdx < lines.length && lines[lineIdx].includes(oldName)) {
3465
- const defRegex = new RegExp(`\\b${oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g');
3466
- addEdit(sym.filePath, sym.startLine, lines[lineIdx].trim(), lines[lineIdx].replace(defRegex, new_name).trim(), 'graph');
3467
- }
3468
- }
3469
- catch (e) {
3470
- logQueryError('rename:read-definition', e);
3471
- }
3593
+ const escapedOldName = oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3594
+ // Classify each file to rewrite by how it was discovered. Definition and
3595
+ // graph-ref files carry graph confidence; files found only by text search
3596
+ // carry text_search confidence. A graph-classified file is never downgraded.
3597
+ const fileConfidence = new Map();
3598
+ if (sym.filePath) {
3599
+ fileConfidence.set(sym.filePath, 'graph');
3472
3600
  }
3473
3601
  // All incoming refs from graph (callers, importers, etc.)
3474
3602
  const allIncoming = [
@@ -3477,31 +3605,12 @@ export class LocalBackend {
3477
3605
  ...(lookupResult.incoming.extends || []),
3478
3606
  ...(lookupResult.incoming.implements || []),
3479
3607
  ];
3480
- let graphEdits = changes.size > 0 ? 1 : 0; // count definition edit
3481
3608
  for (const ref of allIncoming) {
3482
- if (!ref.filePath)
3483
- continue;
3484
- try {
3485
- const content = await fs.readFile(assertSafePath(ref.filePath), 'utf-8');
3486
- const lines = content.split('\n');
3487
- for (let i = 0; i < lines.length; i++) {
3488
- if (lines[i].includes(oldName)) {
3489
- addEdit(ref.filePath, i + 1, lines[i].trim(), lines[i]
3490
- .replace(new RegExp(`\\b${oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g'), new_name)
3491
- .trim(), 'graph');
3492
- graphEdits++;
3493
- break; // one edit per file from graph refs
3494
- }
3495
- }
3496
- }
3497
- catch (e) {
3498
- logQueryError('rename:read-ref', e);
3609
+ if (ref.filePath) {
3610
+ fileConfidence.set(ref.filePath, 'graph');
3499
3611
  }
3500
3612
  }
3501
- // Step 3: Text search for refs the graph might have missed
3502
- let astSearchEdits = 0;
3503
- const graphFiles = new Set([sym.filePath, ...allIncoming.map((r) => r.filePath)].filter(Boolean));
3504
- // Simple text search across the repo for the old name (in files not already covered by graph)
3613
+ // Text search for files the graph might have missed entirely.
3505
3614
  try {
3506
3615
  const { execFileSync } = await import('child_process');
3507
3616
  const rgArgs = [
@@ -3527,65 +3636,199 @@ export class LocalBackend {
3527
3636
  .filter((f) => f.length > 0);
3528
3637
  for (const file of files) {
3529
3638
  const normalizedFile = file.replace(/\\/g, '/').replace(/^\.\//, '');
3530
- if (graphFiles.has(normalizedFile))
3531
- continue; // already covered by graph
3532
- try {
3533
- const content = await fs.readFile(assertSafePath(normalizedFile), 'utf-8');
3534
- const lines = content.split('\n');
3535
- const regex = new RegExp(`\\b${oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g');
3536
- for (let i = 0; i < lines.length; i++) {
3537
- regex.lastIndex = 0;
3538
- if (regex.test(lines[i])) {
3539
- regex.lastIndex = 0;
3540
- addEdit(normalizedFile, i + 1, lines[i].trim(), lines[i].replace(regex, new_name).trim(), 'text_search');
3541
- astSearchEdits++;
3542
- }
3543
- }
3544
- }
3545
- catch (e) {
3546
- logQueryError('rename:text-search-read', e);
3639
+ // Never downgrade a graph-classified file to text_search.
3640
+ if (!fileConfidence.has(normalizedFile)) {
3641
+ fileConfidence.set(normalizedFile, 'text_search');
3547
3642
  }
3548
3643
  }
3549
3644
  }
3550
3645
  catch (e) {
3551
3646
  logQueryError('rename:ripgrep', e);
3552
3647
  }
3553
- // Step 4: Apply or preview
3554
- const allChanges = Array.from(changes.values());
3555
- const totalEdits = allChanges.reduce((sum, c) => sum + c.edits.length, 0);
3648
+ // Enumerate every `\boldName\b` line in each file to rewrite, so the previewed
3649
+ // file set is exactly the set the apply loop below rewrites. A file with no
3650
+ // matching line is dropped (apply would write nothing to it). `wordTest`
3651
+ // (non-global) probes each line; `wordReplace` (global) rewrites it and is
3652
+ // reused by the apply loop — compiled once each rather than once per line,
3653
+ // and one escaping formula serves both passes.
3654
+ const wordTest = new RegExp(`\\b${escapedOldName}\\b`);
3655
+ const wordReplace = new RegExp(`\\b${escapedOldName}\\b`, 'g');
3656
+ const changes = new Map();
3657
+ for (const [filePath, confidence] of fileConfidence) {
3658
+ try {
3659
+ const content = await fs.readFile(assertSafePath(filePath), 'utf-8');
3660
+ const lines = content.split('\n');
3661
+ const edits = [];
3662
+ for (let i = 0; i < lines.length; i++) {
3663
+ if (!wordTest.test(lines[i])) {
3664
+ continue;
3665
+ }
3666
+ edits.push({
3667
+ line: i + 1,
3668
+ old_text: lines[i].trim(),
3669
+ new_text: lines[i].replace(wordReplace, new_name).trim(),
3670
+ confidence,
3671
+ });
3672
+ }
3673
+ if (edits.length > 0) {
3674
+ changes.set(filePath, { file_path: filePath, edits });
3675
+ }
3676
+ }
3677
+ catch (e) {
3678
+ logQueryError('rename:enumerate', e);
3679
+ }
3680
+ }
3681
+ // Step 4: Apply or preview.
3556
3682
  const failedFiles = [];
3557
3683
  if (!dry_run) {
3558
- // Apply edits to files
3559
- for (const change of allChanges) {
3684
+ for (const change of changes.values()) {
3560
3685
  try {
3561
3686
  const fullPath = assertSafePath(change.file_path);
3562
- let content = await fs.readFile(fullPath, 'utf-8');
3563
- const regex = new RegExp(`\\b${oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g');
3564
- content = content.replace(regex, new_name);
3565
- await fs.writeFile(fullPath, content, 'utf-8');
3687
+ const content = await fs.readFile(fullPath, 'utf-8');
3688
+ await fs.writeFile(fullPath, content.replace(wordReplace, new_name), 'utf-8');
3566
3689
  }
3567
3690
  catch (e) {
3568
- // A swallowed write failure must not be reported as a full success
3569
- // (#2283): record the file so the result can degrade to 'partial'
3570
- // with the unwritten files listed, rather than masquerading as done.
3691
+ // A swallowed write failure must not be reported as success (#2283):
3692
+ // record the file so the result degrades to 'partial'.
3571
3693
  logQueryError('rename:apply-edit', e);
3572
3694
  failedFiles.push(change.file_path);
3573
3695
  }
3574
3696
  }
3697
+ // A file whose write threw did not land, so drop its edits from the
3698
+ // reported result — total_edits/changes must describe what actually
3699
+ // reached disk, not what was attempted (#2605: the report matches reality
3700
+ // even on partial failure). failed_files still names every dropped file.
3701
+ for (const f of failedFiles) {
3702
+ changes.delete(f);
3703
+ }
3704
+ }
3705
+ // Counts derive from the reported set (dry-run: every enumerated file;
3706
+ // apply: only files that landed), so the graph/text_search split always
3707
+ // sums to total_edits and never overstates a partial apply.
3708
+ const reported = Array.from(changes.values());
3709
+ let graphEdits = 0;
3710
+ let astSearchEdits = 0;
3711
+ for (const change of reported) {
3712
+ for (const edit of change.edits) {
3713
+ if (edit.confidence === 'graph') {
3714
+ graphEdits++;
3715
+ }
3716
+ else {
3717
+ astSearchEdits++;
3718
+ }
3719
+ }
3575
3720
  }
3576
3721
  return {
3577
3722
  status: failedFiles.length > 0 ? 'partial' : 'success',
3578
3723
  old_name: oldName,
3579
3724
  new_name,
3580
- files_affected: allChanges.length,
3581
- total_edits: totalEdits,
3725
+ files_affected: reported.length,
3726
+ total_edits: graphEdits + astSearchEdits,
3582
3727
  graph_edits: graphEdits,
3583
3728
  text_search_edits: astSearchEdits,
3584
- changes: allChanges,
3729
+ changes: reported,
3585
3730
  applied: !dry_run,
3586
3731
  ...(failedFiles.length > 0 && { failed_files: failedFiles }),
3587
3732
  };
3588
3733
  }
3734
+ async moveEntries(repo, params) {
3735
+ await this.ensureInitialized(repo);
3736
+ if (!isLbugReady(repo.lbugPath))
3737
+ return { error: 'LadybugDB not ready. Index may be corrupted.' };
3738
+ const clauses = ["f.language = 'move'"];
3739
+ switch (params?.kind) {
3740
+ case 'entry':
3741
+ clauses.push('f.isEntry = true');
3742
+ break;
3743
+ case 'view':
3744
+ clauses.push('f.isView = true');
3745
+ break;
3746
+ case 'inline':
3747
+ clauses.push('f.isInline = true');
3748
+ break;
3749
+ case 'native':
3750
+ clauses.push('f.isNative = true');
3751
+ break;
3752
+ default:
3753
+ clauses.push('(f.isEntry = true OR f.isView = true)');
3754
+ }
3755
+ const qp = {};
3756
+ if (typeof params?.module === 'string' && params.module) {
3757
+ clauses.push('f.moduleQualifiedName = $module');
3758
+ qp.module = params.module;
3759
+ }
3760
+ const rows = (await executeParameterized(repo.lbugPath, `MATCH (f:Function) WHERE ${clauses.join(' AND ')}
3761
+ RETURN f.name AS name, f.qualifiedName AS qualifiedName, f.filePath AS filePath,
3762
+ f.isEntry AS isEntry, f.isView AS isView,
3763
+ f.isInline AS isInline, f.isNative AS isNative, f.visibility AS visibility,
3764
+ f.acquires AS acquires, f.attributes AS attributes, f.returnType AS returnType
3765
+ ORDER BY f.filePath, f.name`, qp));
3766
+ const attribute = params?.attribute;
3767
+ const filtered = typeof attribute === 'string' && attribute
3768
+ ? rows.filter((r) => Array.isArray(r.attributes) && r.attributes.includes(attribute))
3769
+ : rows;
3770
+ return { entries: filtered, count: filtered.length };
3771
+ }
3772
+ async moveResources(repo, params) {
3773
+ await this.ensureInitialized(repo);
3774
+ if (!isLbugReady(repo.lbugPath))
3775
+ return { error: 'LadybugDB not ready. Index may be corrupted.' };
3776
+ const qp = {};
3777
+ let moduleFilter = '';
3778
+ if (typeof params?.module === 'string' && params.module) {
3779
+ moduleFilter = ' AND s.moduleQualifiedName = $module';
3780
+ qp.module = params.module;
3781
+ }
3782
+ const resourceQuery = (label) => `
3783
+ MATCH (s:\`${label}\`) WHERE s.language = 'move' AND s.isResource = true${moduleFilter}
3784
+ RETURN s.name AS name, s.qualifiedName AS qualifiedName, s.filePath AS filePath,
3785
+ s.abilities AS abilities, s.fieldList AS fieldList
3786
+ ORDER BY s.qualifiedName`;
3787
+ const accessorQuery = (label) => `
3788
+ MATCH (f:Function)-[r:CodeRelation]->(s:\`${label}\`)
3789
+ WHERE s.language = 'move' AND s.isResource = true${moduleFilter}
3790
+ AND (r.type = 'READS_RESOURCE' OR r.type = 'WRITES_RESOURCE' OR r.type = 'ACQUIRES')
3791
+ RETURN s.qualifiedName AS resourceQualifiedName, f.qualifiedName AS caller,
3792
+ r.type AS reason, f.isEntry AS isEntry, f.isView AS isView`;
3793
+ const [structs, enums, structAccessors, enumAccessors] = await Promise.all([
3794
+ executeParameterized(repo.lbugPath, resourceQuery('Struct'), qp),
3795
+ executeParameterized(repo.lbugPath, resourceQuery('Enum'), qp),
3796
+ executeParameterized(repo.lbugPath, accessorQuery('Struct'), qp),
3797
+ executeParameterized(repo.lbugPath, accessorQuery('Enum'), qp),
3798
+ ]);
3799
+ const rows = [...structs, ...enums].sort((a, b) => String(a.qualifiedName).localeCompare(String(b.qualifiedName)));
3800
+ const accessorsByResource = new Map();
3801
+ for (const row of [...structAccessors, ...enumAccessors]) {
3802
+ const resourceQualifiedName = String(row.resourceQualifiedName ?? '');
3803
+ if (!resourceQualifiedName || !row.caller)
3804
+ continue;
3805
+ const accessors = accessorsByResource.get(resourceQualifiedName) ?? [];
3806
+ accessors.push({
3807
+ caller: row.caller,
3808
+ reason: row.reason,
3809
+ isEntry: row.isEntry,
3810
+ isView: row.isView,
3811
+ });
3812
+ accessorsByResource.set(resourceQualifiedName, accessors);
3813
+ }
3814
+ const resources = rows.map((r) => ({
3815
+ ...r,
3816
+ fieldList: Array.isArray(r.fieldList)
3817
+ ? r.fieldList.map((v) => String(v).replace(/^['"]|['"]$/g, ''))
3818
+ : r.fieldList,
3819
+ accessors: accessorsByResource.get(String(r.qualifiedName)) ?? [],
3820
+ }));
3821
+ return { resources, count: resources.length };
3822
+ }
3823
+ async moveImpact(repo, params) {
3824
+ const impactParams = {
3825
+ target: params.target,
3826
+ direction: params.direction ?? 'upstream',
3827
+ maxDepth: params.maxDepth,
3828
+ relationTypes: ['CALLS', 'READS_RESOURCE', 'WRITES_RESOURCE', 'ACQUIRES', 'USES_TYPE'],
3829
+ };
3830
+ return this.impact(repo, impactParams);
3831
+ }
3589
3832
  async trace(repo, params) {
3590
3833
  try {
3591
3834
  return await this._traceImpl(repo, params);
@@ -4016,7 +4259,7 @@ export class LocalBackend {
4016
4259
  name: c.name,
4017
4260
  kind: c.type,
4018
4261
  filePath: c.filePath,
4019
- line: c.startLine,
4262
+ line: toDisplayLine(c.startLine),
4020
4263
  score: Number(c.score.toFixed(2)),
4021
4264
  })),
4022
4265
  };
@@ -4069,7 +4312,7 @@ export class LocalBackend {
4069
4312
  name: c.name,
4070
4313
  kind: c.type,
4071
4314
  filePath: c.filePath,
4072
- line: c.startLine,
4315
+ line: toDisplayLine(c.startLine),
4073
4316
  score: Number(c.score.toFixed(2)),
4074
4317
  impactedCount: summary?.impactedCount ?? 0,
4075
4318
  risk: summary?.risk ?? 'UNKNOWN',
@@ -4462,6 +4705,9 @@ export class LocalBackend {
4462
4705
  const epistemicPromise = opts.skipEpistemic
4463
4706
  ? Promise.resolve({})
4464
4707
  : this.computeEpistemicBoundary(repo, symId, symType, (sym.name || sym[1]));
4708
+ const beanMetadataPromise = opts.skipEpistemic || summaryOnly
4709
+ ? Promise.resolve(undefined)
4710
+ : queryClassBeanMetadata(repo.lbugPath, symId, symType);
4465
4711
  const impacted = [];
4466
4712
  const visited = new Set([symId]);
4467
4713
  const pdgBridgeEvidenceById = new Map();
@@ -4864,13 +5110,14 @@ export class LocalBackend {
4864
5110
  }
4865
5111
  // #1858 — await the epistemic boundary probe kicked off alongside the BFS
4866
5112
  // above. Additive: leaves impactedCount and every existing field untouched.
4867
- const epistemic = await epistemicPromise;
5113
+ const [epistemic, beanMetadata] = await Promise.all([epistemicPromise, beanMetadataPromise]);
4868
5114
  const base = {
4869
5115
  target: {
4870
5116
  id: symId,
4871
5117
  name: sym.name || sym[1],
4872
5118
  type: symType,
4873
5119
  filePath: sym.filePath || sym[2],
5120
+ ...(beanMetadata ? { bean: beanMetadata } : {}),
4874
5121
  },
4875
5122
  direction,
4876
5123
  impactedCount: impacted.length,