@creeperhost/modlens-mcp 1.6.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 (382) hide show
  1. package/README.md +938 -0
  2. package/dist/access-flags.d.ts +58 -0
  3. package/dist/access-flags.d.ts.map +1 -0
  4. package/dist/access-flags.js +79 -0
  5. package/dist/access-flags.js.map +1 -0
  6. package/dist/access-flags.test.d.ts +2 -0
  7. package/dist/access-flags.test.d.ts.map +1 -0
  8. package/dist/access-flags.test.js +189 -0
  9. package/dist/access-flags.test.js.map +1 -0
  10. package/dist/batch-ingest.d.ts +2 -0
  11. package/dist/batch-ingest.d.ts.map +1 -0
  12. package/dist/batch-ingest.js +54 -0
  13. package/dist/batch-ingest.js.map +1 -0
  14. package/dist/batch-resolve-mixins.d.ts +2 -0
  15. package/dist/batch-resolve-mixins.d.ts.map +1 -0
  16. package/dist/batch-resolve-mixins.js +36 -0
  17. package/dist/batch-resolve-mixins.js.map +1 -0
  18. package/dist/cache.d.ts +16 -0
  19. package/dist/cache.d.ts.map +1 -0
  20. package/dist/cache.js +36 -0
  21. package/dist/cache.js.map +1 -0
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.d.ts.map +1 -0
  24. package/dist/cli.js +1318 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/curseforge.d.ts +53 -0
  27. package/dist/curseforge.d.ts.map +1 -0
  28. package/dist/curseforge.js +104 -0
  29. package/dist/curseforge.js.map +1 -0
  30. package/dist/db-backend.d.ts +17 -0
  31. package/dist/db-backend.d.ts.map +1 -0
  32. package/dist/db-backend.js +40 -0
  33. package/dist/db-backend.js.map +1 -0
  34. package/dist/db.d.ts +11 -0
  35. package/dist/db.d.ts.map +1 -0
  36. package/dist/db.js +55 -0
  37. package/dist/db.js.map +1 -0
  38. package/dist/embed-queue.d.ts +12 -0
  39. package/dist/embed-queue.d.ts.map +1 -0
  40. package/dist/embed-queue.js +103 -0
  41. package/dist/embed-queue.js.map +1 -0
  42. package/dist/embeddings.d.ts +21 -0
  43. package/dist/embeddings.d.ts.map +1 -0
  44. package/dist/embeddings.js +55 -0
  45. package/dist/embeddings.js.map +1 -0
  46. package/dist/env-path.d.ts +19 -0
  47. package/dist/env-path.d.ts.map +1 -0
  48. package/dist/env-path.js +40 -0
  49. package/dist/env-path.js.map +1 -0
  50. package/dist/fetch-utils.d.ts +24 -0
  51. package/dist/fetch-utils.d.ts.map +1 -0
  52. package/dist/fetch-utils.js +73 -0
  53. package/dist/fetch-utils.js.map +1 -0
  54. package/dist/fetch-utils.test.d.ts +2 -0
  55. package/dist/fetch-utils.test.d.ts.map +1 -0
  56. package/dist/fetch-utils.test.js +133 -0
  57. package/dist/fetch-utils.test.js.map +1 -0
  58. package/dist/generated/sqlite/browser.d.ts +55 -0
  59. package/dist/generated/sqlite/browser.d.ts.map +1 -0
  60. package/dist/generated/sqlite/browser.js +18 -0
  61. package/dist/generated/sqlite/browser.js.map +1 -0
  62. package/dist/generated/sqlite/client.d.ts +72 -0
  63. package/dist/generated/sqlite/client.d.ts.map +1 -0
  64. package/dist/generated/sqlite/client.js +33 -0
  65. package/dist/generated/sqlite/client.js.map +1 -0
  66. package/dist/generated/sqlite/commonInputTypes.d.ts +387 -0
  67. package/dist/generated/sqlite/commonInputTypes.d.ts.map +1 -0
  68. package/dist/generated/sqlite/commonInputTypes.js +11 -0
  69. package/dist/generated/sqlite/commonInputTypes.js.map +1 -0
  70. package/dist/generated/sqlite/enums.d.ts +2 -0
  71. package/dist/generated/sqlite/enums.d.ts.map +1 -0
  72. package/dist/generated/sqlite/enums.js +11 -0
  73. package/dist/generated/sqlite/enums.js.map +1 -0
  74. package/dist/generated/sqlite/internal/class.d.ts +226 -0
  75. package/dist/generated/sqlite/internal/class.d.ts.map +1 -0
  76. package/dist/generated/sqlite/internal/class.js +84 -0
  77. package/dist/generated/sqlite/internal/class.js.map +1 -0
  78. package/dist/generated/sqlite/internal/prismaNamespace.d.ts +1344 -0
  79. package/dist/generated/sqlite/internal/prismaNamespace.d.ts.map +1 -0
  80. package/dist/generated/sqlite/internal/prismaNamespace.js +220 -0
  81. package/dist/generated/sqlite/internal/prismaNamespace.js.map +1 -0
  82. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts +204 -0
  83. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts.map +1 -0
  84. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js +191 -0
  85. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js.map +1 -0
  86. package/dist/generated/sqlite/models/DocEntry.d.ts +1223 -0
  87. package/dist/generated/sqlite/models/DocEntry.d.ts.map +1 -0
  88. package/dist/generated/sqlite/models/DocEntry.js +2 -0
  89. package/dist/generated/sqlite/models/DocEntry.js.map +1 -0
  90. package/dist/generated/sqlite/models/McSourceFile.d.ts +1289 -0
  91. package/dist/generated/sqlite/models/McSourceFile.d.ts.map +1 -0
  92. package/dist/generated/sqlite/models/McSourceFile.js +2 -0
  93. package/dist/generated/sqlite/models/McSourceFile.js.map +1 -0
  94. package/dist/generated/sqlite/models/McVersion.d.ts +1315 -0
  95. package/dist/generated/sqlite/models/McVersion.d.ts.map +1 -0
  96. package/dist/generated/sqlite/models/McVersion.js +2 -0
  97. package/dist/generated/sqlite/models/McVersion.js.map +1 -0
  98. package/dist/generated/sqlite/models/McVersionDiff.d.ts +1061 -0
  99. package/dist/generated/sqlite/models/McVersionDiff.d.ts.map +1 -0
  100. package/dist/generated/sqlite/models/McVersionDiff.js +2 -0
  101. package/dist/generated/sqlite/models/McVersionDiff.js.map +1 -0
  102. package/dist/generated/sqlite/models/Mod.d.ts +2396 -0
  103. package/dist/generated/sqlite/models/Mod.d.ts.map +1 -0
  104. package/dist/generated/sqlite/models/Mod.js +2 -0
  105. package/dist/generated/sqlite/models/Mod.js.map +1 -0
  106. package/dist/generated/sqlite/models/ModClass.d.ts +1254 -0
  107. package/dist/generated/sqlite/models/ModClass.d.ts.map +1 -0
  108. package/dist/generated/sqlite/models/ModClass.js +2 -0
  109. package/dist/generated/sqlite/models/ModClass.js.map +1 -0
  110. package/dist/generated/sqlite/models/ModSourceFile.d.ts +1283 -0
  111. package/dist/generated/sqlite/models/ModSourceFile.d.ts.map +1 -0
  112. package/dist/generated/sqlite/models/ModSourceFile.js +2 -0
  113. package/dist/generated/sqlite/models/ModSourceFile.js.map +1 -0
  114. package/dist/generated/sqlite/models/ModTag.d.ts +1278 -0
  115. package/dist/generated/sqlite/models/ModTag.d.ts.map +1 -0
  116. package/dist/generated/sqlite/models/ModTag.js +2 -0
  117. package/dist/generated/sqlite/models/ModTag.js.map +1 -0
  118. package/dist/generated/sqlite/models/ModVersionDiff.d.ts +1073 -0
  119. package/dist/generated/sqlite/models/ModVersionDiff.d.ts.map +1 -0
  120. package/dist/generated/sqlite/models/ModVersionDiff.js +2 -0
  121. package/dist/generated/sqlite/models/ModVersionDiff.js.map +1 -0
  122. package/dist/generated/sqlite/models/Primer.d.ts +1319 -0
  123. package/dist/generated/sqlite/models/Primer.d.ts.map +1 -0
  124. package/dist/generated/sqlite/models/Primer.js +2 -0
  125. package/dist/generated/sqlite/models/Primer.js.map +1 -0
  126. package/dist/generated/sqlite/models.d.ts +12 -0
  127. package/dist/generated/sqlite/models.d.ts.map +1 -0
  128. package/dist/generated/sqlite/models.js +2 -0
  129. package/dist/generated/sqlite/models.js.map +1 -0
  130. package/dist/jar.d.ts +7 -0
  131. package/dist/jar.d.ts.map +1 -0
  132. package/dist/jar.js +52 -0
  133. package/dist/jar.js.map +1 -0
  134. package/dist/java-tools.d.ts +46 -0
  135. package/dist/java-tools.d.ts.map +1 -0
  136. package/dist/java-tools.js +263 -0
  137. package/dist/java-tools.js.map +1 -0
  138. package/dist/launcher.d.ts +3 -0
  139. package/dist/launcher.d.ts.map +1 -0
  140. package/dist/launcher.js +105 -0
  141. package/dist/launcher.js.map +1 -0
  142. package/dist/mappings.d.ts +95 -0
  143. package/dist/mappings.d.ts.map +1 -0
  144. package/dist/mappings.js +1094 -0
  145. package/dist/mappings.js.map +1 -0
  146. package/dist/mappings.test.d.ts +2 -0
  147. package/dist/mappings.test.d.ts.map +1 -0
  148. package/dist/mappings.test.js +161 -0
  149. package/dist/mappings.test.js.map +1 -0
  150. package/dist/minecraft.d.ts +21 -0
  151. package/dist/minecraft.d.ts.map +1 -0
  152. package/dist/minecraft.js +70 -0
  153. package/dist/minecraft.js.map +1 -0
  154. package/dist/modpacks-ch.d.ts +224 -0
  155. package/dist/modpacks-ch.d.ts.map +1 -0
  156. package/dist/modpacks-ch.js +146 -0
  157. package/dist/modpacks-ch.js.map +1 -0
  158. package/dist/modrinth.d.ts +67 -0
  159. package/dist/modrinth.d.ts.map +1 -0
  160. package/dist/modrinth.js +88 -0
  161. package/dist/modrinth.js.map +1 -0
  162. package/dist/platform-adapter.d.ts +23 -0
  163. package/dist/platform-adapter.d.ts.map +1 -0
  164. package/dist/platform-adapter.js +2 -0
  165. package/dist/platform-adapter.js.map +1 -0
  166. package/dist/platform.d.ts +47 -0
  167. package/dist/platform.d.ts.map +1 -0
  168. package/dist/platform.js +175 -0
  169. package/dist/platform.js.map +1 -0
  170. package/dist/processor.d.ts +51 -0
  171. package/dist/processor.d.ts.map +1 -0
  172. package/dist/processor.js +655 -0
  173. package/dist/processor.js.map +1 -0
  174. package/dist/processor.test.d.ts +2 -0
  175. package/dist/processor.test.d.ts.map +1 -0
  176. package/dist/processor.test.js +629 -0
  177. package/dist/processor.test.js.map +1 -0
  178. package/dist/repositories/embeddings-sqlite.d.ts +38 -0
  179. package/dist/repositories/embeddings-sqlite.d.ts.map +1 -0
  180. package/dist/repositories/embeddings-sqlite.js +208 -0
  181. package/dist/repositories/embeddings-sqlite.js.map +1 -0
  182. package/dist/repositories/embeddings.d.ts +40 -0
  183. package/dist/repositories/embeddings.d.ts.map +1 -0
  184. package/dist/repositories/embeddings.js +136 -0
  185. package/dist/repositories/embeddings.js.map +1 -0
  186. package/dist/repositories/index.d.ts +2 -0
  187. package/dist/repositories/index.d.ts.map +1 -0
  188. package/dist/repositories/index.js +15 -0
  189. package/dist/repositories/index.js.map +1 -0
  190. package/dist/repositories/mcVersion.d.ts +16 -0
  191. package/dist/repositories/mcVersion.d.ts.map +1 -0
  192. package/dist/repositories/mcVersion.js +52 -0
  193. package/dist/repositories/mcVersion.js.map +1 -0
  194. package/dist/repositories/mod.d.ts +241 -0
  195. package/dist/repositories/mod.d.ts.map +1 -0
  196. package/dist/repositories/mod.js +342 -0
  197. package/dist/repositories/mod.js.map +1 -0
  198. package/dist/repositories/packs.d.ts +44 -0
  199. package/dist/repositories/packs.d.ts.map +1 -0
  200. package/dist/repositories/packs.js +138 -0
  201. package/dist/repositories/packs.js.map +1 -0
  202. package/dist/search-adapter.d.ts +34 -0
  203. package/dist/search-adapter.d.ts.map +1 -0
  204. package/dist/search-adapter.js +195 -0
  205. package/dist/search-adapter.js.map +1 -0
  206. package/dist/search.d.ts +6 -0
  207. package/dist/search.d.ts.map +1 -0
  208. package/dist/search.js +54 -0
  209. package/dist/search.js.map +1 -0
  210. package/dist/search.test.d.ts +2 -0
  211. package/dist/search.test.d.ts.map +1 -0
  212. package/dist/search.test.js +71 -0
  213. package/dist/search.test.js.map +1 -0
  214. package/dist/security.d.ts +98 -0
  215. package/dist/security.d.ts.map +1 -0
  216. package/dist/security.js +446 -0
  217. package/dist/security.js.map +1 -0
  218. package/dist/security.test.d.ts +2 -0
  219. package/dist/security.test.d.ts.map +1 -0
  220. package/dist/security.test.js +687 -0
  221. package/dist/security.test.js.map +1 -0
  222. package/dist/server.d.ts +2 -0
  223. package/dist/server.d.ts.map +1 -0
  224. package/dist/server.js +1465 -0
  225. package/dist/server.js.map +1 -0
  226. package/dist/setup.d.ts +2 -0
  227. package/dist/setup.d.ts.map +1 -0
  228. package/dist/setup.js +1113 -0
  229. package/dist/setup.js.map +1 -0
  230. package/dist/tools/bytecode.d.ts +129 -0
  231. package/dist/tools/bytecode.d.ts.map +1 -0
  232. package/dist/tools/bytecode.js +679 -0
  233. package/dist/tools/bytecode.js.map +1 -0
  234. package/dist/tools/catalog.d.ts +54 -0
  235. package/dist/tools/catalog.d.ts.map +1 -0
  236. package/dist/tools/catalog.js +249 -0
  237. package/dist/tools/catalog.js.map +1 -0
  238. package/dist/tools/compat-check.d.ts +23 -0
  239. package/dist/tools/compat-check.d.ts.map +1 -0
  240. package/dist/tools/compat-check.js +250 -0
  241. package/dist/tools/compat-check.js.map +1 -0
  242. package/dist/tools/compat-check.test.d.ts +2 -0
  243. package/dist/tools/compat-check.test.d.ts.map +1 -0
  244. package/dist/tools/compat-check.test.js +179 -0
  245. package/dist/tools/compat-check.test.js.map +1 -0
  246. package/dist/tools/diagnostics.d.ts +10 -0
  247. package/dist/tools/diagnostics.d.ts.map +1 -0
  248. package/dist/tools/diagnostics.js +133 -0
  249. package/dist/tools/diagnostics.js.map +1 -0
  250. package/dist/tools/diagnostics.test.d.ts +2 -0
  251. package/dist/tools/diagnostics.test.d.ts.map +1 -0
  252. package/dist/tools/diagnostics.test.js +168 -0
  253. package/dist/tools/diagnostics.test.js.map +1 -0
  254. package/dist/tools/docs.d.ts +19 -0
  255. package/dist/tools/docs.d.ts.map +1 -0
  256. package/dist/tools/docs.js +230 -0
  257. package/dist/tools/docs.js.map +1 -0
  258. package/dist/tools/embed-registry.d.ts +125 -0
  259. package/dist/tools/embed-registry.d.ts.map +1 -0
  260. package/dist/tools/embed-registry.js +560 -0
  261. package/dist/tools/embed-registry.js.map +1 -0
  262. package/dist/tools/gradle.d.ts +16 -0
  263. package/dist/tools/gradle.d.ts.map +1 -0
  264. package/dist/tools/gradle.js +182 -0
  265. package/dist/tools/gradle.js.map +1 -0
  266. package/dist/tools/graphify.d.ts +144 -0
  267. package/dist/tools/graphify.d.ts.map +1 -0
  268. package/dist/tools/graphify.js +798 -0
  269. package/dist/tools/graphify.js.map +1 -0
  270. package/dist/tools/graphify.test.d.ts +2 -0
  271. package/dist/tools/graphify.test.d.ts.map +1 -0
  272. package/dist/tools/graphify.test.js +39 -0
  273. package/dist/tools/graphify.test.js.map +1 -0
  274. package/dist/tools/ingest.d.ts +85 -0
  275. package/dist/tools/ingest.d.ts.map +1 -0
  276. package/dist/tools/ingest.js +477 -0
  277. package/dist/tools/ingest.js.map +1 -0
  278. package/dist/tools/ingest.test.d.ts +2 -0
  279. package/dist/tools/ingest.test.d.ts.map +1 -0
  280. package/dist/tools/ingest.test.js +340 -0
  281. package/dist/tools/ingest.test.js.map +1 -0
  282. package/dist/tools/kubejs.d.ts +37 -0
  283. package/dist/tools/kubejs.d.ts.map +1 -0
  284. package/dist/tools/kubejs.js +245 -0
  285. package/dist/tools/kubejs.js.map +1 -0
  286. package/dist/tools/mappings.d.ts +17 -0
  287. package/dist/tools/mappings.d.ts.map +1 -0
  288. package/dist/tools/mappings.js +85 -0
  289. package/dist/tools/mappings.js.map +1 -0
  290. package/dist/tools/mc-fts.d.ts +101 -0
  291. package/dist/tools/mc-fts.d.ts.map +1 -0
  292. package/dist/tools/mc-fts.js +279 -0
  293. package/dist/tools/mc-fts.js.map +1 -0
  294. package/dist/tools/mcmeta.d.ts +41 -0
  295. package/dist/tools/mcmeta.d.ts.map +1 -0
  296. package/dist/tools/mcmeta.js +365 -0
  297. package/dist/tools/mcmeta.js.map +1 -0
  298. package/dist/tools/mixin-scan.d.ts +113 -0
  299. package/dist/tools/mixin-scan.d.ts.map +1 -0
  300. package/dist/tools/mixin-scan.js +433 -0
  301. package/dist/tools/mixin-scan.js.map +1 -0
  302. package/dist/tools/mod-data.d.ts +83 -0
  303. package/dist/tools/mod-data.d.ts.map +1 -0
  304. package/dist/tools/mod-data.js +630 -0
  305. package/dist/tools/mod-data.js.map +1 -0
  306. package/dist/tools/mod-tags.d.ts +59 -0
  307. package/dist/tools/mod-tags.d.ts.map +1 -0
  308. package/dist/tools/mod-tags.js +279 -0
  309. package/dist/tools/mod-tags.js.map +1 -0
  310. package/dist/tools/mod-tags.test.d.ts +2 -0
  311. package/dist/tools/mod-tags.test.d.ts.map +1 -0
  312. package/dist/tools/mod-tags.test.js +75 -0
  313. package/dist/tools/mod-tags.test.js.map +1 -0
  314. package/dist/tools/modpacks-ch.d.ts +257 -0
  315. package/dist/tools/modpacks-ch.d.ts.map +1 -0
  316. package/dist/tools/modpacks-ch.js +516 -0
  317. package/dist/tools/modpacks-ch.js.map +1 -0
  318. package/dist/tools/packtools.d.ts +113 -0
  319. package/dist/tools/packtools.d.ts.map +1 -0
  320. package/dist/tools/packtools.js +809 -0
  321. package/dist/tools/packtools.js.map +1 -0
  322. package/dist/tools/packtools.test.d.ts +2 -0
  323. package/dist/tools/packtools.test.d.ts.map +1 -0
  324. package/dist/tools/packtools.test.js +99 -0
  325. package/dist/tools/packtools.test.js.map +1 -0
  326. package/dist/tools/platform.d.ts +68 -0
  327. package/dist/tools/platform.d.ts.map +1 -0
  328. package/dist/tools/platform.js +452 -0
  329. package/dist/tools/platform.js.map +1 -0
  330. package/dist/tools/primers.d.ts +36 -0
  331. package/dist/tools/primers.d.ts.map +1 -0
  332. package/dist/tools/primers.js +451 -0
  333. package/dist/tools/primers.js.map +1 -0
  334. package/dist/tools/reports.d.ts +19 -0
  335. package/dist/tools/reports.d.ts.map +1 -0
  336. package/dist/tools/reports.js +573 -0
  337. package/dist/tools/reports.js.map +1 -0
  338. package/dist/tools/source.d.ts +10 -0
  339. package/dist/tools/source.d.ts.map +1 -0
  340. package/dist/tools/source.js +101 -0
  341. package/dist/tools/source.js.map +1 -0
  342. package/dist/tools/vanilla-data.d.ts +127 -0
  343. package/dist/tools/vanilla-data.d.ts.map +1 -0
  344. package/dist/tools/vanilla-data.js +824 -0
  345. package/dist/tools/vanilla-data.js.map +1 -0
  346. package/dist/tools/vanilla.d.ts +171 -0
  347. package/dist/tools/vanilla.d.ts.map +1 -0
  348. package/dist/tools/vanilla.js +612 -0
  349. package/dist/tools/vanilla.js.map +1 -0
  350. package/dist/tools/version-diff.d.ts +113 -0
  351. package/dist/tools/version-diff.d.ts.map +1 -0
  352. package/dist/tools/version-diff.js +519 -0
  353. package/dist/tools/version-diff.js.map +1 -0
  354. package/dist/tools/version-diff.test.d.ts +2 -0
  355. package/dist/tools/version-diff.test.d.ts.map +1 -0
  356. package/dist/tools/version-diff.test.js +102 -0
  357. package/dist/tools/version-diff.test.js.map +1 -0
  358. package/dist/validate.d.ts +19 -0
  359. package/dist/validate.d.ts.map +1 -0
  360. package/dist/validate.js +54 -0
  361. package/dist/validate.js.map +1 -0
  362. package/dist/validate.test.d.ts +2 -0
  363. package/dist/validate.test.d.ts.map +1 -0
  364. package/dist/validate.test.js +73 -0
  365. package/dist/validate.test.js.map +1 -0
  366. package/package.json +62 -0
  367. package/prisma/backends/schema.sqlite.prisma +215 -0
  368. package/prisma/backends/template.db +0 -0
  369. package/prisma/schema.prisma +303 -0
  370. package/scripts/backup.mjs +151 -0
  371. package/scripts/build-template-db.mjs +38 -0
  372. package/scripts/check-atm10.mjs +27 -0
  373. package/scripts/check-sync.mjs +13 -0
  374. package/scripts/create-fts-index.mjs +50 -0
  375. package/scripts/enable-pgvector.mjs +90 -0
  376. package/scripts/enable-sqlite-vec.mjs +158 -0
  377. package/scripts/migrate-backend.mjs +188 -0
  378. package/scripts/migrate-embed-provenance.mjs +80 -0
  379. package/scripts/migrate-metadata-source.mjs +62 -0
  380. package/scripts/migrate-mod-source-files.mjs +67 -0
  381. package/scripts/post-update.mjs +77 -0
  382. package/scripts/verify-atm10.mjs +63 -0
