@creeperhost/modlens-mcp 1.6.18 → 1.6.19

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 (179) hide show
  1. package/README.md +97 -10
  2. package/TESTING.md +69 -0
  3. package/dist/cli.js +21 -5
  4. package/dist/cli.js.map +1 -1
  5. package/dist/curseforge.d.ts +9 -7
  6. package/dist/curseforge.d.ts.map +1 -1
  7. package/dist/curseforge.js +48 -55
  8. package/dist/curseforge.js.map +1 -1
  9. package/dist/db.d.ts.map +1 -1
  10. package/dist/db.js +31 -1
  11. package/dist/db.js.map +1 -1
  12. package/dist/embeddings.d.ts.map +1 -1
  13. package/dist/embeddings.js +1 -0
  14. package/dist/embeddings.js.map +1 -1
  15. package/dist/feed-the-beast.d.ts +5 -5
  16. package/dist/feed-the-beast.d.ts.map +1 -1
  17. package/dist/feed-the-beast.js +5 -21
  18. package/dist/feed-the-beast.js.map +1 -1
  19. package/dist/java-tools.d.ts +1 -0
  20. package/dist/java-tools.d.ts.map +1 -1
  21. package/dist/java-tools.js +31 -7
  22. package/dist/java-tools.js.map +1 -1
  23. package/dist/launcher.js +15 -0
  24. package/dist/launcher.js.map +1 -1
  25. package/dist/mappings.d.ts +4 -1
  26. package/dist/mappings.d.ts.map +1 -1
  27. package/dist/mappings.js +120 -52
  28. package/dist/mappings.js.map +1 -1
  29. package/dist/minecraft.d.ts +0 -4
  30. package/dist/minecraft.d.ts.map +1 -1
  31. package/dist/minecraft.js +7 -23
  32. package/dist/minecraft.js.map +1 -1
  33. package/dist/mod-artifacts.d.ts +4 -0
  34. package/dist/mod-artifacts.d.ts.map +1 -0
  35. package/dist/mod-artifacts.js +58 -0
  36. package/dist/mod-artifacts.js.map +1 -0
  37. package/dist/modpacks-ch.d.ts +72 -46
  38. package/dist/modpacks-ch.d.ts.map +1 -1
  39. package/dist/modpacks-ch.js +134 -20
  40. package/dist/modpacks-ch.js.map +1 -1
  41. package/dist/modrinth.d.ts +14 -6
  42. package/dist/modrinth.d.ts.map +1 -1
  43. package/dist/modrinth.js +70 -55
  44. package/dist/modrinth.js.map +1 -1
  45. package/dist/platform-adapter.d.ts +1 -0
  46. package/dist/platform-adapter.d.ts.map +1 -1
  47. package/dist/platform.d.ts.map +1 -1
  48. package/dist/platform.js +20 -44
  49. package/dist/platform.js.map +1 -1
  50. package/dist/processor.d.ts +5 -0
  51. package/dist/processor.d.ts.map +1 -1
  52. package/dist/processor.js +166 -46
  53. package/dist/processor.js.map +1 -1
  54. package/dist/registry-submission.d.ts +34 -0
  55. package/dist/registry-submission.d.ts.map +1 -0
  56. package/dist/registry-submission.js +128 -0
  57. package/dist/registry-submission.js.map +1 -0
  58. package/dist/repositories/array-fields.d.ts +3 -0
  59. package/dist/repositories/array-fields.d.ts.map +1 -0
  60. package/dist/repositories/array-fields.js +8 -0
  61. package/dist/repositories/array-fields.js.map +1 -0
  62. package/dist/repositories/embeddings-sqlite.d.ts +1 -0
  63. package/dist/repositories/embeddings-sqlite.d.ts.map +1 -1
  64. package/dist/repositories/embeddings-sqlite.js +26 -58
  65. package/dist/repositories/embeddings-sqlite.js.map +1 -1
  66. package/dist/repositories/embeddings.d.ts.map +1 -1
  67. package/dist/repositories/embeddings.js +26 -3
  68. package/dist/repositories/embeddings.js.map +1 -1
  69. package/dist/repositories/index.d.ts +1 -1
  70. package/dist/repositories/index.d.ts.map +1 -1
  71. package/dist/repositories/mod.d.ts +8 -5
  72. package/dist/repositories/mod.d.ts.map +1 -1
  73. package/dist/repositories/mod.js +25 -11
  74. package/dist/repositories/mod.js.map +1 -1
  75. package/dist/repositories/packs.d.ts.map +1 -1
  76. package/dist/repositories/packs.js +10 -2
  77. package/dist/repositories/packs.js.map +1 -1
  78. package/dist/search-adapter.d.ts +2 -0
  79. package/dist/search-adapter.d.ts.map +1 -1
  80. package/dist/search-adapter.js +21 -9
  81. package/dist/search-adapter.js.map +1 -1
  82. package/dist/security.d.ts +2 -0
  83. package/dist/security.d.ts.map +1 -1
  84. package/dist/security.js +5 -1
  85. package/dist/security.js.map +1 -1
  86. package/dist/server.js +63 -25
  87. package/dist/server.js.map +1 -1
  88. package/dist/sqlite-json.d.ts +3 -0
  89. package/dist/sqlite-json.d.ts.map +1 -0
  90. package/dist/sqlite-json.js +78 -0
  91. package/dist/sqlite-json.js.map +1 -0
  92. package/dist/sqlite-parameters.d.ts +3 -0
  93. package/dist/sqlite-parameters.d.ts.map +1 -0
  94. package/dist/sqlite-parameters.js +19 -0
  95. package/dist/sqlite-parameters.js.map +1 -0
  96. package/dist/sqlite-schema.d.ts +4 -0
  97. package/dist/sqlite-schema.d.ts.map +1 -0
  98. package/dist/sqlite-schema.js +76 -0
  99. package/dist/sqlite-schema.js.map +1 -0
  100. package/dist/tools/catalog.d.ts +1 -6
  101. package/dist/tools/catalog.d.ts.map +1 -1
  102. package/dist/tools/catalog.js +10 -14
  103. package/dist/tools/catalog.js.map +1 -1
  104. package/dist/tools/compat-check.d.ts.map +1 -1
  105. package/dist/tools/compat-check.js +18 -30
  106. package/dist/tools/compat-check.js.map +1 -1
  107. package/dist/tools/diagnostics.js.map +1 -1
  108. package/dist/tools/docs.d.ts.map +1 -1
  109. package/dist/tools/docs.js +8 -3
  110. package/dist/tools/docs.js.map +1 -1
  111. package/dist/tools/embed-registry.d.ts +20 -4
  112. package/dist/tools/embed-registry.d.ts.map +1 -1
  113. package/dist/tools/embed-registry.js +30 -19
  114. package/dist/tools/embed-registry.js.map +1 -1
  115. package/dist/tools/graphify.d.ts +19 -4
  116. package/dist/tools/graphify.d.ts.map +1 -1
  117. package/dist/tools/graphify.js +61 -13
  118. package/dist/tools/graphify.js.map +1 -1
  119. package/dist/tools/ingest.d.ts.map +1 -1
  120. package/dist/tools/ingest.js +4 -4
  121. package/dist/tools/ingest.js.map +1 -1
  122. package/dist/tools/kubejs.js +1 -1
  123. package/dist/tools/kubejs.js.map +1 -1
  124. package/dist/tools/mc-fts.d.ts.map +1 -1
  125. package/dist/tools/mc-fts.js +9 -4
  126. package/dist/tools/mc-fts.js.map +1 -1
  127. package/dist/tools/mcmeta.d.ts +10 -1
  128. package/dist/tools/mcmeta.d.ts.map +1 -1
  129. package/dist/tools/mcmeta.js +43 -29
  130. package/dist/tools/mcmeta.js.map +1 -1
  131. package/dist/tools/mixin-scan.d.ts +12 -6
  132. package/dist/tools/mixin-scan.d.ts.map +1 -1
  133. package/dist/tools/mixin-scan.js +12 -7
  134. package/dist/tools/mixin-scan.js.map +1 -1
  135. package/dist/tools/mod-data.d.ts.map +1 -1
  136. package/dist/tools/mod-data.js +40 -27
  137. package/dist/tools/mod-data.js.map +1 -1
  138. package/dist/tools/modpacks-ch.d.ts +9 -5
  139. package/dist/tools/modpacks-ch.d.ts.map +1 -1
  140. package/dist/tools/modpacks-ch.js +54 -33
  141. package/dist/tools/modpacks-ch.js.map +1 -1
  142. package/dist/tools/packtools.js +3 -3
  143. package/dist/tools/packtools.js.map +1 -1
  144. package/dist/tools/platform.d.ts +2 -2
  145. package/dist/tools/platform.d.ts.map +1 -1
  146. package/dist/tools/platform.js +33 -23
  147. package/dist/tools/platform.js.map +1 -1
  148. package/dist/tools/project.d.ts +342 -0
  149. package/dist/tools/project.d.ts.map +1 -0
  150. package/dist/tools/project.js +519 -0
  151. package/dist/tools/project.js.map +1 -0
  152. package/dist/tools/reports.d.ts.map +1 -1
  153. package/dist/tools/reports.js +5 -3
  154. package/dist/tools/reports.js.map +1 -1
  155. package/dist/tools/vanilla-data.d.ts.map +1 -1
  156. package/dist/tools/vanilla-data.js +3 -33
  157. package/dist/tools/vanilla-data.js.map +1 -1
  158. package/dist/tools/vanilla.d.ts +3 -1
  159. package/dist/tools/vanilla.d.ts.map +1 -1
  160. package/dist/tools/vanilla.js +26 -12
  161. package/dist/tools/vanilla.js.map +1 -1
  162. package/dist/tools/version-diff.d.ts.map +1 -1
  163. package/dist/tools/version-diff.js +4 -24
  164. package/dist/tools/version-diff.js.map +1 -1
  165. package/dist/version-ranges.d.ts +5 -0
  166. package/dist/version-ranges.d.ts.map +1 -0
  167. package/dist/version-ranges.js +93 -0
  168. package/dist/version-ranges.js.map +1 -0
  169. package/package.json +5 -1
  170. package/prisma/backends/template.db +0 -0
  171. package/scripts/build-template-db.mjs +3 -1
  172. package/scripts/enable-sqlite-vec.mjs +2 -106
  173. package/scripts/gradle/modlens.init.gradle +154 -0
  174. package/scripts/project-upload.mjs +74 -0
  175. package/scripts/test-minecraft-eras.mjs +202 -0
  176. package/scripts/test-package.mjs +8 -0
  177. package/scripts/test-project-gradle.mjs +76 -0
  178. package/scripts/test-project-http.mjs +98 -0
  179. package/scripts/test-setup.mjs +18 -0
