@creeperhost/modlens-mcp 1.6.0 → 1.6.1

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 (89) hide show
  1. package/README.md +950 -938
  2. package/dist/cli.js +267 -267
  3. package/dist/generated/sqlite/internal/class.d.ts.map +1 -1
  4. package/dist/generated/sqlite/internal/class.js +4 -3
  5. package/dist/generated/sqlite/internal/class.js.map +1 -1
  6. package/dist/launcher.js +4 -1
  7. package/dist/launcher.js.map +1 -1
  8. package/dist/repositories/embeddings-sqlite.js +21 -21
  9. package/dist/repositories/embeddings.js +28 -28
  10. package/dist/repositories/mod.js +2 -2
  11. package/dist/search-adapter.js +51 -51
  12. package/dist/tools/compat-check.js +9 -9
  13. package/dist/tools/embed-registry.js +9 -9
  14. package/dist/tools/graphify.js +14 -14
  15. package/dist/tools/mc-fts.js +2 -2
  16. package/dist/tools/mixin-scan.d.ts +1 -1
  17. package/dist/tools/mixin-scan.js +16 -16
  18. package/dist/tools/version-diff.js +3 -3
  19. package/package.json +70 -62
  20. package/prisma/backends/schema.sqlite.prisma +215 -215
  21. package/prisma/schema.prisma +303 -303
  22. package/scripts/backup.mjs +151 -151
  23. package/scripts/check-atm10.mjs +27 -27
  24. package/scripts/check-sync.mjs +13 -13
  25. package/scripts/create-fts-index.mjs +50 -50
  26. package/scripts/enable-pgvector.mjs +90 -90
  27. package/scripts/enable-sqlite-vec.mjs +158 -158
  28. package/scripts/migrate-backend.mjs +188 -188
  29. package/scripts/migrate-embed-provenance.mjs +80 -80
  30. package/scripts/migrate-metadata-source.mjs +62 -62
  31. package/scripts/migrate-mod-source-files.mjs +67 -67
  32. package/scripts/post-update.mjs +77 -77
  33. package/scripts/verify-atm10.mjs +63 -63
  34. package/dist/access-flags.test.d.ts +0 -2
  35. package/dist/access-flags.test.d.ts.map +0 -1
  36. package/dist/access-flags.test.js +0 -189
  37. package/dist/access-flags.test.js.map +0 -1
  38. package/dist/fetch-utils.test.d.ts +0 -2
  39. package/dist/fetch-utils.test.d.ts.map +0 -1
  40. package/dist/fetch-utils.test.js +0 -133
  41. package/dist/fetch-utils.test.js.map +0 -1
  42. package/dist/mappings.test.d.ts +0 -2
  43. package/dist/mappings.test.d.ts.map +0 -1
  44. package/dist/mappings.test.js +0 -161
  45. package/dist/mappings.test.js.map +0 -1
  46. package/dist/processor.test.d.ts +0 -2
  47. package/dist/processor.test.d.ts.map +0 -1
  48. package/dist/processor.test.js +0 -629
  49. package/dist/processor.test.js.map +0 -1
  50. package/dist/search.test.d.ts +0 -2
  51. package/dist/search.test.d.ts.map +0 -1
  52. package/dist/search.test.js +0 -71
  53. package/dist/search.test.js.map +0 -1
  54. package/dist/security.test.d.ts +0 -2
  55. package/dist/security.test.d.ts.map +0 -1
  56. package/dist/security.test.js +0 -687
  57. package/dist/security.test.js.map +0 -1
  58. package/dist/tools/compat-check.test.d.ts +0 -2
  59. package/dist/tools/compat-check.test.d.ts.map +0 -1
  60. package/dist/tools/compat-check.test.js +0 -179
  61. package/dist/tools/compat-check.test.js.map +0 -1
  62. package/dist/tools/diagnostics.test.d.ts +0 -2
  63. package/dist/tools/diagnostics.test.d.ts.map +0 -1
  64. package/dist/tools/diagnostics.test.js +0 -168
  65. package/dist/tools/diagnostics.test.js.map +0 -1
  66. package/dist/tools/graphify.test.d.ts +0 -2
  67. package/dist/tools/graphify.test.d.ts.map +0 -1
  68. package/dist/tools/graphify.test.js +0 -39
  69. package/dist/tools/graphify.test.js.map +0 -1
  70. package/dist/tools/ingest.test.d.ts +0 -2
  71. package/dist/tools/ingest.test.d.ts.map +0 -1
  72. package/dist/tools/ingest.test.js +0 -340
  73. package/dist/tools/ingest.test.js.map +0 -1
  74. package/dist/tools/mod-tags.test.d.ts +0 -2
  75. package/dist/tools/mod-tags.test.d.ts.map +0 -1
  76. package/dist/tools/mod-tags.test.js +0 -75
  77. package/dist/tools/mod-tags.test.js.map +0 -1
  78. package/dist/tools/packtools.test.d.ts +0 -2
  79. package/dist/tools/packtools.test.d.ts.map +0 -1
  80. package/dist/tools/packtools.test.js +0 -99
  81. package/dist/tools/packtools.test.js.map +0 -1
  82. package/dist/tools/version-diff.test.d.ts +0 -2
  83. package/dist/tools/version-diff.test.d.ts.map +0 -1
  84. package/dist/tools/version-diff.test.js +0 -102
  85. package/dist/tools/version-diff.test.js.map +0 -1
  86. package/dist/validate.test.d.ts +0 -2
  87. package/dist/validate.test.d.ts.map +0 -1
  88. package/dist/validate.test.js +0 -73
  89. package/dist/validate.test.js.map +0 -1
