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
@@ -17,7 +17,9 @@ import path from 'path';
17
17
  import { NODE_TABLES } from './schema.js';
18
18
  import { RelPairRouter } from './rel-pair-routing.js';
19
19
  import { parseTruthyEnv } from '../ingestion/utils/env.js';
20
+ import { SYMBOL_NODE_LABELS } from '../ingestion/utils/symbol-labels.js';
20
21
  import { applyCjkSegmentationIfEnabled } from '../search/cjk-segmentation.js';
22
+ import { CODE_ELEMENT_COLUMNS, getNodeTableCsvHeader, getNodeTableLayout, hasNodeTableLayout, MULTI_LANG_BASE_COLUMNS, } from './node-table-layout.js';
21
23
  /**
22
24
  * Deterministic output ordering — optional (out-of-core / windowed-resolve
23
25
  * enabler). When `GITNEXUS_SORT_GRAPH_OUTPUT` is set, nodes and relationships
@@ -95,6 +97,35 @@ export const escapeCSVNumber = (value, defaultValue = -1) => {
95
97
  return String(defaultValue);
96
98
  return String(value);
97
99
  };
100
+ /**
101
+ * LadybugDB STRING[] literal inside a quoted CSV field. Elements containing a
102
+ * list metacharacter (' , [ ]) are single-quoted so comma-bearing types like
103
+ * `Table<address, u64>` survive as one element. LadybugDB keeps the quotes on
104
+ * read, so user-facing columns must strip them (see moveResources fieldList).
105
+ */
106
+ export const escapeCSVStringArray = (value) => {
107
+ const items = Array.isArray(value) ? value : [];
108
+ const encoded = items.map((item) => {
109
+ const s = item == null ? '' : String(item);
110
+ return /[',\[\]]/.test(s) ? `'${s.replace(/'/g, "''")}'` : s;
111
+ });
112
+ return escapeCSVField(`[${encoded.join(',')}]`);
113
+ };
114
+ // Truthy coercion, matching the incremental CREATE path (`!!properties.isExported`
115
+ // in lbug-adapter) so bulk and incremental loads classify the same values alike.
116
+ export const escapeCSVBoolean = (value) => {
117
+ return value ? 'true' : 'false';
118
+ };
119
+ const formatCSVStringArray = (value) => {
120
+ const items = Array.isArray(value)
121
+ ? value.filter((item) => typeof item === 'string')
122
+ : [];
123
+ const unsafe = items.find((item) => /[,\[\]'"\n\r]/.test(item));
124
+ if (unsafe !== undefined) {
125
+ throw new Error(`Cannot safely encode CSV string-list item: ${JSON.stringify(unsafe)}`);
126
+ }
127
+ return `[${items.join(',')}]`;
128
+ };
98
129
  // ============================================================================
99
130
  // CONTENT EXTRACTION (lazy — reads from disk on demand)
100
131
  // ============================================================================
@@ -187,6 +218,43 @@ class FileContentCache {
187
218
  export const normalizeFtsText = (text) => text.replace(/[\r\n\t]+/g, ' ');
188
219
  /** Composes both FTS-text transforms for the `description` column — one place for the six emission sites below to call, instead of repeating the composition. */
189
220
  const formatFtsDescription = (description) => normalizeFtsText(applyCjkSegmentationIfEnabled(description));
221
+ /**
222
+ * Encode a row from the same ordered layout that owns its DDL, CSV header,
223
+ * and COPY column list. These tables are shared across languages, so missing
224
+ * optional properties deliberately serialize to typed defaults.
225
+ */
226
+ export const buildLayoutNodeRow = (table, node, content) => {
227
+ const layout = getNodeTableLayout(table);
228
+ return layout.columns
229
+ .map((spec) => {
230
+ const value = node.properties[spec.name] ?? spec.defaultValue;
231
+ switch (spec.csvEncoding) {
232
+ case 'node-id':
233
+ return escapeCSVField(node.id);
234
+ case 'number':
235
+ return escapeCSVNumber(typeof value === 'number' ? value : undefined, typeof spec.defaultValue === 'number' ? spec.defaultValue : -1);
236
+ case 'boolean':
237
+ return escapeCSVBoolean(value);
238
+ case 'string-array':
239
+ return escapeCSVStringArray(value);
240
+ case 'content':
241
+ return escapeCSVField(content);
242
+ case 'description':
243
+ return escapeCSVField(formatFtsDescription(String(value ?? '')));
244
+ case 'string':
245
+ return escapeCSVField(String(value ?? ''));
246
+ default: {
247
+ const _exhaustive = spec.csvEncoding;
248
+ throw new Error(`Unsupported CSV column encoding: ${String(_exhaustive)}`);
249
+ }
250
+ }
251
+ })
252
+ .join(',');
253
+ };
254
+ // Labels that get exact source-span content (no ±2 window). Single source of
255
+ // truth in `symbol-labels.ts` — see there for why the exactness depends on the
256
+ // 0-based line invariant. Kept as a named alias to read intent at the use site.
257
+ const EXACT_SYMBOL_CONTENT_LABELS = SYMBOL_NODE_LABELS;
190
258
  const extractContent = async (node, contentCache) => {
191
259
  const filePath = node.properties.filePath;
192
260
  const content = await contentCache.get(filePath);
@@ -209,8 +277,9 @@ const extractContent = async (node, contentCache) => {
209
277
  if (startLine === undefined || endLine === undefined)
210
278
  return '';
211
279
  const lines = content.split('\n');
212
- const start = Math.max(0, startLine - 2);
213
- const end = Math.min(lines.length - 1, endLine + 2);
280
+ const exactSymbolContent = EXACT_SYMBOL_CONTENT_LABELS.has(node.label);
281
+ const start = Math.max(0, exactSymbolContent ? startLine : startLine - 2);
282
+ const end = Math.min(lines.length - 1, exactSymbolContent ? endLine : endLine + 2);
214
283
  const snippet = lines.slice(start, end + 1).join('\n');
215
284
  const MAX_SNIPPET = 5000;
216
285
  const capped = snippet.length > MAX_SNIPPET ? snippet.slice(0, MAX_SNIPPET) + '\n... [truncated]' : snippet;
@@ -357,9 +426,9 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseCo
357
426
  // Create writers for every node type up-front
358
427
  const fileWriter = new BufferedCSVWriter(path.join(csvDir, 'file.csv'), 'id,name,filePath,content');
359
428
  const folderWriter = new BufferedCSVWriter(path.join(csvDir, 'folder.csv'), 'id,name,filePath');
360
- const codeElementHeader = 'id,name,filePath,startLine,endLine,isExported,content,description';
361
- const functionWriter = new BufferedCSVWriter(path.join(csvDir, 'function.csv'), codeElementHeader);
362
- const classWriter = new BufferedCSVWriter(path.join(csvDir, 'class.csv'), codeElementHeader);
429
+ const codeElementHeader = CODE_ELEMENT_COLUMNS.join(',');
430
+ const functionWriter = new BufferedCSVWriter(path.join(csvDir, 'function.csv'), getNodeTableCsvHeader('Function'));
431
+ const classWriter = new BufferedCSVWriter(path.join(csvDir, 'class.csv'), `${codeElementHeader},frameworkAnnotations`);
363
432
  const interfaceWriter = new BufferedCSVWriter(path.join(csvDir, 'interface.csv'), codeElementHeader);
364
433
  const methodHeader = 'id,name,filePath,startLine,endLine,isExported,content,description,parameterCount,returnType';
365
434
  const methodWriter = new BufferedCSVWriter(path.join(csvDir, 'method.csv'), methodHeader);
@@ -376,10 +445,11 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseCo
376
445
  // blocks are identified by id + source span. Emitted by no phase yet.
377
446
  const basicBlockWriter = new BufferedCSVWriter(path.join(csvDir, 'basicblock.csv'), BASICBLOCK_CSV_HEADER);
378
447
  // Multi-language node types share the same CSV shape (no isExported column)
379
- const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
448
+ const multiLangHeader = MULTI_LANG_BASE_COLUMNS.join(',');
380
449
  const MULTI_LANG_TYPES = [
381
450
  'Struct',
382
451
  'Enum',
452
+ 'EnumVariant',
383
453
  'Macro',
384
454
  'Typedef',
385
455
  'Union',
@@ -401,7 +471,11 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseCo
401
471
  const propertyHeader = 'id,name,filePath,startLine,endLine,content,description,declaredType';
402
472
  const multiLangWriters = new Map();
403
473
  for (const t of MULTI_LANG_TYPES) {
404
- multiLangWriters.set(t, new BufferedCSVWriter(path.join(csvDir, `${t.toLowerCase()}.csv`), t === 'Property' ? propertyHeader : multiLangHeader));
474
+ multiLangWriters.set(t, new BufferedCSVWriter(path.join(csvDir, `${t.toLowerCase()}.csv`), t === 'Property'
475
+ ? propertyHeader
476
+ : hasNodeTableLayout(t)
477
+ ? getNodeTableCsvHeader(t)
478
+ : multiLangHeader));
405
479
  }
406
480
  const codeWriterMap = {
407
481
  Function: functionWriter,
@@ -537,35 +611,58 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseCo
537
611
  const writer = codeWriterMap[node.label];
538
612
  if (writer) {
539
613
  const content = await extractContent(node, contentCache);
540
- pending = writer.addRow([
541
- escapeCSVField(node.id),
542
- escapeCSVField(node.properties.name || ''),
543
- escapeCSVField(node.properties.filePath || ''),
544
- escapeCSVNumber(node.properties.startLine, -1),
545
- escapeCSVNumber(node.properties.endLine, -1),
546
- node.properties.isExported ? 'true' : 'false',
547
- escapeCSVField(content),
548
- escapeCSVField(formatFtsDescription(node.properties.description || '')),
549
- ].join(','));
550
- }
551
- else {
552
- // Multi-language node types (Struct, Impl, Trait, Macro, etc.)
553
- const mlWriter = multiLangWriters.get(node.label);
554
- if (mlWriter) {
555
- const content = await extractContent(node, contentCache);
556
- pending = mlWriter.addRow([
614
+ if (node.label === 'Function') {
615
+ pending = writer.addRow(buildLayoutNodeRow('Function', node, content));
616
+ }
617
+ else if (node.label === 'Class') {
618
+ pending = writer.addRow([
557
619
  escapeCSVField(node.id),
558
620
  escapeCSVField(node.properties.name || ''),
559
621
  escapeCSVField(node.properties.filePath || ''),
560
622
  escapeCSVNumber(node.properties.startLine, -1),
561
623
  escapeCSVNumber(node.properties.endLine, -1),
624
+ node.properties.isExported ? 'true' : 'false',
562
625
  escapeCSVField(content),
563
626
  escapeCSVField(formatFtsDescription(node.properties.description || '')),
564
- ...(node.label === 'Property'
565
- ? [escapeCSVField(node.properties.declaredType || '')]
566
- : []),
627
+ escapeCSVField(formatCSVStringArray(node.properties.frameworkAnnotations)),
567
628
  ].join(','));
568
629
  }
630
+ else {
631
+ pending = writer.addRow([
632
+ escapeCSVField(node.id),
633
+ escapeCSVField(node.properties.name || ''),
634
+ escapeCSVField(node.properties.filePath || ''),
635
+ escapeCSVNumber(node.properties.startLine, -1),
636
+ escapeCSVNumber(node.properties.endLine, -1),
637
+ node.properties.isExported ? 'true' : 'false',
638
+ escapeCSVField(content),
639
+ escapeCSVField(formatFtsDescription(node.properties.description || '')),
640
+ ].join(','));
641
+ }
642
+ }
643
+ else {
644
+ // Multi-language node types (Struct, Impl, Trait, Macro, etc.)
645
+ const mlWriter = multiLangWriters.get(node.label);
646
+ if (mlWriter) {
647
+ const content = await extractContent(node, contentCache);
648
+ if (hasNodeTableLayout(node.label)) {
649
+ pending = mlWriter.addRow(buildLayoutNodeRow(node.label, node, content));
650
+ }
651
+ else {
652
+ pending = mlWriter.addRow([
653
+ escapeCSVField(node.id),
654
+ escapeCSVField(node.properties.name || ''),
655
+ escapeCSVField(node.properties.filePath || ''),
656
+ escapeCSVNumber(node.properties.startLine, -1),
657
+ escapeCSVNumber(node.properties.endLine, -1),
658
+ escapeCSVField(content),
659
+ escapeCSVField(formatFtsDescription(node.properties.description || '')),
660
+ ...(node.label === 'Property'
661
+ ? [escapeCSVField(node.properties.declaredType || '')]
662
+ : []),
663
+ ].join(','));
664
+ }
665
+ }
569
666
  else {
570
667
  // Unknown label: not in codeWriterMap or multiLangWriters, so there
571
668
  // is no CSV table for it and it is intentionally NOT persisted —
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Escape a value for embedding in a single-quoted Cypher string literal.
3
+ *
4
+ * LadybugDB's parser uses backslash escapes and REJECTS SQL-style `''`
5
+ * doubling — `'we''ird'` is a parser error, not an escaped quote (#2409
6
+ * review). Every call site that used doubling produced a query that never
7
+ * parsed; the failures were invisible wherever the site swallowed errors
8
+ * (per-file deletes skipping quoted paths, importer BFS returning [],
9
+ * augment/wiki batch lookups silently missing rows).
10
+ *
11
+ * Backslashes are escaped first, then quotes — reversing the order would
12
+ * double the backslash that the quote escape just introduced. For values
13
+ * inside single-quoted literals only; table/label names go through
14
+ * `escapeTableName` in lbug-adapter instead.
15
+ *
16
+ * NOT for CSV emission: the COPY path (csv-generator.ts) quotes fields for
17
+ * LadybugDB's CSV reader (`ESCAPE='"'`), a different grammar with its own
18
+ * rules — its `''` usages are not this bug.
19
+ */
20
+ export declare const escapeCypherString: (value: string) => string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Escape a value for embedding in a single-quoted Cypher string literal.
3
+ *
4
+ * LadybugDB's parser uses backslash escapes and REJECTS SQL-style `''`
5
+ * doubling — `'we''ird'` is a parser error, not an escaped quote (#2409
6
+ * review). Every call site that used doubling produced a query that never
7
+ * parsed; the failures were invisible wherever the site swallowed errors
8
+ * (per-file deletes skipping quoted paths, importer BFS returning [],
9
+ * augment/wiki batch lookups silently missing rows).
10
+ *
11
+ * Backslashes are escaped first, then quotes — reversing the order would
12
+ * double the backslash that the quote escape just introduced. For values
13
+ * inside single-quoted literals only; table/label names go through
14
+ * `escapeTableName` in lbug-adapter instead.
15
+ *
16
+ * NOT for CSV emission: the COPY path (csv-generator.ts) quotes fields for
17
+ * LadybugDB's CSV reader (`ESCAPE='"'`), a different grammar with its own
18
+ * rules — its `''` usages are not this bug.
19
+ */
20
+ export const escapeCypherString = (value) => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
@@ -0,0 +1,67 @@
1
+ export type ExtensionLoadErrorKind = 'missing_file' | 'corrupt_file' | 'missing_dependency' | 'unknown';
2
+ export interface ExtensionLoadDiagnosis {
3
+ readonly kind: ExtensionLoadErrorKind;
4
+ /** Actionable, literal-English remedy suited to the class. */
5
+ readonly remedy: string;
6
+ }
7
+ /**
8
+ * On-disk file corruption / wrong-platform. FORCE INSTALL re-downloads.
9
+ * Kept byte-identical to `FILE_CORRUPTION_SIGNATURES` in
10
+ * scripts/install-duckdb-extension.mjs (that `.mjs` cannot import this `.ts`;
11
+ * the duplication is deliberate — the two serve different call sites). Note
12
+ * `/not a valid/i` already covers Windows error 193 ("is not a valid Win32
13
+ * application"), so a truncated Windows download is caught here, before the
14
+ * missing-dependency branch.
15
+ */
16
+ export declare const FILE_CORRUPTION_SIGNATURES: readonly RegExp[];
17
+ /**
18
+ * Classify a collapsed LadybugDB LOAD error. Order is most-specific-first and is
19
+ * load-bearing: corrupt-file is tested before missing-dependency so a truncated
20
+ * Windows download (error 193, matched by `/not a valid/i`) routes to
21
+ * FORCE-reinstall rather than to the runtime-install remedy.
22
+ */
23
+ export declare function classifyExtensionLoadError(reason: string | undefined | null, label?: string): ExtensionLoadDiagnosis;
24
+ /** Well-formedness of the extension binary for the host platform + arch. */
25
+ export type ExtensionBinaryState = 'absent' | 'corrupt' | 'valid' | 'indeterminate';
26
+ /**
27
+ * Pull the extension file path out of lbug's load error. lbug's wrapper is
28
+ * English regardless of OS language — `Failed to load library: {path} which is
29
+ * needed by extension: {name}` (real lbug), or the quoted `Failed to load
30
+ * library '{path}': {reason}` variant — so the path is recoverable in any locale.
31
+ * Only paths ending in `.lbug_extension` are accepted, so a regex misfire can
32
+ * never point the inspector at an arbitrary file.
33
+ */
34
+ export declare function extractExtensionPath(reason: string | undefined | null): string | null;
35
+ /**
36
+ * A structural verdict on a binary header. `indeterminate` means the probe could
37
+ * not prove validity OR corruption from what it read (e.g. the PE header sits past
38
+ * the BINARY_HEADER_BYTES window) — the caller defers to the string classifier
39
+ * rather than assert a false verdict.
40
+ */
41
+ type HeaderVerdict = 'valid' | 'corrupt' | 'indeterminate';
42
+ /**
43
+ * Decide whether a binary header is a well-formed shared library for the given
44
+ * platform + architecture — using only the file's structure, no localized text.
45
+ * Pure and injectable (platform/arch as params) so every format+arch combination
46
+ * is unit-testable regardless of the host it runs on.
47
+ */
48
+ export declare function classifyBinaryHeader(buf: Buffer, bytesRead: number, platform: NodeJS.Platform, arch: string): HeaderVerdict;
49
+ /**
50
+ * Best-effort language-independent inspection of the extension file. Reads the
51
+ * header and classifies it; never throws — a missing file is `absent`, an
52
+ * unreadable one is `indeterminate`.
53
+ */
54
+ export declare function inspectExtensionBinary(extensionPath: string | null | undefined): ExtensionBinaryState;
55
+ /**
56
+ * Diagnose a LadybugDB load failure, preferring a LANGUAGE-INDEPENDENT structural
57
+ * check of the extension binary over the localized error text:
58
+ * - file absent → missing_file
59
+ * - present but malformed → corrupt_file (bad magic / wrong architecture)
60
+ * - present and well-formed → missing_dependency (a valid binary the loader rejected)
61
+ * The path comes from lbug's own English wrapper, so this holds in any OS display
62
+ * language. When the file cannot be located or read, it falls back to the string
63
+ * classifier (which still carries the language-independent hedged fallback). This
64
+ * is the entry point every surface should call.
65
+ */
66
+ export declare function diagnoseExtensionLoad(reason: string | undefined | null, label?: string): ExtensionLoadDiagnosis;
67
+ export {};
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Classify a LadybugDB `LOAD EXTENSION` failure into one of four actionable
3
+ * classes and produce an accurate, literal-English remedy.
4
+ *
5
+ * Background (#2374): PR #2375 made the real LadybugDB LOAD error visible
6
+ * (instead of a false "not pre-installed" message). The rc.4 reproduction then
7
+ * showed the remaining defect — on Windows the extension file downloads and
8
+ * INSTALLs fine, but `LoadLibrary` fails with error 126 ("the specified module
9
+ * could not be found" / `找不到指定的模块`) because the extension dynamically
10
+ * imports OpenSSL 3 / MSVC 14 DLLs that ship nowhere. For that class, telling
11
+ * the user to reinstall/redownload is wrong — the file is fine; a *runtime
12
+ * dependency* is missing. This module decides which class an error is so each
13
+ * surface (doctor, --repair-fts, the analyze degrade warning, and
14
+ * ftsDegradedWarning) can emit the right remedy instead of a one-size-fits-all
15
+ * "reinstall over the network".
16
+ *
17
+ * `classifyExtensionLoadError` is pure string logic — no `@ladybugdb/core`
18
+ * import, no filesystem — which keeps `native-check.ts` free of a static lbug
19
+ * dependency. `diagnoseExtensionLoad` layers a LANGUAGE-INDEPENDENT structural
20
+ * check on top: it pulls the extension's file path out of lbug's own (English)
21
+ * wrapper and inspects the binary header directly (PE/ELF/Mach-O magic +
22
+ * architecture), so corrupt-vs-valid is decided by the file itself, not by the
23
+ * localized OS error tail. It reads the file (node:fs core module only, still no
24
+ * lbug) and never throws — any read failure degrades to the string classifier.
25
+ */
26
+ import { closeSync, openSync, readSync } from 'node:fs';
27
+ /** LadybugDB says the extension file was never installed. INSTALL can heal it. */
28
+ const MISSING_FILE_SIGNATURES = [
29
+ /has not been installed/i,
30
+ /not been installed/i,
31
+ ];
32
+ /**
33
+ * On-disk file corruption / wrong-platform. FORCE INSTALL re-downloads.
34
+ * Kept byte-identical to `FILE_CORRUPTION_SIGNATURES` in
35
+ * scripts/install-duckdb-extension.mjs (that `.mjs` cannot import this `.ts`;
36
+ * the duplication is deliberate — the two serve different call sites). Note
37
+ * `/not a valid/i` already covers Windows error 193 ("is not a valid Win32
38
+ * application"), so a truncated Windows download is caught here, before the
39
+ * missing-dependency branch.
40
+ */
41
+ // Exported so a parity test can assert this stays byte-identical to the copy in
42
+ // scripts/install-duckdb-extension.mjs (that `.mjs` cannot import this `.ts`), #2383 F5b.
43
+ export const FILE_CORRUPTION_SIGNATURES = [
44
+ /invalid elf/i,
45
+ /file too short/i,
46
+ /not a valid/i,
47
+ /bad magic/i,
48
+ /wrong architecture/i,
49
+ /mach-o/i,
50
+ /truncat/i,
51
+ ];
52
+ /**
53
+ * A *transitive dependency* of the extension is missing — the file loaded far
54
+ * enough to be found, but a library it needs is absent. Reinstalling the
55
+ * extension is a no-op for this class.
56
+ *
57
+ * WINDOWS CATCH-ALL GUARD (adversarial review): LadybugDB wraps *every* Windows
58
+ * load failure in `Failed to load library … which is needed by extension`, so
59
+ * that generic wrapper must NOT be sufficient — otherwise error 127 (wrong
60
+ * OpenSSL minor / unresolved procedure), 5 (AV/permission lock), and 1114
61
+ * (dependency DllMain failure) would all be mislabeled `missing_dependency` and
62
+ * told to install a runtime, the opposite of their real fix. We key strictly on
63
+ * the specific error-126 tail. Linux/macOS loaders name the missing library
64
+ * directly, so their signals are unambiguous.
65
+ *
66
+ * Localized Windows tails we do not enumerate (French, German, Japanese, …) and
67
+ * mojibake renderings of the Chinese text won't match here — but they still
68
+ * carry lbug's language-independent `Failed to load library` wrapper, so they
69
+ * are caught by the hedged fallback (LOAD_FAILURE_WRAPPER) with a non-committal
70
+ * remedy, never a wrong confident "reinstall" instruction.
71
+ */
72
+ const WINDOWS_MISSING_DEPENDENCY_SIGNATURES = [
73
+ /找不到指定的模块/,
74
+ /specified module could not be found/i,
75
+ ];
76
+ const POSIX_MISSING_DEPENDENCY_SIGNATURES = [
77
+ /cannot open shared object file/i, // Linux ld.so
78
+ /image not found/i, // macOS dyld
79
+ /library not loaded/i, // macOS dyld
80
+ ];
81
+ /**
82
+ * LadybugDB's own English wrapper for a dlopen/LoadLibrary failure
83
+ * (extension.cpp: `Failed to load library: {path} which is needed by extension:
84
+ * {name}`). It is emitted for EVERY extension load failure regardless of the OS
85
+ * display language — the only localized part is the OS-error tail after it. So
86
+ * it is the language-independent fallback signal once the specific tails miss: a
87
+ * French/German/Japanese Windows 126 has a localized tail we cannot enumerate,
88
+ * but it still carries this wrapper. See hedgedLoadFailureRemedy.
89
+ */
90
+ const LOAD_FAILURE_WRAPPER = /failed to load library/i;
91
+ // Remedies are label-parameterized (#2623 follow-up): doctor now live-probes
92
+ // VECTOR through the same classifier, and FTS-specific advice (`--repair-fts`
93
+ // repairs FTS indexes only) must not be dispensed for other extensions.
94
+ const repairFtsHint = (label, lead) => label === 'FTS' ? ` (${lead}\`gitnexus analyze --repair-fts\`)` : '';
95
+ const missingFileRemedy = (label) => `The ${label} extension is not installed. Re-run with network access and ` +
96
+ `GITNEXUS_LBUG_EXTENSION_INSTALL=auto${repairFtsHint(label, 'or ')} to download it.`;
97
+ const corruptFileRemedy = (label) => `The ${label} extension file is present but unreadable (corrupt, truncated, or built for another ` +
98
+ `platform). Re-download it with network access and ` +
99
+ `GITNEXUS_LBUG_EXTENSION_INSTALL=auto${repairFtsHint(label, '')}.`;
100
+ // Single source of truth for the VC++ runtime-install pointer, shared by the
101
+ // Windows-126 and structural missing-dependency remedies so the name/URL cannot
102
+ // drift between them (#2383 F5).
103
+ const VC_REDIST_INSTALL_HINT = 'the Microsoft Visual C++ 2015-2022 Redistributable (x64) from ' +
104
+ 'https://aka.ms/vs/17/release/vc_redist.x64.exe';
105
+ // MSVC-first per DuckDB's canonical answer for this exact error; OpenSSL second.
106
+ const windowsMissingDependencyRemedy = (label) => `The ${label} extension is present but a required runtime library is missing (Windows error 126). ` +
107
+ 'Reinstalling the extension will NOT help. Install ' +
108
+ VC_REDIST_INSTALL_HINT +
109
+ '; if the error persists, the extension also needs OpenSSL 3 ' +
110
+ '(libcrypto-3-x64.dll / libssl-3-x64.dll) on the DLL search path.';
111
+ const posixMissingDependencyRemedy = (label) => `The ${label} extension is present but a shared library it depends on could not be loaded (named in ` +
112
+ 'the error above). Reinstalling the extension will NOT help — install that library or add it to ' +
113
+ 'your loader search path.';
114
+ // Language-independent fallback: we know the extension failed to load, but the
115
+ // OS-error tail is in a locale we did not enumerate, so we cannot say which class
116
+ // it is. Hedge honestly — point at the user's own localized error and give both
117
+ // branches — rather than confidently prescribing the wrong single fix. The clean
118
+ // long-term fix is upstream: have LadybugDB include the numeric GetLastError/errno
119
+ // in the message (as it already does elsewhere), so this becomes a code match.
120
+ const hedgedLoadFailureRemedy = (label) => `The ${label} extension file was found but could not be loaded — see the "Error:" text above (shown ` +
121
+ "in your system's language). Reinstalling usually will not help. If it names a missing module or " +
122
+ 'library, install the required runtime (on Windows: the Microsoft Visual C++ 2015-2022 ' +
123
+ 'Redistributable x64 and OpenSSL 3); if it names a corrupt or invalid file, ' +
124
+ (label === 'FTS'
125
+ ? 'run `gitnexus analyze --repair-fts` to re-download.'
126
+ : 're-run analyze with network access and GITNEXUS_LBUG_EXTENSION_INSTALL=auto to re-download.');
127
+ const unknownRemedy = (label) => `The ${label} extension failed to load for an unrecognized reason. Run \`gitnexus doctor\` for live ` +
128
+ `${label} status and verify the extension file and platform.`;
129
+ const matchesAny = (reason, signatures) => signatures.some((re) => re.test(reason));
130
+ /**
131
+ * Classify a collapsed LadybugDB LOAD error. Order is most-specific-first and is
132
+ * load-bearing: corrupt-file is tested before missing-dependency so a truncated
133
+ * Windows download (error 193, matched by `/not a valid/i`) routes to
134
+ * FORCE-reinstall rather than to the runtime-install remedy.
135
+ */
136
+ export function classifyExtensionLoadError(reason, label = 'FTS') {
137
+ const text = reason ?? '';
138
+ if (matchesAny(text, MISSING_FILE_SIGNATURES)) {
139
+ return { kind: 'missing_file', remedy: missingFileRemedy(label) };
140
+ }
141
+ if (matchesAny(text, FILE_CORRUPTION_SIGNATURES)) {
142
+ return { kind: 'corrupt_file', remedy: corruptFileRemedy(label) };
143
+ }
144
+ if (matchesAny(text, WINDOWS_MISSING_DEPENDENCY_SIGNATURES)) {
145
+ return { kind: 'missing_dependency', remedy: windowsMissingDependencyRemedy(label) };
146
+ }
147
+ if (matchesAny(text, POSIX_MISSING_DEPENDENCY_SIGNATURES)) {
148
+ return { kind: 'missing_dependency', remedy: posixMissingDependencyRemedy(label) };
149
+ }
150
+ // Language-independent fallback: the extension demonstrably failed to load
151
+ // (lbug's English wrapper is present) but the localized OS tail matched no
152
+ // specific class. Treat as a dependency/runtime load failure with a hedged
153
+ // remedy — strictly better than the generic `unknown` for non-English hosts,
154
+ // and it never prescribes the wrong fix.
155
+ if (LOAD_FAILURE_WRAPPER.test(text)) {
156
+ return { kind: 'missing_dependency', remedy: hedgedLoadFailureRemedy(label) };
157
+ }
158
+ return { kind: 'unknown', remedy: unknownRemedy(label) };
159
+ }
160
+ const structuralMissingDependencyRemedy = (label) => `The ${label} extension file is valid, so the failure is a missing or incompatible runtime dependency, ` +
161
+ 'not the extension itself — reinstalling will NOT help. On Windows, install ' +
162
+ VC_REDIST_INSTALL_HINT +
163
+ ' and ensure OpenSSL 3 is available; on Linux/macOS install the shared library named in the error above.';
164
+ /**
165
+ * Pull the extension file path out of lbug's load error. lbug's wrapper is
166
+ * English regardless of OS language — `Failed to load library: {path} which is
167
+ * needed by extension: {name}` (real lbug), or the quoted `Failed to load
168
+ * library '{path}': {reason}` variant — so the path is recoverable in any locale.
169
+ * Only paths ending in `.lbug_extension` are accepted, so a regex misfire can
170
+ * never point the inspector at an arbitrary file.
171
+ */
172
+ export function extractExtensionPath(reason) {
173
+ const text = reason ?? '';
174
+ const m = /failed to load library:?\s*['"]?(.+?\.lbug_extension)/i.exec(text);
175
+ const path = m?.[1]?.trim();
176
+ return path && path.length > 0 ? path : null;
177
+ }
178
+ /** Node `process.arch` → PE `Machine`. Undefined for arches we don't map. */
179
+ const PE_MACHINE = { x64: 0x8664, arm64: 0xaa64 };
180
+ /** Node `process.arch` → ELF `e_machine`. */
181
+ const ELF_MACHINE = { x64: 0x3e, arm64: 0xb7 };
182
+ /** Node `process.arch` → Mach-O `cputype`. */
183
+ const MACHO_CPUTYPE = { x64: 0x01000007, arm64: 0x0100000c };
184
+ function classifyPE(buf, bytesRead, arch) {
185
+ if (bytesRead < 0x40 || buf[0] !== 0x4d || buf[1] !== 0x5a)
186
+ return 'corrupt'; // 'MZ'
187
+ const peOffset = buf.readUInt32LE(0x3c);
188
+ // The PE header (e_lfanew) points beyond what we read. A large-DOS-stub VALID PE
189
+ // and a garbage e_lfanew are indistinguishable from here, so don't claim 'corrupt'
190
+ // — defer to the loader's own report (#2383 F1-secondary).
191
+ if (peOffset + 6 > bytesRead)
192
+ return 'indeterminate';
193
+ const isPE = buf[peOffset] === 0x50 &&
194
+ buf[peOffset + 1] === 0x45 &&
195
+ buf[peOffset + 2] === 0 &&
196
+ buf[peOffset + 3] === 0;
197
+ if (!isPE)
198
+ return 'corrupt';
199
+ const expected = PE_MACHINE[arch];
200
+ if (expected === undefined)
201
+ return 'valid'; // arch we don't map: don't claim corrupt
202
+ return buf.readUInt16LE(peOffset + 4) === expected ? 'valid' : 'corrupt';
203
+ }
204
+ function classifyELF(buf, bytesRead, arch) {
205
+ if (bytesRead < 20)
206
+ return 'corrupt';
207
+ if (buf[0] !== 0x7f || buf[1] !== 0x45 || buf[2] !== 0x4c || buf[3] !== 0x46)
208
+ return 'corrupt'; // 0x7F ELF
209
+ const littleEndian = buf[5] === 1; // EI_DATA
210
+ const eMachine = littleEndian ? buf.readUInt16LE(18) : buf.readUInt16BE(18);
211
+ const expected = ELF_MACHINE[arch];
212
+ if (expected === undefined)
213
+ return 'valid';
214
+ return eMachine === expected ? 'valid' : 'corrupt';
215
+ }
216
+ function classifyMachO(buf, bytesRead, arch) {
217
+ if (bytesRead < 8)
218
+ return 'corrupt';
219
+ const magicLE = buf.readUInt32LE(0);
220
+ const magicBE = buf.readUInt32BE(0);
221
+ // Universal ("fat") binary — assume it carries the host slice.
222
+ if (magicBE === 0xcafebabe || magicLE === 0xcafebabe)
223
+ return 'valid';
224
+ const thin = magicLE === 0xfeedfacf || magicLE === 0xfeedface;
225
+ const thinSwapped = magicBE === 0xfeedfacf || magicBE === 0xfeedface;
226
+ if (!thin && !thinSwapped)
227
+ return 'corrupt';
228
+ const cpuType = thin ? buf.readUInt32LE(4) : buf.readUInt32BE(4);
229
+ const expected = MACHO_CPUTYPE[arch];
230
+ if (expected === undefined)
231
+ return 'valid';
232
+ return cpuType === expected ? 'valid' : 'corrupt';
233
+ }
234
+ /**
235
+ * Decide whether a binary header is a well-formed shared library for the given
236
+ * platform + architecture — using only the file's structure, no localized text.
237
+ * Pure and injectable (platform/arch as params) so every format+arch combination
238
+ * is unit-testable regardless of the host it runs on.
239
+ */
240
+ export function classifyBinaryHeader(buf, bytesRead, platform, arch) {
241
+ if (platform === 'win32')
242
+ return classifyPE(buf, bytesRead, arch);
243
+ if (platform === 'linux')
244
+ return classifyELF(buf, bytesRead, arch);
245
+ if (platform === 'darwin')
246
+ return classifyMachO(buf, bytesRead, arch);
247
+ return 'valid'; // unknown host: never claim corrupt
248
+ }
249
+ const BINARY_HEADER_BYTES = 4096;
250
+ /**
251
+ * Best-effort language-independent inspection of the extension file. Reads the
252
+ * header and classifies it; never throws — a missing file is `absent`, an
253
+ * unreadable one is `indeterminate`.
254
+ */
255
+ export function inspectExtensionBinary(extensionPath) {
256
+ if (!extensionPath)
257
+ return 'indeterminate';
258
+ let fd;
259
+ try {
260
+ fd = openSync(extensionPath, 'r');
261
+ }
262
+ catch (err) {
263
+ return err?.code === 'ENOENT' ? 'absent' : 'indeterminate';
264
+ }
265
+ try {
266
+ const buf = Buffer.alloc(BINARY_HEADER_BYTES);
267
+ const bytesRead = readSync(fd, buf, 0, BINARY_HEADER_BYTES, 0);
268
+ return classifyBinaryHeader(buf, bytesRead, process.platform, process.arch);
269
+ }
270
+ catch {
271
+ return 'indeterminate';
272
+ }
273
+ finally {
274
+ try {
275
+ closeSync(fd);
276
+ }
277
+ catch {
278
+ /* closing the probe fd must never surface */
279
+ }
280
+ }
281
+ }
282
+ /**
283
+ * Diagnose a LadybugDB load failure, preferring a LANGUAGE-INDEPENDENT structural
284
+ * check of the extension binary over the localized error text:
285
+ * - file absent → missing_file
286
+ * - present but malformed → corrupt_file (bad magic / wrong architecture)
287
+ * - present and well-formed → missing_dependency (a valid binary the loader rejected)
288
+ * The path comes from lbug's own English wrapper, so this holds in any OS display
289
+ * language. When the file cannot be located or read, it falls back to the string
290
+ * classifier (which still carries the language-independent hedged fallback). This
291
+ * is the entry point every surface should call.
292
+ */
293
+ export function diagnoseExtensionLoad(reason, label = 'FTS') {
294
+ const text = reason ?? '';
295
+ const stringResult = classifyExtensionLoadError(text, label);
296
+ const fileState = inspectExtensionBinary(extractExtensionPath(text));
297
+ if (fileState === 'corrupt') {
298
+ return { kind: 'corrupt_file', remedy: corruptFileRemedy(label) };
299
+ }
300
+ if (fileState === 'valid') {
301
+ // The structural probe only inspects the first BINARY_HEADER_BYTES, so a file
302
+ // truncated AFTER its header still reads 'valid'. When the loader itself reported
303
+ // corruption (e.g. "file too short" / Windows error 193 "not a valid Win32
304
+ // application"), that whole-file verdict is stronger evidence than an intact-looking
305
+ // header — honor it and route to re-download, not a runtime-dependency install (#2383
306
+ // F1). Localized corrupt tails classify as hedged missing_dependency (not
307
+ // corrupt_file), so they still fall through to the dependency remedy below.
308
+ if (stringResult.kind === 'corrupt_file') {
309
+ return stringResult;
310
+ }
311
+ // A structurally sound binary that still failed to load ⇒ a dependency/runtime
312
+ // problem, decided WITHOUT the localized tail. Keep the string classifier's
313
+ // sharper remedy when it recognized the specific case (e.g. English 126).
314
+ const remedy = stringResult.kind === 'missing_dependency'
315
+ ? stringResult.remedy
316
+ : structuralMissingDependencyRemedy(label);
317
+ return { kind: 'missing_dependency', remedy };
318
+ }
319
+ // 'absent' or 'indeterminate' → no positive structural evidence, so defer to the
320
+ // string classifier. Note a real never-installed extension has NO path in its
321
+ // reason (lbug says "has not been installed"), so it lands here via
322
+ // 'indeterminate' and the string classifier reports missing_file correctly; a
323
+ // path that lbug named but that is now gone (stale/racy) is better judged by
324
+ // what lbug actually reported than by re-deriving from disk.
325
+ return stringResult;
326
+ }