package/dist/platform.js CHANGED
@@ -2,36 +2,27 @@ import { createWriteStream } from "fs";
2
2
  import { pipeline } from "stream/promises";
3
3
  import { join } from "path";
4
4
  import { CACHE_ROOT, ensureDir, exists } from "./cache.js";
5
- import { LEGACY_SRG_VERSIONS, LEGACY_RETROMCP_VERSIONS } from "./minecraft.js";
6
- const PISTON_META = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
7
- const NEOFORGE_MAVEN = "https://maven.neoforged.net/releases/net/neoforged/neoforge";
8
- const NEOFORGE_META = "https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge";
9
- const FORGE_MAVEN = "https://maven.minecraftforge.net/net/minecraftforge/forge";
5
+ import { fetchMcVersionList } from "./minecraft.js";
6
+ import { loaderVersions, providerVersions } from "./modpacks-ch.js";
7
+ const NEOFORGE_MAVEN = "https://maven.creeperhost.net/net/neoforged/neoforge";
8
+ const NEOFORGE_META = `${NEOFORGE_MAVEN}/maven-metadata.xml`;
9
+ const FORGE_MAVEN = "https://maven.creeperhost.net/net/minecraftforge/forge";
10
10
  const FORGE_PROMOS = "https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json";
11
- let mcCache = null;
12
11
  let neoforgeCache = null;
