@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,158 @@
1
+ #!/usr/bin/env node
2
+ // scripts/enable-sqlite-vec.mjs
3
+ // Creates FTS5 virtual tables, sync triggers, and sqlite-vec vec0 tables.
4
+ // Run after: npm run db:push:sqlite
5
+
6
+ import Database from "better-sqlite3";
7
+ import { createRequire } from "module";
8
+
9
+ const url = process.env.DATABASE_URL ?? "";
10
+ const dbPath = url.replace(/^file:\/\//, "").replace(/^file:/, "");
11
+ if (!dbPath) {
12
+ console.error("DATABASE_URL must be set to a file: path");
13
+ process.exit(1);
14
+ }
15
+
16
+ const db = new Database(dbPath);
17
+
18
+ // Load sqlite-vec extension
19
+ const require = createRequire(import.meta.url);
20
+ try {
21
+ const sqliteVec = require("sqlite-vec");
22
+ sqliteVec.load(db);
23
+ console.log("sqlite-vec loaded");
24
+ } catch (e) {
25
+ console.warn("sqlite-vec not available — vector search disabled:", e.message);
26
+ }
27
+
28
+ db.exec(`
29
+ -- FTS5 virtual table for Minecraft source files
30
+ CREATE VIRTUAL TABLE IF NOT EXISTS fts_mc_source (
31
+ content,
32
+ class_name,
33
+ mc_version_id UNINDEXED
34
+ ) USING fts5(content, class_name, mc_version_id UNINDEXED);
35
+
36
+ -- Sync triggers for mc_source_files
37
+ CREATE TRIGGER IF NOT EXISTS mc_source_fts_insert
38
+ AFTER INSERT ON mc_source_files BEGIN
39
+ INSERT INTO fts_mc_source(rowid, content, class_name, mc_version_id)
40
+ VALUES (new.id, new.content, new.class_name, new.mc_version_id);
41
+ END;
42
+
43
+ CREATE TRIGGER IF NOT EXISTS mc_source_fts_delete
44
+ AFTER DELETE ON mc_source_files BEGIN
45
+ DELETE FROM fts_mc_source WHERE rowid = old.id;
46
+ END;
47
+
48
+ CREATE TRIGGER IF NOT EXISTS mc_source_fts_update
49
+ AFTER UPDATE ON mc_source_files BEGIN
50
+ DELETE FROM fts_mc_source WHERE rowid = old.id;
51
+ INSERT INTO fts_mc_source(rowid, content, class_name, mc_version_id)
52
+ VALUES (new.id, new.content, new.class_name, new.mc_version_id);
53
+ END;
54
+
55
+ -- FTS5 virtual table for doc entries
56
+ CREATE VIRTUAL TABLE IF NOT EXISTS fts_doc_entries (
57
+ title,
58
+ summary,
59
+ url UNINDEXED,
60
+ category UNINDEXED
61
+ ) USING fts5(title, summary, url UNINDEXED, category UNINDEXED);
62
+
63
+ -- Sync triggers for doc_entries
64
+ CREATE TRIGGER IF NOT EXISTS doc_entries_fts_insert
65
+ AFTER INSERT ON doc_entries BEGIN
66
+ INSERT INTO fts_doc_entries(rowid, title, summary, url, category)
67
+ VALUES (new.id, new.title, new.summary, new.url, new.category);
68
+ END;
69
+
70
+ CREATE TRIGGER IF NOT EXISTS doc_entries_fts_delete
71
+ AFTER DELETE ON doc_entries BEGIN
72
+ DELETE FROM fts_doc_entries WHERE rowid = old.id;
73
+ END;
74
+
75
+ CREATE TRIGGER IF NOT EXISTS doc_entries_fts_update
76
+ AFTER UPDATE ON doc_entries BEGIN
77
+ DELETE FROM fts_doc_entries WHERE rowid = old.id;
78
+ INSERT INTO fts_doc_entries(rowid, title, summary, url, category)
79
+ VALUES (new.id, new.title, new.summary, new.url, new.category);
80
+ END;
81
+
82
+ -- FTS5 virtual table for primers
83
+ CREATE VIRTUAL TABLE IF NOT EXISTS fts_primers (
84
+ title,
85
+ summary,
86
+ content
87
+ ) USING fts5(title, summary, content);
88
+
89
+ -- Sync triggers for primers
90
+ CREATE TRIGGER IF NOT EXISTS primers_fts_insert
91
+ AFTER INSERT ON primers BEGIN
92
+ INSERT INTO fts_primers(rowid, title, summary, content)
93
+ VALUES (new.id, new.title, new.summary, new.content);
94
+ END;
95
+
96
+ CREATE TRIGGER IF NOT EXISTS primers_fts_delete
97
+ AFTER DELETE ON primers BEGIN
98
+ DELETE FROM fts_primers WHERE rowid = old.id;
99
+ END;
100
+
101
+ CREATE TRIGGER IF NOT EXISTS primers_fts_update
102
+ AFTER UPDATE ON primers BEGIN
103
+ DELETE FROM fts_primers WHERE rowid = old.id;
104
+ INSERT INTO fts_primers(rowid, title, summary, content)
105
+ VALUES (new.id, new.title, new.summary, new.content);
106
+ END;
107
+
108
+ -- FTS5 virtual table for mod source files (fabric / neoforge / forge / quilt)
109
+ CREATE VIRTUAL TABLE IF NOT EXISTS fts_mod_source (
110
+ content,
111
+ class_name,
112
+ mod_id UNINDEXED
113
+ ) USING fts5(content, class_name, mod_id UNINDEXED);
114
+
115
+ -- Sync triggers for mod_source_files
116
+ CREATE TRIGGER IF NOT EXISTS mod_source_fts_insert
117
+ AFTER INSERT ON mod_source_files BEGIN
118
+ INSERT INTO fts_mod_source(rowid, content, class_name, mod_id)
119
+ VALUES (new.id, new.content, new.class_name, new.mod_id);
120
+ END;
121
+
122
+ CREATE TRIGGER IF NOT EXISTS mod_source_fts_delete
123
+ AFTER DELETE ON mod_source_files BEGIN
124
+ DELETE FROM fts_mod_source WHERE rowid = old.id;
125
+ END;
126
+
127
+ CREATE TRIGGER IF NOT EXISTS mod_source_fts_update
128
+ AFTER UPDATE ON mod_source_files BEGIN
129
+ DELETE FROM fts_mod_source WHERE rowid = old.id;
130
+ INSERT INTO fts_mod_source(rowid, content, class_name, mod_id)
131
+ VALUES (new.id, new.content, new.class_name, new.mod_id);
132
+ END;
133
+ `);
134
+
135
+ console.log("FTS5 virtual tables and triggers created");
136
+
137
+ // sqlite-vec tables (created only if the extension loaded)
138
+ try {
139
+ db.exec(`
140
+ CREATE VIRTUAL TABLE IF NOT EXISTS vec_mc_source
141
+ USING vec0(embedding float[768]);
142
+
143
+ CREATE VIRTUAL TABLE IF NOT EXISTS vec_mod_source
144
+ USING vec0(embedding float[768]);
145
+
146
+ CREATE VIRTUAL TABLE IF NOT EXISTS vec_doc_entries
147
+ USING vec0(embedding float[768]);
148
+
149
+ CREATE VIRTUAL TABLE IF NOT EXISTS vec_primers
150
+ USING vec0(embedding float[768]);
151
+ `);
152
+ console.log("sqlite-vec vec0 tables created (dim=768)");
153
+ } catch (e) {
154
+ console.warn("Skipping vec0 tables (sqlite-vec unavailable):", e.message);
155
+ }
156
+
157
+ db.close();
158
+ console.log("Done.");
@@ -0,0 +1,188 @@
1
+ // scripts/migrate-backend.mjs
2
+ /**
3
+ * Migrate core modlens data between backends.
4
+ *
5
+ * Usage:
6
+ * SOURCE_DATABASE_URL=postgresql://... DATABASE_URL=pglite:///path node scripts/migrate-backend.mjs
7
+ *
8
+ * Migrates: mods, mod_classes, mod_tags, doc_entries, primers.
9
+ * Skips: mc_versions, mc_source_files (too large — user re-indexes).
10
+ * Safe: uses INSERT OR IGNORE (SQLite) / ON CONFLICT DO NOTHING (Postgres/PGlite).
11
+ */
12
+ import { createRequire } from "module";
13
+ const require = createRequire(import.meta.url);
14
+
15
+ try { require("dotenv").config(); } catch { /* optional */ }
16
+
17
+ const TABLES = ["mods", "mod_classes", "mod_tags", "doc_entries", "primers"];
18
+
19
+ function detectBackend(url) {
20
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
21
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
22
+ return "postgres";
23
+ }
24
+
25
+ // ── Source readers ────────────────────────────────────────────────────────────
26
+
27
+ async function readSourceSqlite(url, table) {
28
+ const Database = require("better-sqlite3");
29
+ const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
30
+ const db = new Database(path, { readonly: true });
31
+ const rows = db.prepare(`SELECT * FROM "${table}"`).all();
32
+ db.close();
33
+ return rows;
34
+ }
35
+
36
+ async function readSourcePglite(url, table) {
37
+ const { PGlite } = require("@electric-sql/pglite");
38
+ const dataDir = url.replace(/^pglite:\/\//, "");
39
+ const pg = await PGlite.create(dataDir);
40
+ const result = await pg.query(`SELECT * FROM "${table}"`);
41
+ await pg.close();
42
+ return result.rows;
43
+ }
44
+
45
+ async function readSourcePostgres(url, table) {
46
+ const pg = (await import("pg")).default;
47
+ const client = new pg.Client({ connectionString: url });
48
+ await client.connect();
49
+ const result = await client.query(`SELECT * FROM "${table}"`);
50
+ await client.end();
51
+ return result.rows;
52
+ }
53
+
54
+ async function readFromSource(backend, url, table) {
55
+ if (backend === "sqlite") return readSourceSqlite(url, table);
56
+ if (backend === "pglite") return readSourcePglite(url, table);
57
+ return readSourcePostgres(url, table);
58
+ }
59
+
60
+ // ── Target writers ────────────────────────────────────────────────────────────
61
+
62
+ async function writeTargetSqlite(url, table, rows) {
63
+ const Database = require("better-sqlite3");
64
+ const path = url.replace(/^file:\/\//, "").replace(/^file:/, "");
65
+ const db = new Database(path);
66
+ const cols = Object.keys(rows[0]);
67
+ const placeholders = cols.map(() => "?").join(", ");
68
+ const stmt = db.prepare(
69
+ `INSERT OR IGNORE INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
70
+ );
71
+ let inserted = 0;
72
+ let skipped = 0;
73
+ const insertMany = db.transaction((allRows) => {
74
+ for (const row of allRows) {
75
+ const vals = cols.map((c) => {
76
+ const v = row[c];
77
+ // Postgres arrays → JSON strings for SQLite column type
78
+ return Array.isArray(v) ? JSON.stringify(v) : v;
79
+ });
80
+ const info = stmt.run(...vals);
81
+ if (info.changes > 0) inserted++; else skipped++;
82
+ }
83
+ });
84
+ insertMany(rows);
85
+ db.close();
86
+ return { inserted, skipped };
87
+ }
88
+
89
+ async function writeTargetPg(url, table, rows, isPglite) {
90
+ let client;
91
+ let needsClose = false;
92
+ if (isPglite) {
93
+ const { PGlite } = require("@electric-sql/pglite");
94
+ const dataDir = url.replace(/^pglite:\/\//, "");
95
+ client = await PGlite.create(dataDir);
96
+ needsClose = true;
97
+ } else {
98
+ const pg = (await import("pg")).default;
99
+ client = new pg.Client({ connectionString: url });
100
+ await client.connect();
101
+ needsClose = true;
102
+ }
103
+
104
+ const cols = Object.keys(rows[0]);
105
+ const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
106
+ const sql = `INSERT INTO "${table}" (${cols.map(c => `"${c}"`).join(", ")}) VALUES (${placeholders}) ON CONFLICT DO NOTHING`;
107
+
108
+ let inserted = 0;
109
+ let skipped = 0;
110
+
111
+ for (const row of rows) {
112
+ const vals = cols.map((c) => row[c]);
113
+ try {
114
+ const result = await client.query(sql, vals);
115
+ if ((result.rowCount ?? 0) > 0) inserted++; else skipped++;
116
+ } catch {
117
+ skipped++;
118
+ }
119
+ }
120
+
121
+ if (needsClose) {
122
+ await (client.end?.() ?? client.close?.());
123
+ }
124
+
125
+ return { inserted, skipped };
126
+ }
127
+
128
+ // ── Migration runner ──────────────────────────────────────────────────────────
129
+
130
+ /**
131
+ * Migrate core data from sourceUrl to targetUrl.
132
+ * @param {string} sourceUrl
133
+ * @param {string} targetUrl
134
+ * @returns {Promise<number>} total rows inserted
135
+ */
136
+ export async function migrate(sourceUrl, targetUrl) {
137
+ const srcBackend = detectBackend(sourceUrl);
138
+ const tgtBackend = detectBackend(targetUrl);
139
+ console.log(`Migrating ${srcBackend} → ${tgtBackend}`);
140
+
141
+ let total = 0;
142
+
143
+ for (const table of TABLES) {
144
+ process.stdout.write(` Reading ${table}...`);
145
+ let rows;
146
+ try {
147
+ rows = await readFromSource(srcBackend, sourceUrl, table);
148
+ process.stdout.write(` ${rows.length} rows\n`);
149
+ } catch (e) {
150
+ process.stdout.write(` SKIP (${e.message})\n`);
151
+ continue;
152
+ }
153
+ if (!rows.length) { console.log(` ${table}: 0 rows`); continue; }
154
+
155
+ let stats;
156
+ try {
157
+ if (tgtBackend === "sqlite") {
158
+ stats = await writeTargetSqlite(targetUrl, table, rows);
159
+ } else {
160
+ stats = await writeTargetPg(targetUrl, table, rows, tgtBackend === "pglite");
161
+ }
162
+ } catch (e) {
163
+ console.error(` ${table}: write failed — ${e.message}`);
164
+ continue;
165
+ }
166
+ console.log(` ${table}: ${stats.inserted} inserted, ${stats.skipped} skipped`);
167
+ total += stats.inserted;
168
+ }
169
+
170
+ console.log(`\nMigration complete. ${total} total rows inserted.`);
171
+ console.log(
172
+ "Note: mc_versions / mc_source_files were not migrated — re-run index after setup.",
173
+ );
174
+ return total;
175
+ }
176
+
177
+ // ── CLI entry point ───────────────────────────────────────────────────────────
178
+
179
+ const isCli = process.argv[1]?.replace(/\\/g, "/").endsWith("migrate-backend.mjs");
180
+ if (isCli) {
181
+ const sourceUrl = process.env.SOURCE_DATABASE_URL ?? "";
182
+ const targetUrl = process.env.DATABASE_URL ?? "";
183
+ if (!sourceUrl || !targetUrl) {
184
+ console.error("Set SOURCE_DATABASE_URL (old backend) and DATABASE_URL (new backend).");
185
+ process.exit(1);
186
+ }
187
+ await migrate(sourceUrl, targetUrl);
188
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Add embed_source and embed_updated_at columns to mc_source_files and mod_source_files.
3
+ * Safe to re-run — uses IF NOT EXISTS / ADD COLUMN IF NOT EXISTS guards.
4
+ *
5
+ * Usage: node scripts/migrate-embed-provenance.mjs
6
+ */
7
+ import { createRequire } from "module";
8
+ const require = createRequire(import.meta.url);
9
+
10
+ try { require("dotenv").config(); } catch { /* optional */ }
11
+
12
+ const dbUrl = process.env.DATABASE_URL ?? "";
13
+
14
+ function detectBackend(url) {
15
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
+ return "postgres";
18
+ }
19
+
20
+ const TABLES = ["mc_source_files", "mod_source_files"];
21
+ const COLUMNS = [
22
+ { name: "embed_source", pgType: "TEXT", sqliteType: "TEXT" },
23
+ { name: "embed_updated_at", pgType: "TIMESTAMPTZ", sqliteType: "DATETIME" },
24
+ ];
25
+
26
+ async function migrateSqlite() {
27
+ const Database = require("better-sqlite3");
28
+ const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
29
+ const db = new Database(path);
30
+ for (const table of TABLES) {
31
+ for (const col of COLUMNS) {
32
+ try {
33
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${col.name} ${col.sqliteType}`);
34
+ console.log(` + ${table}.${col.name}`);
35
+ } catch (e) {
36
+ if (e.message?.includes("duplicate column")) {
37
+ console.log(` = ${table}.${col.name} (already exists)`);
38
+ } else {
39
+ throw e;
40
+ }
41
+ }
42
+ }
43
+ }
44
+ db.close();
45
+ }
46
+
47
+ async function migratePostgres() {
48
+ const { Client } = require("pg");
49
+ const client = new Client({ connectionString: dbUrl });
50
+ await client.connect();
51
+ for (const table of TABLES) {
52
+ for (const col of COLUMNS) {
53
+ await client.query(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
54
+ console.log(` + ${table}.${col.name}`);
55
+ }
56
+ }
57
+ await client.end();
58
+ }
59
+
60
+ async function migratePglite() {
61
+ const { PGlite } = await import("@electric-sql/pglite");
62
+ const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
63
+ const db = new PGlite(dataDir);
64
+ for (const table of TABLES) {
65
+ for (const col of COLUMNS) {
66
+ await db.exec(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${col.name} ${col.pgType}`);
67
+ console.log(` + ${table}.${col.name}`);
68
+ }
69
+ }
70
+ await db.close();
71
+ }
72
+
73
+ const backend = detectBackend(dbUrl);
74
+ console.log(`Migrating embed provenance columns (${backend})...`);
75
+
76
+ if (backend === "sqlite") await migrateSqlite();
77
+ else if (backend === "pglite") await migratePglite();
78
+ else await migratePostgres();
79
+
80
+ console.log("Done.");
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Add metadata_source column to the mods table.
3
+ * Safe to re-run — uses IF NOT EXISTS / duplicate column guards.
4
+ *
5
+ * Usage: node scripts/migrate-metadata-source.mjs
6
+ */
7
+ import { createRequire } from "module";
8
+ const require = createRequire(import.meta.url);
9
+
10
+ try { require("dotenv").config(); } catch { /* optional */ }
11
+
12
+ const dbUrl = process.env.DATABASE_URL ?? "";
13
+
14
+ function detectBackend(url) {
15
+ if (url.startsWith("file:") || url.endsWith(".db")) return "sqlite";
16
+ if (url.startsWith("pglite://") || url.startsWith("pglite:")) return "pglite";
17
+ return "postgres";
18
+ }
19
+
20
+ async function migrateSqlite() {
21
+ const Database = require("better-sqlite3");
22
+ const path = dbUrl.replace(/^file:\/\//, "").replace(/^file:/, "");
23
+ const db = new Database(path);
24
+ try {
25
+ db.exec(`ALTER TABLE mods ADD COLUMN metadata_source TEXT`);
26
+ console.log(" + mods.metadata_source");
27
+ } catch (e) {
28
+ if (e.message?.includes("duplicate column")) {
29
+ console.log(" = mods.metadata_source (already exists)");
30
+ } else {
31
+ throw e;
32
+ }
33
+ }
34
+ db.close();
35
+ }
36
+
37
+ async function migratePostgres() {
38
+ const { Client } = require("pg");
39
+ const client = new Client({ connectionString: dbUrl });
40
+ await client.connect();
41
+ await client.query(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
42
+ console.log(" + mods.metadata_source");
43
+ await client.end();
44
+ }
45
+
46
+ async function migratePglite() {
47
+ const { PGlite } = await import("@electric-sql/pglite");
48
+ const dataDir = dbUrl.replace(/^pglite:\/\//, "").replace(/^pglite:/, "");
49
+ const db = new PGlite(dataDir);
50
+ await db.exec(`ALTER TABLE mods ADD COLUMN IF NOT EXISTS metadata_source TEXT`);
51
+ console.log(" + mods.metadata_source");
52
+ await db.close();
53
+ }
54
+
55
+ const backend = detectBackend(dbUrl);
56
+ console.log(`Migrating metadata_source column (${backend})...`);
57
+
58
+ if (backend === "sqlite") await migrateSqlite();
59
+ else if (backend === "pglite") await migratePglite();
60
+ else await migratePostgres();
61
+
62
+ console.log("Done.");
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Creates the mod_source_files table and a pgvector column for semantic search.
3
+ * Run via: node scripts/migrate-mod-source-files.mjs
4
+ *
5
+ * Safe to re-run — uses IF NOT EXISTS / DO $$ guards throughout.
6
+ */
7
+ import { PrismaClient } from "@prisma/client";
8
+ import { readFileSync, existsSync } from "fs";
9
+ import { join, dirname } from "path";
10
+ import { fileURLToPath } from "url";
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const envPath = join(__dirname, "..", ".env");
14
+ if (existsSync(envPath)) {
15
+ for (const line of readFileSync(envPath, "utf8").split("\n")) {
16
+ const m = line.match(/^([^#=]+)=(.*)$/);
17
+ if (m) process.env[m[1].trim()] ??= m[2].trim().replace(/^["']|["']$/g, "");
18
+ }
19
+ }
20
+
21
+ const prisma = new PrismaClient();
22
+
23
+ async function main() {
24
+ // 1. Create table (no embedding column here — enable-pgvector.mjs owns that
25
+ // so the correct OLLAMA_EMBED_DIM dimension is always used)
26
+ await prisma.$executeRawUnsafe(`
27
+ CREATE TABLE IF NOT EXISTS mod_source_files (
28
+ id SERIAL PRIMARY KEY,
29
+ mod_id INTEGER NOT NULL REFERENCES mods(id) ON DELETE CASCADE,
30
+ class_name TEXT NOT NULL,
31
+ content TEXT NOT NULL,
32
+ UNIQUE (mod_id, class_name)
33
+ )
34
+ `);
35
+ console.log("✓ mod_source_files table ready");
36
+
37
+ // 2. B-tree index on mod_id
38
+ await prisma.$executeRawUnsafe(`
39
+ CREATE INDEX IF NOT EXISTS mod_source_files_mod_id_idx
40
+ ON mod_source_files (mod_id)
41
+ `);
42
+ console.log("✓ mod_source_files_mod_id_idx ready");
43
+
44
+ // 3. GIN index for FTS (same pattern as mc_source_files)
45
+ const ftsExists = await prisma.$queryRaw`
46
+ SELECT 1 FROM pg_indexes
47
+ WHERE schemaname = 'public'
48
+ AND tablename = 'mod_source_files'
49
+ AND indexname = 'mod_source_files_tsv_idx'
50
+ `;
51
+ if (ftsExists.length === 0) {
52
+ await prisma.$executeRawUnsafe(`
53
+ CREATE INDEX CONCURRENTLY mod_source_files_tsv_idx
54
+ ON mod_source_files
55
+ USING GIN (to_tsvector('simple', content))
56
+ `);
57
+ console.log("✓ mod_source_files_tsv_idx (GIN FTS) created");
58
+ } else {
59
+ console.log(" mod_source_files_tsv_idx already exists, skipping");
60
+ }
61
+
62
+ console.log("\nDone. Run 'npm run db:vector' to add the embedding column with the correct dimension.");
63
+ }
64
+
65
+ main()
66
+ .catch((e) => { console.error(e); process.exit(1); })
67
+ .finally(() => prisma.$disconnect());
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Profile-aware post-update script.
3
+ * Called by `npm run update` after git pull + npm install + build.
4
+ * Reads DATABASE_URL / MODLENS_PROFILE from .env and runs the correct
5
+ * schema migration + vector extension commands for the user's backend.
6
+ *
7
+ * Safe to re-run — all underlying scripts use IF NOT EXISTS guards.
8
+ */
9
+ import { execSync } from "child_process";
10
+ import { readFileSync, existsSync } from "fs";
11
+ import { join, dirname } from "path";
12
+ import { fileURLToPath } from "url";
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const ROOT = join(__dirname, "..");
16
+ const envPath = join(ROOT, ".env");
17
+
18
+ // ── Load .env ─────────────────────────────────────────────────────────────────
19
+ if (existsSync(envPath)) {
20
+ for (const line of readFileSync(envPath, "utf8").split("\n")) {
21
+ const m = line.match(/^([^#=]+)=(.*)$/);
22
+ if (m) process.env[m[1].trim()] ??= m[2].trim().replace(/^["']|["']$/g, "");
23
+ }
24
+ }
25
+
26
+ const dbUrl = process.env.DATABASE_URL ?? "";
27
+
28
+ function run(cmd) {
29
+ console.log(`\n> ${cmd}`);
30
+ execSync(cmd, { cwd: ROOT, stdio: "inherit" });
31
+ }
32
+
33
+ // ── Detect backend from DATABASE_URL prefix ───────────────────────────────────
34
+ let backend;
35
+ if (dbUrl.startsWith("postgresql://") || dbUrl.startsWith("postgres://")) {
36
+ backend = "postgres";
37
+ } else if (dbUrl.startsWith("pglite://") || dbUrl.startsWith("pglite:")) {
38
+ backend = "pglite";
39
+ } else if (dbUrl.startsWith("file:")) {
40
+ backend = "sqlite";
41
+ } else {
42
+ console.warn(`⚠ Could not detect backend from DATABASE_URL="${dbUrl}". Defaulting to postgres.`);
43
+ backend = "postgres";
44
+ }
45
+
46
+ console.log(`\nDetected backend: ${backend}`);
47
+
48
+ // ── Apply schema ──────────────────────────────────────────────────────────────
49
+ if (backend === "sqlite") {
50
+ // SQLite uses a separate schema file — db push is safest (no migration files)
51
+ run("npx prisma db push --schema prisma/backends/schema.sqlite.prisma --accept-data-loss");
52
+ } else {
53
+ // Postgres and PGlite both use the main schema
54
+ // prisma migrate deploy applies any new migration files; db push is the fallback
55
+ // for dev setups that use db push instead of migrate
56
+ try {
57
+ run("npx prisma migrate deploy");
58
+ } catch {
59
+ console.log(" migrate deploy failed (likely db-push setup) — falling back to db push");
60
+ run("npx prisma db push");
61
+ }
62
+ // Extra post-migrate steps for Postgres (GIN FTS indexes, mod_source_files table)
63
+ if (backend === "postgres") {
64
+ run("node scripts/create-fts-index.mjs");
65
+ run("node scripts/migrate-mod-source-files.mjs");
66
+ }
67
+ }
68
+
69
+ // ── Vector extension ──────────────────────────────────────────────────────────
70
+ if (backend === "sqlite") {
71
+ run("node scripts/enable-sqlite-vec.mjs");
72
+ } else {
73
+ // Postgres and PGlite: adds/resizes embedding columns to match OLLAMA_EMBED_DIM
74
+ run("node scripts/enable-pgvector.mjs");
75
+ }
76
+
77
+ console.log("\n✓ Update complete. Restart your MCP client to load the new server.");