@@ -1,303 +1,303 @@
1
- generator client {
2
- provider = "prisma-client-js"
3
- binaryTargets = ["native", "windows", "debian-openssl-3.0.x", "rhel-openssl-3.0.x", "linux-musl-openssl-3.0.x", "darwin", "darwin-arm64"]
4
- }
5
-
6
- datasource db {
7
- provider = "postgresql"
8
- url = env("DATABASE_URL")
9
- }
10
-
11
- model Mod {
12
- id Int @id @default(autoincrement())
13
- modId String @map("mod_id")
14
- displayName String @map("display_name")
15
- version String
16
- mcVersion String @map("mc_version")
17
- loader String // fabric | neoforge | forge | quilt | unknown
18
- jarPath String @unique @map("jar_path")
19
- sha256 String?
20
- murmur2 String?
21
- sha512 String?
22
- sourcePath String? @map("source_path")
23
- decompPath String? @map("decomp_path")
24
- decompiled Boolean @default(false)
25
- graphPath String? @map("graph_path")
26
- modrinthId String? @map("modrinth_id")
27
- curseforgeId Int? @map("curseforge_id")
28
- hasMixins Boolean @default(false) @map("has_mixins")
29
- hasAt Boolean @default(false) @map("has_at")
30
- hasAw Boolean @default(false) @map("has_aw")
31
- mixinConfigs String[] @map("mixin_configs")
32
- mixinTargets Json @default("[]") @map("mixin_targets")
33
- atEntries Json @default("[]") @map("at_entries")
34
- awEntries Json @default("[]") @map("aw_entries")
35
- dependencies Json @default("[]")
36
- metadata Json @default("{}")
37
- metadataSource String? @map("metadata_source")
38
- /// User-defined labels for filtering/grouping, e.g. ["combat", "storage", "compat"]
39
- tags String[] @default([])
40
- ingestedAt DateTime @default(now()) @map("ingested_at")
41
- updatedAt DateTime @updatedAt @map("updated_at")
42
-
43
- classes ModClass[]
44
- modTags ModTag[]
45
- packFiles PackFile[]
46
- sourceFiles ModSourceFile[]
47
-
48
- @@unique([modId, version, mcVersion, loader])
49
- @@index([modId])
50
- @@index([mcVersion])
51
- @@index([loader])
52
- @@index([modrinthId])
53
- @@index([curseforgeId])
54
- @@map("mods")
55
- }
56
-
57
- model ModClass {
58
- id Int @id @default(autoincrement())
59
- modId Int @map("mod_id")
60
- className String @map("class_name")
61
- superClass String? @map("super_class")
62
- interfaces String[]
63
- accessFlags Int @default(0) @map("access_flags")
64
-
65
- mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
66
-
67
- @@unique([modId, className])
68
- @@index([className])
69
- @@index([modId])
70
- @@map("mod_classes")
71
- }
72
-
73
- // ── Vanilla Minecraft versions ──────────────────────────────────────────────
74
-
75
- model McVersion {
76
- id Int @id @default(autoincrement())
77
- versionId String @unique @map("version_id")
78
- type String @default("release")
79
- jarPath String? @map("jar_path")
80
- decompPath String? @map("decomp_path")
81
- decompiled Boolean @default(false)
82
- indexed Boolean @default(false)
83
- releaseTime DateTime @map("release_time")
84
- createdAt DateTime @default(now()) @map("created_at")
85
-
86
- sourceFiles McSourceFile[]
87
-
88
- @@map("mc_versions")
89
- }
90
-
91
- // ── Cached AST-level version diffs ──────────────────────────────────────────
92
- // Keyed by (versionA, versionB, packagesHash) to allow per-package scoping.
93
- // result stores the full VersionDiffResult JSON. Recomputed on force=true.
94
-
95
- model McVersionDiff {
96
- id Int @id @default(autoincrement())
97
- versionA String @map("version_a")
98
- versionB String @map("version_b")
99
- /// SHA-1 prefix of sorted joined packages filter, or "all" when no filter
100
- packagesHash String @default("all") @map("packages_hash")
101
- result Json
102
- createdAt DateTime @default(now()) @map("created_at")
103
-
104
- @@unique([versionA, versionB, packagesHash])
105
- @@index([versionA, versionB])
106
- @@map("mc_version_diffs")
107
- }
108
-
109
- // ── Cached AST-level mod version diffs ────────────────────────────────────────
110
- // Keyed by (modDbIdA, modDbIdB, packagesHash). Integer IDs are stable per-JAR row.
111
- // Mirrors McVersionDiff but for mod-to-mod comparisons.
112
-
113
- model ModVersionDiff {
114
- id Int @id @default(autoincrement())
115
- modDbIdA Int @map("mod_db_id_a")
116
- modDbIdB Int @map("mod_db_id_b")
117
- /// SHA-1 prefix of sorted joined packages filter, or "all" when no filter
118
- packagesHash String @default("all") @map("packages_hash")
119
- result Json
120
- createdAt DateTime @default(now()) @map("created_at")
121
-
122
- @@unique([modDbIdA, modDbIdB, packagesHash])
123
- @@index([modDbIdA, modDbIdB])
124
- @@map("mod_version_diffs")
125
- }
126
-
127
- // ── Mod-shipped tag files ──────────────────────────────────────────────────────
128
- // One row per data/<namespace>/tags/<registry>/<path>.json file found in a mod JAR.
129
- // tagPath = "<namespace>:<subpath>" e.g. "c:ores/iron", "forge:storage_blocks"
130
- // registry = folder name under tags/ e.g. "block", "item", "entity_type"
131
- // entries = the values array (strings, may include #tag references)
132
- // replace = true when the file sets "replace": true (overrides other mods' contributions)
133
-
134
- model ModTag {
135
- id Int @id @default(autoincrement())
136
- modId Int @map("mod_id")
137
- mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
138
- registry String // block | item | entity_type | fluid | worldgen/biome | …
139
- tagPath String // namespace:subpath, e.g. "c:ores/iron"
140
- namespace String // owning namespace of the tag file, e.g. "c", "minecraft", "forge"
141
- entries String[] // values listed in this tag file
142
- replace Boolean @default(false)
143
-
144
- @@index([modId])
145
- @@index([tagPath])
146
- @@index([registry, tagPath])
147
- @@index([namespace])
148
- @@map("mod_tags")
149
- }
150
-
151
- // Stores decompiled vanilla source per class — enables PostgreSQL FTS search.
152
- // GIN index is created automatically by `npm run db:setup` (scripts/create-fts-index.mjs).
153
- model McSourceFile {
154
- id Int @id @default(autoincrement())
155
- mcVersionId Int @map("mc_version_id")
156
- className String @map("class_name")
157
- content String
158
- /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
159
- embedding Unsupported("vector")? @map("embedding")
160
- /// Provenance: "local" (user Ollama), "registry" (public download), "community" (user contribution)
161
- embedSource String? @map("embed_source")
162
- embedUpdatedAt DateTime? @map("embed_updated_at")
163
-
164
- mcVersion McVersion @relation(fields: [mcVersionId], references: [id], onDelete: Cascade)
165
-
166
- @@unique([mcVersionId, className])
167
- @@index([mcVersionId])
168
- @@map("mc_source_files")
169
- }
170
-
171
- // ── Documentation entries ────────────────────────────────────────────────────
172
-
173
- model DocEntry {
174
- id Int @id @default(autoincrement())
175
- /// Optional: fully-qualified class name this doc entry describes (slashes or dots).
176
- className String? @map("class_name")
177
- title String
178
- summary String?
179
- url String
180
- /// One of: minecraft | neoforge | fabric | forge | quilt | mod | other
181
- category String @default("minecraft")
182
- tags String[]
183
- /// Logical namespace: vanilla | neoforge | fabric | forge | quilt | parchment
184
- namespace String @default("vanilla")
185
- /// How it was added: manual | seed | parchment | javadoc
186
- source String @default("manual")
187
- createdAt DateTime @default(now()) @map("created_at")
188
- updatedAt DateTime @updatedAt @map("updated_at")
189
- /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
190
- embedding Unsupported("vector")? @map("embedding")
191
-
192
- @@index([className])
193
- @@index([category])
194
- @@map("doc_entries")
195
- }
196
-
197
- // ── Mod decompiled source files (for semantic + FTS search) ─────────────────
198
- // One row per .java file from a decompiled mod JAR.
199
- // Mirrors mc_source_files but scoped to ingested mods instead of vanilla MC.
200
- model ModSourceFile {
201
- id Int @id @default(autoincrement())
202
- modId Int @map("mod_id")
203
- className String @map("class_name")
204
- content String
205
- /// pgvector embedding — populated by mod index_semantic action
206
- embedding Unsupported("vector")? @map("embedding")
207
- /// Provenance: "local" (user Ollama), "registry" (public download), "community" (user contribution)
208
- embedSource String? @map("embed_source")
209
- embedUpdatedAt DateTime? @map("embed_updated_at")
210
-
211
- mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
212
-
213
- @@unique([modId, className])
214
- @@index([modId])
215
- @@map("mod_source_files")
216
- }
217
-
218
- // ── Version migration primers ──────────────────────────────────────────────────────────
219
- // Documents that guide modders through upgrading mods from one MC/loader version to another.
220
- // fromDataVersion / toDataVersion store the integer data_version from mcmeta for numeric range queries.
221
-
222
- model Primer {
223
- id Int @id @default(autoincrement())
224
- /// Minecraft version this primer starts at, e.g. "1.20.4"
225
- fromVersion String @map("from_version")
226
- /// Minecraft version this primer targets, e.g. "1.21.1"
227
- toVersion String @map("to_version")
228
- /// Numeric data_version from mcmeta for ordering/range queries
229
- fromDataVersion Int? @map("from_data_version")
230
- toDataVersion Int? @map("to_data_version")
231
- /// Mod loader: neoforge | forge | fabric | quilt | vanilla | other
232
- modloader String @default("neoforge")
233
- title String
234
- summary String?
235
- url String @unique
236
- /// Full text of the primer (optional — populated by ingest with fetch=true)
237
- content String?
238
- tags String[]
239
- source String @default("manual")
240
- createdAt DateTime @default(now()) @map("created_at")
241
- updatedAt DateTime @updatedAt @map("updated_at")
242
- /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
243
- embedding Unsupported("vector")? @map("embedding")
244
-
245
- @@index([fromVersion, toVersion])
246
- @@index([fromDataVersion, toDataVersion])
247
- @@index([modloader])
248
- @@map("primers")
249
- }
250
-
251
- // ── Modpack version tracking ──────────────────────────────────────────────────
252
- // One row per (namespace, packId, versionId) that has been synced or inspected.
253
-
254
- model PackVersion {
255
- id Int @id @default(autoincrement())
256
- /// "ftb" | "curseforge"
257
- namespace String
258
- packId Int @map("pack_id")
259
- versionId Int @map("version_id")
260
- packName String @map("pack_name")
261
- versionName String @map("version_name")
262
- mcVersion String? @map("mc_version")
263
- modloader String?
264
- syncedAt DateTime @default(now()) @map("synced_at")
265
- updatedAt DateTime @updatedAt @map("updated_at")
266
-
267
- files PackFile[]
268
-
269
- @@unique([namespace, packId, versionId])
270
- @@index([namespace, packId])
271
- @@map("pack_versions")
272
- }
273
-
274
- // One row per file listed in a pack version manifest.
275
- // Covers mods, configs, scripts, resource packs, and cf-extract overrides ZIPs.
276
- // modId is set when the file was ingested as a Mod in this database.
277
-
278
- model PackFile {
279
- id Int @id @default(autoincrement())
280
- packVersionId Int @map("pack_version_id")
281
- packVersion PackVersion @relation(fields: [packVersionId], references: [id], onDelete: Cascade)
282
- /// file.id from the modpacks.ch manifest
283
- manifestFileId Int? @map("manifest_file_id")
284
- /// "mod" | "resource" | "config" | "script" | "cf-extract" | "override" | etc.
285
- fileType String @map("file_type")
286
- fileName String @map("file_name")
287
- /// Destination path relative to the pack root (from manifest file.path)
288
- filePath String? @map("file_path")
289
- cfProject Int? @map("cf_project")
290
- cfFile Int? @map("cf_file")
291
- sha1 String?
292
- /// "ingested" | "already_ingested" | "downloaded_zip" | "error" | "skipped" | "not_synced"
293
- status String @default("not_synced")
294
- /// Set when this file was successfully ingested as a Mod row.
295
- modId Int? @map("mod_id")
296
- mod Mod? @relation(fields: [modId], references: [id], onDelete: SetNull)
297
-
298
- @@unique([packVersionId, manifestFileId])
299
- @@index([packVersionId])
300
- @@index([modId])
301
- @@index([cfProject])
302
- @@map("pack_files")
303
- }
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ binaryTargets = ["native", "windows", "debian-openssl-3.0.x", "rhel-openssl-3.0.x", "linux-musl-openssl-3.0.x", "darwin", "darwin-arm64"]
4
+ }
5
+
6
+ datasource db {
7
+ provider = "postgresql"
8
+ url = env("DATABASE_URL")
9
+ }
10
+
11
+ model Mod {
12
+ id Int @id @default(autoincrement())
13
+ modId String @map("mod_id")
14
+ displayName String @map("display_name")
15
+ version String
16
+ mcVersion String @map("mc_version")
17
+ loader String // fabric | neoforge | forge | quilt | unknown
18
+ jarPath String @unique @map("jar_path")
19
+ sha256 String?
20
+ murmur2 String?
21
+ sha512 String?
22
+ sourcePath String? @map("source_path")
23
+ decompPath String? @map("decomp_path")
24
+ decompiled Boolean @default(false)
25
+ graphPath String? @map("graph_path")
26
+ modrinthId String? @map("modrinth_id")
27
+ curseforgeId Int? @map("curseforge_id")
28
+ hasMixins Boolean @default(false) @map("has_mixins")
29
+ hasAt Boolean @default(false) @map("has_at")
30
+ hasAw Boolean @default(false) @map("has_aw")
31
+ mixinConfigs String[] @map("mixin_configs")
32
+ mixinTargets Json @default("[]") @map("mixin_targets")
33
+ atEntries Json @default("[]") @map("at_entries")
34
+ awEntries Json @default("[]") @map("aw_entries")
35
+ dependencies Json @default("[]")
36
+ metadata Json @default("{}")
37
+ metadataSource String? @map("metadata_source")
38
+ /// User-defined labels for filtering/grouping, e.g. ["combat", "storage", "compat"]
39
+ tags String[] @default([])
40
+ ingestedAt DateTime @default(now()) @map("ingested_at")
41
+ updatedAt DateTime @updatedAt @map("updated_at")
42
+
43
+ classes ModClass[]
44
+ modTags ModTag[]
45
+ packFiles PackFile[]
46
+ sourceFiles ModSourceFile[]
47
+
48
+ @@unique([modId, version, mcVersion, loader])
49
+ @@index([modId])
50
+ @@index([mcVersion])
51
+ @@index([loader])
52
+ @@index([modrinthId])
53
+ @@index([curseforgeId])
54
+ @@map("mods")
55
+ }
56
+
57
+ model ModClass {
58
+ id Int @id @default(autoincrement())
59
+ modId Int @map("mod_id")
60
+ className String @map("class_name")
61
+ superClass String? @map("super_class")
62
+ interfaces String[]
63
+ accessFlags Int @default(0) @map("access_flags")
64
+
65
+ mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
66
+
67
+ @@unique([modId, className])
68
+ @@index([className])
69
+ @@index([modId])
70
+ @@map("mod_classes")
71
+ }
72
+
73
+ // ── Vanilla Minecraft versions ──────────────────────────────────────────────
74
+
75
+ model McVersion {
76
+ id Int @id @default(autoincrement())
77
+ versionId String @unique @map("version_id")
78
+ type String @default("release")
79
+ jarPath String? @map("jar_path")
80
+ decompPath String? @map("decomp_path")
81
+ decompiled Boolean @default(false)
82
+ indexed Boolean @default(false)
83
+ releaseTime DateTime @map("release_time")
84
+ createdAt DateTime @default(now()) @map("created_at")
85
+
86
+ sourceFiles McSourceFile[]
87
+
88
+ @@map("mc_versions")
89
+ }
90
+
91
+ // ── Cached AST-level version diffs ──────────────────────────────────────────
92
+ // Keyed by (versionA, versionB, packagesHash) to allow per-package scoping.
93
+ // result stores the full VersionDiffResult JSON. Recomputed on force=true.
94
+
95
+ model McVersionDiff {
96
+ id Int @id @default(autoincrement())
97
+ versionA String @map("version_a")
98
+ versionB String @map("version_b")
99
+ /// SHA-1 prefix of sorted joined packages filter, or "all" when no filter
100
+ packagesHash String @default("all") @map("packages_hash")
101
+ result Json
102
+ createdAt DateTime @default(now()) @map("created_at")
103
+
104
+ @@unique([versionA, versionB, packagesHash])
105
+ @@index([versionA, versionB])
106
+ @@map("mc_version_diffs")
107
+ }
108
+
109
+ // ── Cached AST-level mod version diffs ────────────────────────────────────────
110
+ // Keyed by (modDbIdA, modDbIdB, packagesHash). Integer IDs are stable per-JAR row.
111
+ // Mirrors McVersionDiff but for mod-to-mod comparisons.
112
+
113
+ model ModVersionDiff {
114
+ id Int @id @default(autoincrement())
115
+ modDbIdA Int @map("mod_db_id_a")
116
+ modDbIdB Int @map("mod_db_id_b")
117
+ /// SHA-1 prefix of sorted joined packages filter, or "all" when no filter
118
+ packagesHash String @default("all") @map("packages_hash")
119
+ result Json
120
+ createdAt DateTime @default(now()) @map("created_at")
121
+
122
+ @@unique([modDbIdA, modDbIdB, packagesHash])
123
+ @@index([modDbIdA, modDbIdB])
124
+ @@map("mod_version_diffs")
125
+ }
126
+
127
+ // ── Mod-shipped tag files ──────────────────────────────────────────────────────
128
+ // One row per data/<namespace>/tags/<registry>/<path>.json file found in a mod JAR.
129
+ // tagPath = "<namespace>:<subpath>" e.g. "c:ores/iron", "forge:storage_blocks"
130
+ // registry = folder name under tags/ e.g. "block", "item", "entity_type"
131
+ // entries = the values array (strings, may include #tag references)
132
+ // replace = true when the file sets "replace": true (overrides other mods' contributions)
133
+
134
+ model ModTag {
135
+ id Int @id @default(autoincrement())
136
+ modId Int @map("mod_id")
137
+ mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
138
+ registry String // block | item | entity_type | fluid | worldgen/biome | …
139
+ tagPath String // namespace:subpath, e.g. "c:ores/iron"
140
+ namespace String // owning namespace of the tag file, e.g. "c", "minecraft", "forge"
141
+ entries String[] // values listed in this tag file
142
+ replace Boolean @default(false)
143
+
144
+ @@index([modId])
145
+ @@index([tagPath])
146
+ @@index([registry, tagPath])
147
+ @@index([namespace])
148
+ @@map("mod_tags")
149
+ }
150
+
151
+ // Stores decompiled vanilla source per class — enables PostgreSQL FTS search.
152
+ // GIN index is created automatically by `npm run db:setup` (scripts/create-fts-index.mjs).
153
+ model McSourceFile {
154
+ id Int @id @default(autoincrement())
155
+ mcVersionId Int @map("mc_version_id")
156
+ className String @map("class_name")
157
+ content String
158
+ /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
159
+ embedding Unsupported("vector")? @map("embedding")
160
+ /// Provenance: "local" (user Ollama), "registry" (public download), "community" (user contribution)
161
+ embedSource String? @map("embed_source")
162
+ embedUpdatedAt DateTime? @map("embed_updated_at")
163
+
164
+ mcVersion McVersion @relation(fields: [mcVersionId], references: [id], onDelete: Cascade)
165
+
166
+ @@unique([mcVersionId, className])
167
+ @@index([mcVersionId])
168
+ @@map("mc_source_files")
169
+ }
170
+
171
+ // ── Documentation entries ────────────────────────────────────────────────────
172
+
173
+ model DocEntry {
174
+ id Int @id @default(autoincrement())
175
+ /// Optional: fully-qualified class name this doc entry describes (slashes or dots).
176
+ className String? @map("class_name")
177
+ title String
178
+ summary String?
179
+ url String
180
+ /// One of: minecraft | neoforge | fabric | forge | quilt | mod | other
181
+ category String @default("minecraft")
182
+ tags String[]
183
+ /// Logical namespace: vanilla | neoforge | fabric | forge | quilt | parchment
184
+ namespace String @default("vanilla")
185
+ /// How it was added: manual | seed | parchment | javadoc
186
+ source String @default("manual")
187
+ createdAt DateTime @default(now()) @map("created_at")
188
+ updatedAt DateTime @updatedAt @map("updated_at")
189
+ /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
190
+ embedding Unsupported("vector")? @map("embedding")
191
+
192
+ @@index([className])
193
+ @@index([category])
194
+ @@map("doc_entries")
195
+ }
196
+
197
+ // ── Mod decompiled source files (for semantic + FTS search) ─────────────────
198
+ // One row per .java file from a decompiled mod JAR.
199
+ // Mirrors mc_source_files but scoped to ingested mods instead of vanilla MC.
200
+ model ModSourceFile {
201
+ id Int @id @default(autoincrement())
202
+ modId Int @map("mod_id")
203
+ className String @map("class_name")
204
+ content String
205
+ /// pgvector embedding — populated by mod index_semantic action
206
+ embedding Unsupported("vector")? @map("embedding")
207
+ /// Provenance: "local" (user Ollama), "registry" (public download), "community" (user contribution)
208
+ embedSource String? @map("embed_source")
209
+ embedUpdatedAt DateTime? @map("embed_updated_at")
210
+
211
+ mod Mod @relation(fields: [modId], references: [id], onDelete: Cascade)
212
+
213
+ @@unique([modId, className])
214
+ @@index([modId])
215
+ @@map("mod_source_files")
216
+ }
217
+
218
+ // ── Version migration primers ──────────────────────────────────────────────────────────
219
+ // Documents that guide modders through upgrading mods from one MC/loader version to another.
220
+ // fromDataVersion / toDataVersion store the integer data_version from mcmeta for numeric range queries.
221
+
222
+ model Primer {
223
+ id Int @id @default(autoincrement())
224
+ /// Minecraft version this primer starts at, e.g. "1.20.4"
225
+ fromVersion String @map("from_version")
226
+ /// Minecraft version this primer targets, e.g. "1.21.1"
227
+ toVersion String @map("to_version")
228
+ /// Numeric data_version from mcmeta for ordering/range queries
229
+ fromDataVersion Int? @map("from_data_version")
230
+ toDataVersion Int? @map("to_data_version")
231
+ /// Mod loader: neoforge | forge | fabric | quilt | vanilla | other
232
+ modloader String @default("neoforge")
233
+ title String
234
+ summary String?
235
+ url String @unique
236
+ /// Full text of the primer (optional — populated by ingest with fetch=true)
237
+ content String?
238
+ tags String[]
239
+ source String @default("manual")
240
+ createdAt DateTime @default(now()) @map("created_at")
241
+ updatedAt DateTime @updatedAt @map("updated_at")
242
+ /// pgvector embedding — populated by `npm run db:vector` + backfill-embeddings
243
+ embedding Unsupported("vector")? @map("embedding")
244
+
245
+ @@index([fromVersion, toVersion])
246
+ @@index([fromDataVersion, toDataVersion])
247
+ @@index([modloader])
248
+ @@map("primers")
249
+ }
250
+
251
+ // ── Modpack version tracking ──────────────────────────────────────────────────
252
+ // One row per (namespace, packId, versionId) that has been synced or inspected.
253
+
254
+ model PackVersion {
255
+ id Int @id @default(autoincrement())
256
+ /// "ftb" | "curseforge"
257
+ namespace String
258
+ packId Int @map("pack_id")
259
+ versionId Int @map("version_id")
260
+ packName String @map("pack_name")
261
+ versionName String @map("version_name")
262
+ mcVersion String? @map("mc_version")
263
+ modloader String?
264
+ syncedAt DateTime @default(now()) @map("synced_at")
265
+ updatedAt DateTime @updatedAt @map("updated_at")
266
+
267
+ files PackFile[]
268
+
269
+ @@unique([namespace, packId, versionId])
270
+ @@index([namespace, packId])
271
+ @@map("pack_versions")
272
+ }
273
+
274
+ // One row per file listed in a pack version manifest.
275
+ // Covers mods, configs, scripts, resource packs, and cf-extract overrides ZIPs.
276
+ // modId is set when the file was ingested as a Mod in this database.
277
+
278
+ model PackFile {
279
+ id Int @id @default(autoincrement())
280
+ packVersionId Int @map("pack_version_id")
281
+ packVersion PackVersion @relation(fields: [packVersionId], references: [id], onDelete: Cascade)
282
+ /// file.id from the modpacks.ch manifest
283
+ manifestFileId Int? @map("manifest_file_id")
284
+ /// "mod" | "resource" | "config" | "script" | "cf-extract" | "override" | etc.
285
+ fileType String @map("file_type")
286
+ fileName String @map("file_name")
287
+ /// Destination path relative to the pack root (from manifest file.path)
288
+ filePath String? @map("file_path")
289
+ cfProject Int? @map("cf_project")
290
+ cfFile Int? @map("cf_file")
291
+ sha1 String?
292
+ /// "ingested" | "already_ingested" | "downloaded_zip" | "error" | "skipped" | "not_synced"
293
+ status String @default("not_synced")
294
+ /// Set when this file was successfully ingested as a Mod row.
295
+ modId Int? @map("mod_id")
296
+ mod Mod? @relation(fields: [modId], references: [id], onDelete: SetNull)
297
+
298
+ @@unique([packVersionId, manifestFileId])
299
+ @@index([packVersionId])
300
+ @@index([modId])
301
+ @@index([cfProject])
302
+ @@map("pack_files")
303
+ }