13
12
  let forgeCache = null;
14
13
  export async function listMcVersions(type) {
15
- if (!mcCache) {
16
- const res = await fetch(PISTON_META);
17
- if (!res.ok)
18
- throw new Error(`Failed to fetch MC versions: ${res.status}`);
19
- const data = await res.json();
20
- mcCache = data.versions.filter((v) => v.type !== "old_beta" && v.type !== "old_alpha" &&
21
- (new Date(v.releaseTime) >= new Date("2019-04-23") || LEGACY_SRG_VERSIONS.has(v.id) || LEGACY_RETROMCP_VERSIONS.has(v.id)));
22
- }
23
- if (!type || type === "all")
24
- return mcCache;
25
- if (type === "release")
26
- return mcCache.filter((v) => v.type === "release");
27
- return mcCache.filter((v) => v.type === "snapshot");
14
+ const versions = (await fetchMcVersionList(true)).map(({ id, type, releaseTime }) => ({ id, type, releaseTime }));
15
+ return !type || type === "all" ? versions : versions.filter(version => version.type === type);
28
16
  }
29
17
  export async function listNeoForgeVersions(mcVersion, limit = 20) {
18
+ if (mcVersion)
19
+ return (await loaderVersions(mcVersion, "neoforge")).slice(0, limit)
20
+ .map(v => ({ version: v.version, mcVersion: v.gameVersion ?? mcVersion }));
30
21
  if (!neoforgeCache) {
31
22
  const res = await fetch(NEOFORGE_META);
32
23
  if (!res.ok)
33
24
  throw new Error(`Failed to fetch NeoForge versions: ${res.status}`);
34
- const data = await res.json();
25
+ const data = { versions: [...(await res.text()).matchAll(/<version>([^<]+)<\/version>/g)].map(m => m[1]) };
35
26
  // NeoForge versions look like "21.1.0", "21.1.1", etc. — leading number = MC major
36
27
  neoforgeCache = data.versions
37
28
  .filter((v) => /^\d+\.\d+\.\d+/.test(v))
@@ -50,21 +41,17 @@ export async function listNeoForgeVersions(mcVersion, limit = 20) {
50
41
  return filtered.slice(0, limit);
51
42
  }
52
43
  export async function listFabricApiVersions(mcVersion, limit = 20) {
53
- // Fabric API project on Modrinth: P7dR8mSH
54
- const url = mcVersion
55
- ? `https://api.modrinth.com/v2/project/P7dR8mSH/version?game_versions=%5B%22${encodeURIComponent(mcVersion)}%22%5D&loaders=%5B%22fabric%22%5D`
56
- : `https://api.modrinth.com/v2/project/P7dR8mSH/version?loaders=%5B%22fabric%22%5D`;
57
- const res = await fetch(url, { headers: { "User-Agent": "modlens-mcp/1.0" } });
58
- if (!res.ok)
59
- throw new Error(`Failed to fetch Fabric API versions: ${res.status}`);
60
- const versions = await res.json();
61
- return versions.slice(0, limit).map((v) => ({
62
- version: v.version_number,
63
- mcVersion: v.game_versions[0] ?? "unknown",
64
- datePublished: v.date_published,
44
+ const versions = await providerVersions("mod", "P7dR8mSH", { mcVersion, loader: "fabric", limit });
45
+ return versions.map((v) => ({
46
+ version: v.version,
47
+ mcVersion: (v.targets ?? []).find(t => t.type === "game")?.version ?? "unknown",
48
+ datePublished: new Date((v.updated ?? 0) * 1000).toISOString(),
65
49
  }));
66
50
  }
67
51
  export async function listForgeVersions(mcVersion, limit = 20) {
52
+ if (mcVersion)
53
+ return (await loaderVersions(mcVersion, "forge")).slice(0, limit)
54
+ .map(v => ({ version: v.version, fullVersion: `${mcVersion}-${v.version}`, mcVersion: v.gameVersion ?? mcVersion }));
68
55
  if (!forgeCache) {
69
56
  // Fetch promotions to know which versions are recommended
70
57
  const promoRes = await fetch(FORGE_PROMOS, { headers: { "User-Agent": "modlens-mcp/1.0" } });
@@ -178,17 +165,6 @@ export async function downloadFabricApi(version) {
178
165
  const destPath = join(CACHE_ROOT, "loaders", "fabric-api", `fabric-api-${version}.jar`);
179
166
  if (await exists(destPath))
180
167
  return destPath;
181
- // Fetch the version file list from Modrinth
182
- const res = await fetch(`https://api.modrinth.com/v2/project/P7dR8mSH/version?loaders=%5B%22fabric%22%5D`, { headers: { "User-Agent": "modlens-mcp/1.0" } });
183
- if (!res.ok)
184
- throw new Error(`Modrinth lookup failed: ${res.status}`);
185
- const versions = await res.json();
186
- const match = versions.find((v) => v.version_number === version);
187
- if (!match)
188
- throw new Error(`Fabric API version "${version}" not found on Modrinth`);
189
- const file = match.files.find((f) => f.primary) ?? match.files[0];
190
- if (!file)
191
- throw new Error(`No download file found for Fabric API ${version}`);
192
- return downloadJar(file.url, destPath);
168
+ return downloadJar(`https://maven.creeperhost.net/net/fabricmc/fabric-api/fabric-api/${encodeURIComponent(version)}/fabric-api-${encodeURIComponent(version)}.jar`, destPath);
193
169
  }
194
170
  //# sourceMappingURL=platform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -24,11 +24,15 @@ export interface ParsedManifest {
24
24
  mixinTargets: string[];
25
25
  metadataSource: MetadataSource;
26
26
  }
27
+ /** Read every declared loader, including JARs that ship metadata for multiple loaders. */
28
+ export declare function inspectJarLoaders(jarPath: string): Promise<Array<Exclude<ParsedManifest["loader"], "unknown">>>;
27
29
  export declare function parseJar(jarPath: string): Promise<ParsedManifest>;
28
30
  interface ForgeModAnnotationResult {
29
31
  modId: string;
30
32
  name: string;
31
33
  version: string;
34
+ mcVersion: string;
35
+ dependencies: string;
32
36
  }
33
37
  /**
34
38
  * Scan class entries in a JAR for the Forge @Mod annotation.
@@ -41,6 +45,7 @@ export declare function parseClassForModAnnotation(buf: Buffer): ForgeModAnnotat
41
45
  export declare function parseAtEntries(content: string): string[];
42
46
  export declare function parseAwEntries(content: string): string[];
43
47
  export declare function computeHashes(jarPath: string): Promise<{
48
+ sha1: string;
44
49
  sha256: string;
45
50
  sha512: string;
46
51
  murmur2: string;
@@ -1 +1 @@
1
- {"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAM7B,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,UAAU,CAAC;AAEhI,qGAAqG;AACrG,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAO3D,CAAC;AAEF,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;KAAE,CAAC,CAAC;IACzE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA2GvE;AA4MD,UAAU,wBAAwB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAqBtF;AAED,sEAAsE;AACtE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAuEvF;AA4ID,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAeD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE,CAAC,CAMlH;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBnD"}
1
+ {"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAO7B,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,UAAU,CAAC;AAEhI,qGAAqG;AACrG,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAO3D,CAAC;AAEF,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;KAAE,CAAC,CAAC;IACzE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,0FAA0F;AAC1F,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAgCrH;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA4HvE;AA4PD,UAAU,wBAAwB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAqBtF;AAED,sEAAsE;AACtE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAwEvF;AA8ID,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAeD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE,CAAC,CAMhI;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBnD"}
package/dist/processor.js CHANGED
@@ -3,6 +3,7 @@ import { createHash } from "crypto";
3
3
  import { readFile } from "fs/promises";
4
4
  import { parse as parseToml } from "smol-toml";
5
5
  import { assertJarPath } from "./security.js";
6
+ import { normalizeVersionRange } from "./version-ranges.js";
6
7
  /** Higher = better quality metadata. Used to decide whether re-parse upgrades an existing record. */
7
8
  export const METADATA_QUALITY = {
8
9
  "filename": 0,
@@ -12,6 +13,49 @@ export const METADATA_QUALITY = {
12
13
  "quilt.mod.json": 3,
13
14
  "fabric.mod.json": 3,
14
15
  };
16
+ /** Read every declared loader, including JARs that ship metadata for multiple loaders. */
17
+ export async function inspectJarLoaders(jarPath) {
18
+ assertJarPath(jarPath);
19
+ const zip = new AdmZip(jarPath);
20
+ const readEntry = (name) => zip.readAsText(name) || null;
21
+ const loaders = new Set();
22
+ const addManifest = (parse) => {
23
+ try {
24
+ const manifest = parse();
25
+ if (manifest.loader !== "unknown" && manifest.modId && manifest.modId !== "unknown")
26
+ loaders.add(manifest.loader);
27
+ }
28
+ catch {
29
+ // Invalid metadata is not loader evidence; another declaration may be valid.
30
+ }
31
+ };
32
+ const fabric = readEntry("fabric.mod.json");
33
+ const quilt = readEntry("quilt.mod.json");
34
+ const forge = readEntry("META-INF/mods.toml");
35
+ const neoforge = readEntry("META-INF/neoforge.mods.toml");
36
+ const legacy = readEntry("mcmod.info");
37
+ if (fabric)
38
+ addManifest(() => parseFabric(fabric, []));
39
+ if (quilt)
40
+ addManifest(() => parseQuilt(quilt, []));
41
+ if (forge)
42
+ addManifest(() => parseForgeToml(forge, "forge", [], readEntry));
43
+ if (neoforge)
44
+ addManifest(() => parseForgeToml(neoforge, "neoforge", [], readEntry));
45
+ if (legacy)
46
+ addManifest(() => parseMcModInfo(legacy, []));
47
+ if (!loaders.size) {
48
+ // Annotation-only FML mods have no metadata file. Never guess from a filename.
49
+ try {
50
+ if (extractForgeModAnnotation(zip)?.modId)
51
+ loaders.add("forge");
52
+ }
53
+ catch {
54
+ // Unrecognised bytecode provides no loader evidence.
55
+ }
56
+ }
57
+ return [...loaders];
58
+ }
15
59
  export async function parseJar(jarPath) {
16
60
  assertJarPath(jarPath);
17
61
  const zip = new AdmZip(jarPath);
@@ -20,6 +64,7 @@ export async function parseJar(jarPath) {
20
64
  const e = zip.getEntry(name);
21
65
  return e ? zip.readFile(e)?.toString("utf8") ?? null : null;
22
66
  };
67
+ const jarAttributes = parseJarAttributes(readEntry("META-INF/MANIFEST.MF") ?? "");
23
68
  // Detect loader
24
69
  const fabricJson = readEntry("fabric.mod.json");
25
70
  const quiltJson = readEntry("quilt.mod.json");
@@ -33,19 +78,19 @@ export async function parseJar(jarPath) {
33
78
  manifest = parseQuilt(quiltJson, entries);
34
79
  }
35
80
  else if (neoforgeToml) {
36
- manifest = parseNeoForge(neoforgeToml, entries);
81
+ manifest = parseForgeToml(neoforgeToml, "neoforge", entries, readEntry);
37
82
  }
38
83
  else if (forgeToml) {
39
- manifest = parseForge(forgeToml, entries);
84
+ manifest = parseForgeToml(forgeToml, "forge", entries, readEntry);
40
85
  }
41
86
  else {
42
- // Legacy Forge (1.7.10–1.12.2) uses mcmod.info at the JAR root
87
+ // FML-era mods can provide mcmod.info, an @Mod annotation, or both.
43
88
  const mcmodInfoRaw = readEntry("mcmod.info");
44
89
  if (mcmodInfoRaw) {
45
90
  manifest = parseMcModInfo(mcmodInfoRaw, entries);
46
91
  }
47
92
  else {
48
- // Pre-mcmod.info era (1.2.5–1.6) try @Mod annotation from bytecode
93
+ // Annotation metadata is also used by mods that omit mcmod.info.
49
94
  let modAnnotation = null;
50
95
  try {
51
96
  modAnnotation = extractForgeModAnnotation(zip);
@@ -54,16 +99,16 @@ export async function parseJar(jarPath) {
54
99
  // Malformed class files (obfuscators, Kotlin metadata, etc.) — degrade gracefully
55
100
  }
56
101
  if (modAnnotation) {
57
- const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
102
+ const mixinConfigs = mixinConfigNames(entries);
58
103
  manifest = {
59
104
  modId: modAnnotation.modId,
60
105
  displayName: modAnnotation.name,
61
106
  version: modAnnotation.version,
62
- mcVersion: "",
107
+ mcVersion: modAnnotation.mcVersion,
63
108
  loader: "forge",
64
109
  description: "",
65
110
  sourceUrl: null,
66
- dependencies: [],
111
+ dependencies: parseLegacyDependencies(modAnnotation.dependencies.split(";")),
67
112
  mixinConfigs,
68
113
  hasMixins: mixinConfigs.length > 0,
69
114
  hasAt: entries.includes("META-INF/accesstransformer.cfg"),
@@ -79,12 +124,27 @@ export async function parseJar(jarPath) {
79
124
  }
80
125
  }
81
126
  }
82
- // AT entries
83
- const atContent = readEntry("META-INF/accesstransformer.cfg");
84
- if (atContent) {
85
- manifest.hasAt = true;
86
- manifest.atEntries = parseAtEntries(atContent);
127
+ if (manifest.version === "${file.jarVersion}" && jarAttributes["implementation-version"]) {
128
+ manifest.version = jarAttributes["implementation-version"];
129
+ }
130
+ // Legacy FML names AT files in the manifest; later Forge uses a fixed path.
131
+ const atPaths = new Set(["META-INF/accesstransformer.cfg"]);
132
+ for (const name of (jarAttributes.fmlat ?? "").split(/\s+/).filter(Boolean)) {
133
+ atPaths.add(name.startsWith("META-INF/") ? name : `META-INF/${name}`);
134
+ }
135
+ for (const path of atPaths) {
136
+ const content = readEntry(path);
137
+ if (content !== null) {
138
+ manifest.hasAt = true;
139
+ manifest.atEntries.push(...parseAtEntries(content));
140
+ }
87
141
  }
142
+ manifest.atEntries = [...new Set(manifest.atEntries)];
143
+ manifest.mixinConfigs = [...new Set([
144
+ ...manifest.mixinConfigs,
145
+ ...(jarAttributes.mixinconfigs ?? "").split(",").map(name => name.trim()).filter(name => entries.includes(name)),
146
+ ])];
147
+ manifest.hasMixins = manifest.mixinConfigs.length > 0;
88
148
  // AW entries — scan all entries for *.accesswidener
89
149
  const awEntry = entries.find((e) => e.endsWith(".accesswidener"));
90
150
  if (awEntry) {
@@ -116,6 +176,26 @@ export async function parseJar(jarPath) {
116
176
  }
117
177
  return manifest;
118
178
  }
179
+ /** JAR manifest main attributes, with continuation lines unfolded per the JAR format. */
180
+ function parseJarAttributes(content) {
181
+ const main = content.replace(/\r?\n /g, "").split(/\r?\n\r?\n/, 1)[0];
182
+ const attributes = {};
183
+ for (const line of main.split(/\r?\n/)) {
184
+ const separator = line.indexOf(": ");
185
+ if (separator > 0)
186
+ attributes[line.slice(0, separator).toLowerCase()] = line.slice(separator + 2);
187
+ }
188
+ return attributes;
189
+ }
190
+ function mixinConfigNames(entries, declared) {
191
+ const values = Array.isArray(declared) ? declared : declared ? [declared] : [];
192
+ const names = values.map(value => typeof value === "string" ? value
193
+ : value && typeof value === "object" ? value.config : undefined);
194
+ return [...new Set([
195
+ ...names.filter((name) => typeof name === "string" && entries.includes(name)),
196
+ ...entries.filter(name => name.endsWith(".mixins.json") || /(^|\/)mixins\.[^/]+\.json$/.test(name)),
197
+ ])];
198
+ }
119
199
  function parseFabric(raw, entries) {
120
200
  let json;
121
201
  try {
@@ -124,11 +204,20 @@ function parseFabric(raw, entries) {
124
204
  catch {
125
205
  json = {};
126
206
  }
127
- const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
207
+ const mixinConfigs = mixinConfigNames(entries, json.mixins);
128
208
  const deps = [];
129
209
  const rawDeps = (json.depends ?? {});
130
210
  for (const [id, ver] of Object.entries(rawDeps)) {
131
- deps.push({ id, version: ver, required: true });
211
+ deps.push({ id, version: normalizeVersionRange(ver), required: true });
212
+ }
213
+ for (const field of ["recommends", "suggests"]) {
214
+ const optional = json[field];
215
+ if (!optional || typeof optional !== "object")
216
+ continue;
217
+ for (const [id, ver] of Object.entries(optional)) {
218
+ if (!deps.some(dep => dep.id === id))
219
+ deps.push({ id, version: normalizeVersionRange(ver), required: false });
220
+ }
132
221
  }
133
222
  return {
134
223
  modId: String(json.id ?? "unknown"),
@@ -158,16 +247,26 @@ function parseQuilt(raw, entries) {
158
247
  json = {};
159
248
  }
160
249
  const ql = (json.quilt_loader ?? {});
161
- const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
250
+ const mixinConfigs = mixinConfigNames(entries, json.mixin);
251
+ const metadata = (ql.metadata ?? {});
252
+ const dependencies = [];
253
+ for (const value of Array.isArray(ql.depends) ? ql.depends : []) {
254
+ if (typeof value === "string")
255
+ dependencies.push({ id: value, version: "*", required: true });
256
+ else if (value && typeof value.id === "string")
257
+ dependencies.push({
258
+ id: value.id, version: normalizeVersionRange(value.versions) || "*", required: value.optional !== true,
259
+ });
260
+ }
162
261
  return {
163
262
  modId: String(ql.id ?? "unknown"),
164
263
  displayName: String(ql.metadata?.name ?? ql.id ?? "unknown"),
165
264
  version: String(ql.version ?? "0.0.0"),
166
- mcVersion: "",
265
+ mcVersion: dependencies.find(dep => dep.id === "minecraft")?.version ?? "",
167
266
  loader: "quilt",
168
- description: "",
169
- sourceUrl: null,
170
- dependencies: [],
267
+ description: typeof metadata.description === "string" ? metadata.description : "",
268
+ sourceUrl: extractString(metadata, "contact", "sources"),
269
+ dependencies,
171
270
  mixinConfigs,
172
271
  hasMixins: mixinConfigs.length > 0,
173
272
  hasAt: false,
@@ -178,13 +277,7 @@ function parseQuilt(raw, entries) {
178
277
  metadataSource: "quilt.mod.json",
179
278
  };
180
279
  }
181
- function parseNeoForge(raw, entries) {
182
- return parseForgeToml(raw, "neoforge", entries);
183
- }
184
- function parseForge(raw, entries) {
185
- return parseForgeToml(raw, "forge", entries);
186
- }
187
- function parseForgeToml(raw, loader, entries) {
280
+ function parseForgeToml(raw, loader, entries, readEntry) {
188
281
  let doc;
189
282
  try {
190
283
  doc = parseToml(raw);
@@ -213,19 +306,31 @@ function parseForgeToml(raw, loader, entries) {
213
306
  if (Array.isArray(v))
214
307
  allDepObjs.push(...v);
215
308
  }
309
+ // Early NeoForge versions still used mods.toml.
310
+ if (modId === "neoforge" || allDepObjs.some(dep => dep.modId === "neoforge"))
311
+ loader = "neoforge";
216
312
  const mcDepEntry = allDepObjs.find((d) => str(d.modId) === "minecraft");
217
313
  const mcVersion = str(mcDepEntry?.versionRange);
218
314
  const dependencies = allDepObjs
219
315
  .filter((d) => {
220
316
  const id = str(d.modId);
221
- return id && id !== "minecraft" && id !== "neoforge" && id !== "forge";
317
+ return id && id !== "minecraft" && id !== "neoforge" && id !== "forge"
318
+ && d.type !== "incompatible" && d.type !== "discouraged";
222
319
  })
223
320
  .map((d) => ({
224
321
  id: str(d.modId),
225
322
  version: str(d.versionRange, "*"),
226
- required: d.mandatory !== false,
323
+ required: d.type ? d.type === "required" : d.mandatory !== false,
227
324
  }));
228
- const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
325
+ const mixinConfigs = mixinConfigNames(entries, doc.mixins);
326
+ const atEntries = [];
327
+ for (const at of Array.isArray(doc.accessTransformers) ? doc.accessTransformers : []) {
328
+ if (typeof at?.file !== "string")
329
+ continue;
330
+ const content = readEntry(at.file);
331
+ if (content !== null)
332
+ atEntries.push(...parseAtEntries(content));
333
+ }
229
334
  return {
230
335
  modId,
231
336
  displayName,
@@ -237,9 +342,9 @@ function parseForgeToml(raw, loader, entries) {
237
342
  dependencies,
238
343
  mixinConfigs,
239
344
  hasMixins: mixinConfigs.length > 0,
240
- hasAt: entries.includes("META-INF/accesstransformer.cfg"),
345
+ hasAt: entries.includes("META-INF/accesstransformer.cfg") || atEntries.length > 0,
241
346
  hasAw: false,
242
- atEntries: [],
347
+ atEntries,
243
348
  awEntries: [],
244
349
  mixinTargets: [],
245
350
  metadataSource: "mods.toml",
@@ -271,21 +376,11 @@ function parseMcModInfo(raw, entries) {
271
376
  return unknownMod("mcmod.info");
272
377
  const str = (v, fallback = "") => (typeof v === "string" ? v : fallback);
273
378
  const modId = str(mod.modid ?? mod.modId, "unknown");
274
- const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
379
+ const mixinConfigs = mixinConfigNames(entries);
275
380
  // Dependencies — handle multiple legacy formats
276
381
  const rawDeps = Array.isArray(mod.dependencies) ? mod.dependencies : [];
277
382
  const rawRequired = Array.isArray(mod.requiredMods) ? mod.requiredMods : [];
278
- const allDeps = [...rawDeps, ...rawRequired];
279
- const dependencies = allDeps
280
- .filter((d) => typeof d === "string")
281
- .filter((d) => d !== "Forge" && d !== "forge" && d !== "FML" && d !== "mcp" && d !== "minecraft")
282
- // Strip version ranges from dependency strings like "required-after:SomeLib@[1.0,)"
283
- .map((d) => {
284
- const depMatch = d.match(/^(?:required-after|after|required-before|before|required):?\s*([^@\s;]+)/i);
285
- return depMatch ? depMatch[1] : d;
286
- })
287
- .filter((d) => d !== "Forge" && d !== "forge" && d !== "FML")
288
- .map((d) => ({ id: d, version: "*", required: true }));
383
+ const dependencies = parseLegacyDependencies(rawDeps, rawRequired);
289
384
  return {
290
385
  modId,
291
386
  displayName: str(mod.name, modId),
@@ -305,6 +400,27 @@ function parseMcModInfo(raw, entries) {
305
400
  metadataSource: "mcmod.info",
306
401
  };
307
402
  }
403
+ function parseLegacyDependencies(declarations, requiredMods = []) {
404
+ const dependencies = new Map();
405
+ for (const [values, required] of [[declarations, false], [requiredMods, true]]) {
406
+ for (const value of values) {
407
+ if (typeof value !== "string")
408
+ continue;
409
+ const match = value.trim().match(/^(?:(required-(?:after|before)|after|before|required):)?([^@\s;]+)(?:@(.+))?$/i);
410
+ if (!match)
411
+ continue;
412
+ const [, order = "", id, version = "*"] = match;
413
+ if (["forge", "fml", "mcp", "minecraft", "*"].includes(id.toLowerCase()))
414
+ continue;
415
+ const previous = dependencies.get(id);
416
+ dependencies.set(id, {
417
+ id, version: version === "*" ? previous?.version ?? "*" : version,
418
+ required: required || order.toLowerCase().startsWith("required") || previous?.required === true,
419
+ });
420
+ }
421
+ }
422
+ return [...dependencies.values()];
423
+ }
308
424
  // ── @Mod annotation extraction from bytecode ──────────────────────────────────
309
425
  const FORGE_MOD_DESCRIPTORS = new Set([
310
426
  "Lcpw/mods/fml/common/Mod;", // Forge 1.7.10 and earlier
@@ -345,6 +461,8 @@ export function extractForgeModAnnotation(zip) {
345
461
  }
346
462
  /** Parse a single .class file's bytes for a Forge @Mod annotation. */
347
463
  export function parseClassForModAnnotation(buf) {
464
+ if (buf.length < 10)
465
+ return null;
348
466
  if (buf.readUInt32BE(0) !== 0xCAFEBABE)
349
467
  return null;
350
468
  // ── Parse constant pool ──
@@ -494,6 +612,8 @@ function parseModAnnotationAttr(buf, start, cpUtf8) {
494
612
  modId,
495
613
  name: values["name"] ?? modId,
496
614
  version: values["version"] ?? "0.0.0",
615
+ mcVersion: values["acceptedMinecraftVersions"] ?? "",
616
+ dependencies: values["dependencies"] ?? "",
497
617
  };
498
618
  }
499
619
  }
@@ -592,7 +712,7 @@ function unknownMod(jarPath) {
592
712
  export function parseAtEntries(content) {
593
713
  return content
594
714
  .split("\n")
595
- .map((l) => l.trim())
715
+ .map((l) => l.split("#", 1)[0].trim())
596
716
  .filter((l) => l && !l.startsWith("#"));
597
717
  }
598
718
  export function parseAwEntries(content) {
@@ -602,7 +722,7 @@ export function parseAwEntries(content) {
602
722
  .filter((l) => l && !l.startsWith("#") && !l.startsWith("accessWidener"));
603
723
  }
604
724
  function extractFabricMcVersion(deps) {
605
- return deps["minecraft"] ?? "";
725
+ return normalizeVersionRange(deps["minecraft"]);
606
726
  }
607
727
  function extractString(obj, ...keys) {
608
728
  let cur = obj;
@@ -618,7 +738,7 @@ export async function computeHashes(jarPath) {
618
738
  const sha256 = createHash("sha256").update(buf).digest("hex");
619
739
  const sha512 = createHash("sha512").update(buf).digest("hex");
620
740
  const murmur2 = computeMurmur2(buf).toString();
621
- return { sha256, sha512, murmur2 };
741
+ return { sha1: createHash("sha1").update(buf).digest("hex"), sha256, sha512, murmur2 };
622
742
  }
623
743
  /** CurseForge Murmur2 hash — matches CF API fingerprint (whitespace-normalized). */
624
744
  export function computeMurmur2(data) {