@@ -0,0 +1,113 @@
1
+ import { type ClassInfo } from "../access-flags.js";
2
+ export type ChangeKind = "method_added" | "method_removed" | "method_signature_changed" | "field_added" | "field_removed" | "field_type_changed" | "superclass_changed" | "interface_added" | "interface_removed" | "access_changed";
3
+ export interface MethodChange {
4
+ name: string;
5
+ descriptor: string;
6
+ access: number;
7
+ accessStr: string;
8
+ }
9
+ export interface MethodSignatureChange {
10
+ name: string;
11
+ from: string;
12
+ to: string;
13
+ access: number;
14
+ }
15
+ export interface FieldChange {
16
+ name: string;
17
+ descriptor: string;
18
+ simpleType: string;
19
+ access: number;
20
+ accessStr: string;
21
+ }
22
+ export interface FieldTypeChange {
23
+ name: string;
24
+ from: string;
25
+ to: string;
26
+ fromSimple: string;
27
+ toSimple: string;
28
+ }
29
+ export interface ClassDiff {
30
+ className: string;
31
+ superChanged: boolean;
32
+ superFrom: string | null;
33
+ superTo: string | null;
34
+ interfaces: {
35
+ added: string[];
36
+ removed: string[];
37
+ };
38
+ methods: {
39
+ added: MethodChange[];
40
+ removed: MethodChange[];
41
+ signatureChanged: MethodSignatureChange[];
42
+ };
43
+ fields: {
44
+ added: FieldChange[];
45
+ removed: FieldChange[];
46
+ typeChanged: FieldTypeChange[];
47
+ };
48
+ hasBreakingChange: boolean;
49
+ /** Cosine similarity 0–1 between the two versions' source embeddings. null = unavailable. */
50
+ semanticSimilarity: number | null;
51
+ }
52
+ export interface VersionDiffResult {
53
+ versionA: string;
54
+ versionB: string;
55
+ packages: string[] | null;
56
+ summary: {
57
+ classesAdded: number;
58
+ classesRemoved: number;
59
+ classesChanged: number;
60
+ breakingChanges: number;
61
+ };
62
+ added: string[];
63
+ removed: string[];
64
+ changed: ClassDiff[];
65
+ }
66
+ /**
67
+ * Returns true if a change of this kind on a member with the given access flags
68
+ * constitutes a breaking API change.
69
+ */
70
+ export declare function classifyBreaking(kind: ChangeKind | string, accessFlags: number): boolean;
71
+ /**
72
+ * Compares two ClassInfo objects and returns a structured ClassDiff.
73
+ * Does NOT populate semanticSimilarity (caller does that separately).
74
+ */
75
+ export declare function diffClassIndex(a: ClassInfo, b: ClassInfo): ClassDiff;
76
+ /**
77
+ * Produces a detailed AST-level diff between two MC versions.
78
+ *
79
+ * @param versionA Earlier version (e.g. "1.20.1")
80
+ * @param versionB Later version (e.g. "1.21.1")
81
+ * @param packages Optional slash-prefix filter (e.g. ["net/minecraft/world/entity"])
82
+ * @param maxClasses Cap on changed-class output (default 200). Does not affect summary counts.
83
+ * @param force Skip cache read and recompute (still writes result to cache).
84
+ * @param semantic Enrich with Ollama embedding similarity (requires Ollama + index_semantic).
85
+ * @param cache When false, skip both reading and writing the DB cache (default true).
86
+ */
87
+ export declare function diffMcVersionsDetailed(versionA: string, versionB: string, packages?: string[], maxClasses?: number, force?: boolean, semantic?: boolean, cache?: boolean): Promise<VersionDiffResult>;
88
+ export interface ModVersionDiffResult extends VersionDiffResult {
89
+ modA: {
90
+ id: number;
91
+ modId: string;
92
+ version: string;
93
+ };
94
+ modB: {
95
+ id: number;
96
+ modId: string;
97
+ version: string;
98
+ };
99
+ }
100
+ /**
101
+ * Produces a detailed AST-level diff between two ingested mod versions.
102
+ * Uses the same ClassDiff / breaking-change logic as diffMcVersionsDetailed.
103
+ *
104
+ * @param dbIdA DB id of the older mod version
105
+ * @param dbIdB DB id of the newer mod version
106
+ * @param packages Optional slash-prefix filter (e.g. ["com/example/mymod"])
107
+ * @param maxClasses Cap on changed-class output (default 200)
108
+ * @param semantic Enrich with Ollama embedding similarity (requires mod index_semantic)
109
+ * @param cache When true: read from DB cache first, write result to DB after compute
110
+ * @param force When true (implies cache=true): skip cache read, recompute, write to cache
111
+ */
112
+ export declare function diffModVersionsDetailed(dbIdA: number, dbIdB: number, packages?: string[], maxClasses?: number, semantic?: boolean, cache?: boolean, force?: boolean): Promise<ModVersionDiffResult>;
113
+ //# sourceMappingURL=version-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-diff.d.ts","sourceRoot":"","sources":["../../src/tools/version-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,519 @@
1
+ /**
2
+ * AST-level version diff for Minecraft source.
3
+ * Uses JarIndex data (bytecode-extracted method/field descriptors) to produce
4
+ * structured ClassDiff results with breaking-change classification.
5
+ * Cache layer stores computed diffs in McVersionDiff (Prisma, both PG + SQLite).
6
+ * Semantic scoring (optional) uses existing Ollama + pgvector/sqlite-vec pipeline.
7
+ */
8
+ import { createHash } from "crypto";
9
+ import { readFile, writeFile } from "fs/promises";
10
+ import { getMcJarPath, mcPaths } from "../minecraft.js";
11
+ import { indexJar } from "../java-tools.js";
12
+ import { descriptorToSimpleType, accessStr } from "../access-flags.js";
13
+ import { exists, ensureDir } from "../cache.js";
14
+ import { validateVersion } from "../validate.js";
15
+ import { getDb } from "../db.js";
16
+ import { detectBackend } from "../db-backend.js";
17
+ import { ensureMcVersion } from "../repositories/mcVersion.js";
18
+ // ── Breaking change classification ───────────────────────────────────────────
19
+ /**
20
+ * Returns true if a change of this kind on a member with the given access flags
21
+ * constitutes a breaking API change.
22
+ */
23
+ export function classifyBreaking(kind, accessFlags) {
24
+ const isPublicOrProtected = !!(accessFlags & 0x0001) || !!(accessFlags & 0x0004);
25
+ switch (kind) {
26
+ case "method_removed":
27
+ case "method_signature_changed":
28
+ case "field_removed":
29
+ case "field_type_changed":
30
+ return isPublicOrProtected;
31
+ case "superclass_changed":
32
+ case "interface_removed":
33
+ return true;
34
+ case "access_changed":
35
+ return isPublicOrProtected;
36
+ default:
37
+ return false;
38
+ }
39
+ }
40
+ // ── Single-class diff ─────────────────────────────────────────────────────────
41
+ /**
42
+ * Compares two ClassInfo objects and returns a structured ClassDiff.
43
+ * Does NOT populate semanticSimilarity (caller does that separately).
44
+ */
45
+ export function diffClassIndex(a, b) {
46
+ // Methods: key by (name, descriptor) for exact match
47
+ const aMethods = new Map();
48
+ const bMethods = new Map();
49
+ for (const m of a.methods ?? [])
50
+ aMethods.set(`${m.name}::${m.descriptor}`, m);
51
+ for (const m of b.methods ?? [])
52
+ bMethods.set(`${m.name}::${m.descriptor}`, m);
53
+ const methodsAdded = [];
54
+ const methodsRemoved = [];
55
+ const methodsSigChanged = [];
56
+ for (const [key, m] of aMethods) {
57
+ if (!bMethods.has(key))
58
+ methodsRemoved.push({
59
+ name: m.name, descriptor: m.descriptor, access: m.access, accessStr: accessStr(m.access),
60
+ });
61
+ }
62
+ for (const [key, m] of bMethods) {
63
+ if (!aMethods.has(key))
64
+ methodsAdded.push({
65
+ name: m.name, descriptor: m.descriptor, access: m.access, accessStr: accessStr(m.access),
66
+ });
67
+ }
68
+ // Signature change heuristic: a method with same name removed in A and added in B,
69
+ // only when that name has exactly one unmatched entry on each side.
70
+ const aByName = new Map();
71
+ const bByName = new Map();
72
+ for (const m of a.methods ?? []) {
73
+ const arr = aByName.get(m.name) ?? [];
74
+ arr.push(m);
75
+ aByName.set(m.name, arr);
76
+ }
77
+ for (const m of b.methods ?? []) {
78
+ const arr = bByName.get(m.name) ?? [];
79
+ arr.push(m);
80
+ bByName.set(m.name, arr);
81
+ }
82
+ const removedNames = new Set(methodsRemoved.map((m) => m.name));
83
+ const addedNames = new Set(methodsAdded.map((m) => m.name));
84
+ for (const name of removedNames) {
85
+ if (!addedNames.has(name))
86
+ continue;
87
+ const fromList = (aByName.get(name) ?? []).filter((m) => !bMethods.has(`${m.name}::${m.descriptor}`));
88
+ const toList = (bByName.get(name) ?? []).filter((m) => !aMethods.has(`${m.name}::${m.descriptor}`));
89
+ // Only collapse to signature change when neither version has multiple overloads for this name.
90
+ // If A or B has >1 overload, treat each descriptor independently (removed vs added).
91
+ const totalInA = aByName.get(name)?.length ?? 0;
92
+ const totalInB = bByName.get(name)?.length ?? 0;
93
+ if (fromList.length === 1 && toList.length === 1 && totalInA === 1 && totalInB === 1) {
94
+ methodsSigChanged.push({ name, from: fromList[0].descriptor, to: toList[0].descriptor, access: fromList[0].access });
95
+ const rIdx = methodsRemoved.findIndex((m) => m.name === name && m.descriptor === fromList[0].descriptor);
96
+ if (rIdx !== -1)
97
+ methodsRemoved.splice(rIdx, 1);
98
+ const aIdx = methodsAdded.findIndex((m) => m.name === name && m.descriptor === toList[0].descriptor);
99
+ if (aIdx !== -1)
100
+ methodsAdded.splice(aIdx, 1);
101
+ }
102
+ }
103
+ // Fields: key by name (unique within a class)
104
+ const aFields = new Map((a.fields ?? []).map((f) => [f.name, f]));
105
+ const bFields = new Map((b.fields ?? []).map((f) => [f.name, f]));
106
+ const fieldsAdded = [];
107
+ const fieldsRemoved = [];
108
+ const fieldsTypeChanged = [];
109
+ for (const [name, f] of aFields) {
110
+ const bf = bFields.get(name);
111
+ if (!bf) {
112
+ fieldsRemoved.push({ name, descriptor: f.descriptor, simpleType: descriptorToSimpleType(f.descriptor), access: f.access, accessStr: accessStr(f.access) });
113
+ }
114
+ else if (bf.descriptor !== f.descriptor) {
115
+ fieldsTypeChanged.push({ name, from: f.descriptor, to: bf.descriptor, fromSimple: descriptorToSimpleType(f.descriptor), toSimple: descriptorToSimpleType(bf.descriptor) });
116
+ }
117
+ }
118
+ for (const [name, f] of bFields) {
119
+ if (!aFields.has(name))
120
+ fieldsAdded.push({ name, descriptor: f.descriptor, simpleType: descriptorToSimpleType(f.descriptor), access: f.access, accessStr: accessStr(f.access) });
121
+ }
122
+ // Superclass / interfaces
123
+ const superChanged = a.superName !== b.superName;
124
+ const aIfaces = new Set(a.interfaces ?? []);
125
+ const bIfaces = new Set(b.interfaces ?? []);
126
+ const ifacesAdded = [...bIfaces].filter((i) => !aIfaces.has(i));
127
+ const ifacesRemoved = [...aIfaces].filter((i) => !bIfaces.has(i));
128
+ // Breaking change flag
129
+ const hasBreakingChange = methodsRemoved.some((m) => classifyBreaking("method_removed", m.access)) ||
130
+ methodsSigChanged.some((m) => classifyBreaking("method_signature_changed", m.access)) ||
131
+ fieldsRemoved.some((f) => classifyBreaking("field_removed", f.access)) ||
132
+ fieldsTypeChanged.some((f) => {
133
+ const aField = aFields.get(f.name);
134
+ return aField ? classifyBreaking("field_type_changed", aField.access) : false;
135
+ }) ||
136
+ (superChanged && classifyBreaking("superclass_changed", 0)) ||
137
+ ifacesRemoved.length > 0;
138
+ return {
139
+ className: a.name,
140
+ superChanged,
141
+ superFrom: superChanged ? a.superName : null,
142
+ superTo: superChanged ? b.superName : null,
143
+ interfaces: { added: ifacesAdded, removed: ifacesRemoved },
144
+ methods: { added: methodsAdded, removed: methodsRemoved, signatureChanged: methodsSigChanged },
145
+ fields: { added: fieldsAdded, removed: fieldsRemoved, typeChanged: fieldsTypeChanged },
146
+ hasBreakingChange,
147
+ semanticSimilarity: null,
148
+ };
149
+ }
150
+ // ── Index loading (cached to disk, mirrors vanilla.ts getMcIndex) ─────────────
151
+ const indexMemCache = new Map();
152
+ async function getMcIndexCached(version) {
153
+ if (indexMemCache.has(version))
154
+ return indexMemCache.get(version);
155
+ const cachePath = mcPaths.index(version);
156
+ if (await exists(cachePath)) {
157
+ const data = JSON.parse(await readFile(cachePath, "utf8"));
158
+ indexMemCache.set(version, data);
159
+ return data;
160
+ }
161
+ const jarPath = await getMcJarPath(version);
162
+ const index = await indexJar(jarPath);
163
+ await ensureDir(cachePath);
164
+ await writeFile(cachePath, JSON.stringify(index), "utf8");
165
+ indexMemCache.set(version, index);
166
+ return index;
167
+ }
168
+ // ── packages hash helper ──────────────────────────────────────────────────────
169
+ function buildPackagesHash(packages) {
170
+ if (!packages || packages.length === 0)
171
+ return "all";
172
+ return createHash("sha1").update([...packages].sort().join("|")).digest("hex").slice(0, 12);
173
+ }
174
+ // ── DB cache helpers ──────────────────────────────────────────────────────────
175
+ async function readCachedDiff(versionA, versionB, pkgHash) {
176
+ try {
177
+ const db = await getDb();
178
+ const row = await db.mcVersionDiff.findUnique({
179
+ where: { versionA_versionB_packagesHash: { versionA, versionB, packagesHash: pkgHash } },
180
+ });
181
+ if (!row)
182
+ return null;
183
+ const raw = detectBackend() === "sqlite" ? JSON.parse(row.result) : row.result;
184
+ return raw;
185
+ }
186
+ catch {
187
+ return null; // table may not exist yet in older DBs
188
+ }
189
+ }
190
+ async function writeCachedDiff(versionA, versionB, pkgHash, result) {
191
+ try {
192
+ const db = await getDb();
193
+ const resultData = detectBackend() === "sqlite" ? JSON.stringify(result) : result;
194
+ await db.mcVersionDiff.upsert({
195
+ where: { versionA_versionB_packagesHash: { versionA, versionB, packagesHash: pkgHash } },
196
+ update: { result: resultData },
197
+ create: { versionA, versionB, packagesHash: pkgHash, result: resultData },
198
+ });
199
+ }
200
+ catch {
201
+ // Non-fatal — result is still returned even if caching fails
202
+ }
203
+ }
204
+ // ── Main exported function ────────────────────────────────────────────────────
205
+ /**
206
+ * Produces a detailed AST-level diff between two MC versions.
207
+ *
208
+ * @param versionA Earlier version (e.g. "1.20.1")
209
+ * @param versionB Later version (e.g. "1.21.1")
210
+ * @param packages Optional slash-prefix filter (e.g. ["net/minecraft/world/entity"])
211
+ * @param maxClasses Cap on changed-class output (default 200). Does not affect summary counts.
212
+ * @param force Skip cache read and recompute (still writes result to cache).
213
+ * @param semantic Enrich with Ollama embedding similarity (requires Ollama + index_semantic).
214
+ * @param cache When false, skip both reading and writing the DB cache (default true).
215
+ */
216
+ export async function diffMcVersionsDetailed(versionA, versionB, packages, maxClasses = 200, force = false, semantic = false, cache = true) {
217
+ validateVersion(versionA);
218
+ validateVersion(versionB);
219
+ const pkgHash = buildPackagesHash(packages);
220
+ if (!force && cache) {
221
+ const cached = await readCachedDiff(versionA, versionB, pkgHash);
222
+ if (cached) {
223
+ return { ...cached, changed: cached.changed.slice(0, maxClasses) };
224
+ }
225
+ }
226
+ const [indexA, indexB] = await Promise.all([
227
+ getMcIndexCached(versionA),
228
+ getMcIndexCached(versionB),
229
+ ]);
230
+ const setA = new Set(Object.keys(indexA.classes));
231
+ const setB = new Set(Object.keys(indexB.classes));
232
+ const inScope = (cls) => {
233
+ if (!packages || packages.length === 0)
234
+ return true;
235
+ return packages.some((pkg) => cls.startsWith(pkg));
236
+ };
237
+ const added = [...setB].filter((c) => !setA.has(c) && inScope(c)).sort();
238
+ const removed = [...setA].filter((c) => !setB.has(c) && inScope(c)).sort();
239
+ const common = [...setA].filter((c) => setB.has(c) && inScope(c));
240
+ const changed = [];
241
+ let breakingCount = 0;
242
+ for (const cls of common) {
243
+ const diff = diffClassIndex(indexA.classes[cls], indexB.classes[cls]);
244
+ const isEmpty = diff.methods.added.length === 0 &&
245
+ diff.methods.removed.length === 0 &&
246
+ diff.methods.signatureChanged.length === 0 &&
247
+ diff.fields.added.length === 0 &&
248
+ diff.fields.removed.length === 0 &&
249
+ diff.fields.typeChanged.length === 0 &&
250
+ !diff.superChanged &&
251
+ diff.interfaces.added.length === 0 &&
252
+ diff.interfaces.removed.length === 0;
253
+ if (!isEmpty) {
254
+ changed.push(diff);
255
+ if (diff.hasBreakingChange)
256
+ breakingCount++;
257
+ }
258
+ }
259
+ const result = {
260
+ versionA, versionB,
261
+ packages: packages ?? null,
262
+ summary: {
263
+ classesAdded: added.length,
264
+ classesRemoved: removed.length,
265
+ classesChanged: changed.length,
266
+ breakingChanges: breakingCount,
267
+ },
268
+ added,
269
+ removed,
270
+ changed, // full array stored in cache; sliced at return
271
+ };
272
+ if (semantic) {
273
+ result.changed = await enrichWithSemanticScores(result.changed, versionA, versionB);
274
+ }
275
+ if (cache) {
276
+ await writeCachedDiff(versionA, versionB, pkgHash, result);
277
+ }
278
+ return { ...result, changed: result.changed.slice(0, maxClasses) };
279
+ }
280
+ // ── Semantic similarity enrichment ───────────────────────────────────────────
281
+ /**
282
+ * For each ClassDiff, look up embeddings for its class in versionA and versionB.
283
+ * If both are found, compute cosine similarity and set semanticSimilarity.
284
+ */
285
+ async function enrichWithSemanticScores(diffs, versionA, versionB) {
286
+ const [idA, idB] = await Promise.all([
287
+ ensureMcVersion(versionA),
288
+ ensureMcVersion(versionB),
289
+ ]);
290
+ const backend = detectBackend();
291
+ const embRepo = backend === "sqlite"
292
+ ? await import("../repositories/embeddings-sqlite.js")
293
+ : await import("../repositories/embeddings.js");
294
+ // Build lookup keys in both slash-notation (JarIndex native) and dot-notation
295
+ const slashNames = diffs.map((d) => d.className);
296
+ const dotNames = diffs.map((d) => d.className.replace(/\//g, "."));
297
+ const allNames = [...new Set([...slashNames, ...dotNames])];
298
+ // Direct SQL lookup — embeddings are already stored; we just need the row IDs
299
+ const [mapA, mapB] = await Promise.all([
300
+ embRepo.findSourceIdsByClassNames(allNames, idA),
301
+ embRepo.findSourceIdsByClassNames(allNames, idB),
302
+ ]);
303
+ const pairs = [];
304
+ for (let i = 0; i < diffs.length; i++) {
305
+ const aId = mapA.get(slashNames[i]) ?? mapA.get(dotNames[i]);
306
+ const bId = mapB.get(slashNames[i]) ?? mapB.get(dotNames[i]);
307
+ if (aId !== undefined && bId !== undefined)
308
+ pairs.push({ diffIdx: i, aId, bId });
309
+ }
310
+ // Batch all similarity computations in one DB round-trip
311
+ const simMap = await batchSimilarities(pairs, backend, "mc_source_files");
312
+ // Assign scores back
313
+ const enriched = diffs.map((d) => ({ ...d, semanticSimilarity: null }));
314
+ for (const { diffIdx, aId, bId } of pairs) {
315
+ enriched[diffIdx].semanticSimilarity = simMap.get(`${aId}:${bId}`) ?? null;
316
+ }
317
+ return enriched;
318
+ }
319
+ /**
320
+ * Batch-compute cosine similarities for multiple id pairs against a source table.
321
+ * SQLite: opens ONE connection and fetches all needed embeddings in a single query.
322
+ * PG: single unnest-based JOIN query.
323
+ * Returns a Map keyed by "aId:bId".
324
+ */
325
+ async function batchSimilarities(pairs, backend, table) {
326
+ const out = new Map();
327
+ if (pairs.length === 0)
328
+ return out;
329
+ if (backend !== "sqlite") {
330
+ const db = await getDb();
331
+ const aIds = pairs.map((p) => p.aId);
332
+ const bIds = pairs.map((p) => p.bId);
333
+ const rows = await db.$queryRawUnsafe(`SELECT p.a_id, p.b_id, (1 - (a.embedding <=> b.embedding))::float AS sim
334
+ FROM unnest($1::int[], $2::int[]) AS p(a_id, b_id)
335
+ JOIN ${table} a ON a.id = p.a_id AND a.embedding IS NOT NULL
336
+ JOIN ${table} b ON b.id = p.b_id AND b.embedding IS NOT NULL`, aIds, bIds);
337
+ for (const { a_id, b_id, sim } of rows)
338
+ out.set(`${a_id}:${b_id}`, sim);
339
+ }
340
+ else {
341
+ const Database = (await import("better-sqlite3")).default;
342
+ const url = process.env.DATABASE_URL ?? "";
343
+ const dbPath = url.replace(/^file:\/\//, "").replace(/^file:/, "");
344
+ const db = new Database(dbPath, { readonly: true });
345
+ const allIds = [...new Set(pairs.flatMap((p) => [p.aId, p.bId]))];
346
+ const placeholders = allIds.map(() => "?").join(",");
347
+ const rows = db.prepare(`SELECT id, embedding FROM ${table} WHERE id IN (${placeholders})`)
348
+ .all(...allIds);
349
+ db.close();
350
+ const embMap = new Map(rows.map((r) => [r.id, r.embedding]));
351
+ for (const { aId, bId } of pairs) {
352
+ const ea = embMap.get(aId);
353
+ const eb = embMap.get(bId);
354
+ out.set(`${aId}:${bId}`, ea && eb ? cosineSimilarityBlob(ea, eb) : null);
355
+ }
356
+ }
357
+ return out;
358
+ }
359
+ function cosineSimilarityBlob(a, b) {
360
+ const len = Math.min(a.length, b.length) >> 2;
361
+ let dot = 0, normA = 0, normB = 0;
362
+ for (let i = 0; i < len; i++) {
363
+ const va = a.readFloatLE(i * 4);
364
+ const vb = b.readFloatLE(i * 4);
365
+ dot += va * vb;
366
+ normA += va * va;
367
+ normB += vb * vb;
368
+ }
369
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
370
+ return denom === 0 ? 0 : dot / denom;
371
+ }
372
+ // ── Mod diff DB cache helpers ─────────────────────────────────────────────────
373
+ async function readCachedModDiff(dbIdA, dbIdB, pkgHash) {
374
+ try {
375
+ const db = await getDb();
376
+ const row = await db.modVersionDiff.findUnique({
377
+ where: { modDbIdA_modDbIdB_packagesHash: { modDbIdA: dbIdA, modDbIdB: dbIdB, packagesHash: pkgHash } },
378
+ });
379
+ if (!row)
380
+ return null;
381
+ const raw = detectBackend() === "sqlite" ? JSON.parse(row.result) : row.result;
382
+ return raw;
383
+ }
384
+ catch {
385
+ return null;
386
+ }
387
+ }
388
+ async function writeCachedModDiff(dbIdA, dbIdB, pkgHash, result) {
389
+ try {
390
+ const db = await getDb();
391
+ const resultData = detectBackend() === "sqlite" ? JSON.stringify(result) : result;
392
+ await db.modVersionDiff.upsert({
393
+ where: { modDbIdA_modDbIdB_packagesHash: { modDbIdA: dbIdA, modDbIdB: dbIdB, packagesHash: pkgHash } },
394
+ update: { result: resultData },
395
+ create: { modDbIdA: dbIdA, modDbIdB: dbIdB, packagesHash: pkgHash, result: resultData },
396
+ });
397
+ }
398
+ catch {
399
+ // Non-fatal
400
+ }
401
+ }
402
+ /**
403
+ * Produces a detailed AST-level diff between two ingested mod versions.
404
+ * Uses the same ClassDiff / breaking-change logic as diffMcVersionsDetailed.
405
+ *
406
+ * @param dbIdA DB id of the older mod version
407
+ * @param dbIdB DB id of the newer mod version
408
+ * @param packages Optional slash-prefix filter (e.g. ["com/example/mymod"])
409
+ * @param maxClasses Cap on changed-class output (default 200)
410
+ * @param semantic Enrich with Ollama embedding similarity (requires mod index_semantic)
411
+ * @param cache When true: read from DB cache first, write result to DB after compute
412
+ * @param force When true (implies cache=true): skip cache read, recompute, write to cache
413
+ */
414
+ export async function diffModVersionsDetailed(dbIdA, dbIdB, packages, maxClasses = 200, semantic = false, cache = false, force = false) {
415
+ const { findModById } = await import("../repositories/mod.js");
416
+ const [modA, modB] = await Promise.all([findModById(dbIdA), findModById(dbIdB)]);
417
+ if (!modA)
418
+ throw new Error(`Mod #${dbIdA} not found`);
419
+ if (!modB)
420
+ throw new Error(`Mod #${dbIdB} not found`);
421
+ const useCache = cache || force;
422
+ const pkgHash = buildPackagesHash(packages);
423
+ if (useCache && !force) {
424
+ const cached = await readCachedModDiff(dbIdA, dbIdB, pkgHash);
425
+ if (cached) {
426
+ return { ...cached, changed: cached.changed.slice(0, maxClasses) };
427
+ }
428
+ }
429
+ const [indexA, indexB] = await Promise.all([
430
+ indexJar(modA.jarPath),
431
+ indexJar(modB.jarPath),
432
+ ]);
433
+ const setA = new Set(Object.keys(indexA.classes));
434
+ const setB = new Set(Object.keys(indexB.classes));
435
+ const inScope = (cls) => {
436
+ if (!packages || packages.length === 0)
437
+ return true;
438
+ return packages.some((pkg) => cls.startsWith(pkg));
439
+ };
440
+ const added = [...setB].filter((c) => !setA.has(c) && inScope(c)).sort();
441
+ const removed = [...setA].filter((c) => !setB.has(c) && inScope(c)).sort();
442
+ const common = [...setA].filter((c) => setB.has(c) && inScope(c));
443
+ const changed = [];
444
+ let breakingCount = 0;
445
+ for (const cls of common) {
446
+ const diff = diffClassIndex(indexA.classes[cls], indexB.classes[cls]);
447
+ const isEmpty = diff.methods.added.length === 0 &&
448
+ diff.methods.removed.length === 0 &&
449
+ diff.methods.signatureChanged.length === 0 &&
450
+ diff.fields.added.length === 0 &&
451
+ diff.fields.removed.length === 0 &&
452
+ diff.fields.typeChanged.length === 0 &&
453
+ !diff.superChanged &&
454
+ diff.interfaces.added.length === 0 &&
455
+ diff.interfaces.removed.length === 0;
456
+ if (!isEmpty) {
457
+ changed.push(diff);
458
+ if (diff.hasBreakingChange)
459
+ breakingCount++;
460
+ }
461
+ }
462
+ const base = {
463
+ versionA: modA.version,
464
+ versionB: modB.version,
465
+ packages: packages ?? null,
466
+ summary: {
467
+ classesAdded: added.length,
468
+ classesRemoved: removed.length,
469
+ classesChanged: changed.length,
470
+ breakingChanges: breakingCount,
471
+ },
472
+ added,
473
+ removed,
474
+ changed, // full array stored in cache; sliced at return
475
+ };
476
+ const result = {
477
+ ...base,
478
+ modA: { id: dbIdA, modId: modA.modId, version: modA.version },
479
+ modB: { id: dbIdB, modId: modB.modId, version: modB.version },
480
+ };
481
+ if (semantic) {
482
+ result.changed = await enrichModWithSemanticScores(result.changed, dbIdA, dbIdB);
483
+ }
484
+ if (useCache) {
485
+ await writeCachedModDiff(dbIdA, dbIdB, pkgHash, result);
486
+ }
487
+ return { ...result, changed: result.changed.slice(0, maxClasses) };
488
+ }
489
+ /**
490
+ * Semantic similarity enrichment for mod source files.
491
+ * Uses mod_source_files embeddings (mod index_semantic must have been run first).
492
+ */
493
+ async function enrichModWithSemanticScores(diffs, dbIdA, dbIdB) {
494
+ const backend = detectBackend();
495
+ const embRepo = backend === "sqlite"
496
+ ? await import("../repositories/embeddings-sqlite.js")
497
+ : await import("../repositories/embeddings.js");
498
+ const slashNames = diffs.map((d) => d.className);
499
+ const dotNames = diffs.map((d) => d.className.replace(/\//g, "."));
500
+ const allNames = [...new Set([...slashNames, ...dotNames])];
501
+ const [mapA, mapB] = await Promise.all([
502
+ embRepo.findModSourceIdsByClassNames(allNames, dbIdA),
503
+ embRepo.findModSourceIdsByClassNames(allNames, dbIdB),
504
+ ]);
505
+ const pairs = [];
506
+ for (let i = 0; i < diffs.length; i++) {
507
+ const aId = mapA.get(slashNames[i]) ?? mapA.get(dotNames[i]);
508
+ const bId = mapB.get(slashNames[i]) ?? mapB.get(dotNames[i]);
509
+ if (aId !== undefined && bId !== undefined)
510
+ pairs.push({ diffIdx: i, aId, bId });
511
+ }
512
+ const simMap = await batchSimilarities(pairs, backend, "mod_source_files");
513
+ const enriched = diffs.map((d) => ({ ...d, semanticSimilarity: null }));
514
+ for (const { diffIdx, aId, bId } of pairs) {
515
+ enriched[diffIdx].semanticSimilarity = simMap.get(`${aId}:${bId}`) ?? null;
516
+ }
517
+ return enriched;
518
+ }
519
+ //# sourceMappingURL=version-diff.js.map