@adhisang/minecraft-modding-mcp 6.3.0 → 7.0.0-rc.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.
- package/CHANGELOG.md +90 -0
- package/README.md +13 -3
- package/dist/cache-policy.d.ts +71 -0
- package/dist/cache-policy.js +83 -0
- package/dist/cache-registry.js +45 -8
- package/dist/cli.js +74 -3
- package/dist/compat-stdio-transport.d.ts +1 -1
- package/dist/compat-stdio-transport.js +13 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +8 -2
- package/dist/decompiler/vineflower.d.ts +1 -0
- package/dist/decompiler/vineflower.js +8 -5
- package/dist/entry-tools/analyze-mod-service.d.ts +70 -136
- package/dist/entry-tools/analyze-symbol-service.d.ts +112 -150
- package/dist/entry-tools/compare-minecraft-service.d.ts +59 -145
- package/dist/entry-tools/entry-tool-schema.d.ts +38 -4
- package/dist/entry-tools/entry-tool-schema.js +4 -1
- package/dist/entry-tools/inspect-minecraft/internal.d.ts +235 -799
- package/dist/entry-tools/inspect-minecraft/internal.js +50 -13
- package/dist/entry-tools/inspect-minecraft-service.d.ts +372 -1736
- package/dist/entry-tools/manage-cache-service.d.ts +81 -91
- package/dist/entry-tools/validate-project/cases/mixin.js +26 -6
- package/dist/entry-tools/validate-project/cases/project-summary.d.ts +7 -7
- package/dist/entry-tools/validate-project-service.d.ts +164 -592
- package/dist/entry-tools/verify-mixin-target-service.d.ts +3 -19
- package/dist/entry-tools/verify-mixin-target-service.js +19 -1
- package/dist/era-classifier.d.ts +161 -0
- package/dist/era-classifier.js +292 -0
- package/dist/error-mapping.d.ts +76 -0
- package/dist/error-mapping.js +116 -8
- package/dist/index.d.ts +42 -4
- package/dist/index.js +636 -473
- package/dist/java-process.d.ts +2 -0
- package/dist/java-process.js +22 -2
- package/dist/json-rpc-framing.d.ts +77 -1
- package/dist/json-rpc-framing.js +249 -13
- package/dist/mapping/loaders/tiny-loom-selection.d.ts +88 -0
- package/dist/mapping/loaders/tiny-loom-selection.js +223 -0
- package/dist/mapping/loaders/tiny-loom.js +45 -33
- package/dist/mapping/loaders/tiny-maven.js +6 -11
- package/dist/mapping/parsers/tiny.d.ts +57 -0
- package/dist/mapping/parsers/tiny.js +99 -22
- package/dist/mapping-service.d.ts +19 -0
- package/dist/mapping-service.js +93 -9
- package/dist/maven-resolver.d.ts +18 -0
- package/dist/maven-resolver.js +20 -0
- package/dist/mcp-helpers.d.ts +19 -2
- package/dist/mcp-helpers.js +58 -9
- package/dist/minecraft-explorer-service.d.ts +1 -1
- package/dist/mixin/types.d.ts +8 -0
- package/dist/mod-analyzer.js +7 -7
- package/dist/mod-decompile-service.js +1 -0
- package/dist/nbt/java-nbt-codec.js +12 -2
- package/dist/nbt/json-patch.js +14 -3
- package/dist/nbt/pipeline.js +40 -3
- package/dist/nbt/typed-json.js +26 -1
- package/dist/registration-adapter.d.ts +32 -0
- package/dist/registration-adapter.js +52 -0
- package/dist/repo-downloader.d.ts +165 -0
- package/dist/repo-downloader.js +568 -10
- package/dist/request-context.d.ts +7 -0
- package/dist/request-context.js +9 -0
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +25 -19
- package/dist/server-identity.d.ts +27 -0
- package/dist/server-identity.js +26 -0
- package/dist/source/access-validate.js +53 -0
- package/dist/source/artifact-resolver.d.ts +81 -2
- package/dist/source/artifact-resolver.js +227 -15
- package/dist/source/class-source.d.ts +36 -0
- package/dist/source/class-source.js +222 -38
- package/dist/source/did-you-mean.d.ts +12 -1
- package/dist/source/did-you-mean.js +6 -2
- package/dist/source/file-access.js +150 -46
- package/dist/source/indexer.js +1 -0
- package/dist/source/shared-utils.d.ts +21 -0
- package/dist/source/shared-utils.js +23 -0
- package/dist/source-resolver.js +224 -57
- package/dist/source-service.d.ts +12 -1
- package/dist/stdio-supervisor.d.ts +357 -2
- package/dist/stdio-supervisor.js +1031 -80
- package/dist/storage/db.d.ts +2 -1
- package/dist/storage/db.js +15 -8
- package/dist/synthetic-decorator.d.ts +24 -0
- package/dist/synthetic-decorator.js +48 -0
- package/dist/tool-guidance.d.ts +17 -1
- package/dist/tool-guidance.js +323 -18
- package/dist/tool-schema-registry.d.ts +2 -0
- package/dist/tool-schema-registry.js +4 -0
- package/dist/tool-schemas.d.ts +2212 -3919
- package/dist/tool-schemas.js +33 -7
- package/dist/types.d.ts +35 -0
- package/dist/v1-parity-schemas.d.ts +7 -0
- package/dist/v1-parity-schemas.js +5584 -0
- package/dist/version-diff-service.d.ts +33 -0
- package/dist/version-diff-service.js +148 -3
- package/dist/version-service.js +36 -14
- package/dist/warning-details.js +18 -1
- package/docs/README-ja.md +5 -3
- package/docs/tool-reference.md +196 -19
- package/package.json +13 -8
|
@@ -14,6 +14,7 @@ import { resolveTinyRemapperJar } from "../tiny-remapper-resolver.js";
|
|
|
14
14
|
import { isUnobfuscatedVersion } from "../version-service.js";
|
|
15
15
|
import { dedupeQualityFlags, normalizeMapping, normalizeOptionalString, normalizePathStyle } from "./shared-utils.js";
|
|
16
16
|
const VERSION_TOKEN_REGEX_CACHE = new Map();
|
|
17
|
+
const LOADER_VERSION_TOKEN_REGEX_CACHE = new Map();
|
|
17
18
|
const MAX_HELPER_REGEX_CACHE = 128;
|
|
18
19
|
function rememberCachedRegex(cache, key, regex) {
|
|
19
20
|
if (cache.size >= MAX_HELPER_REGEX_CACHE) {
|
|
@@ -57,6 +58,97 @@ export function hasExactVersionToken(path, version) {
|
|
|
57
58
|
?? rememberCachedRegex(VERSION_TOKEN_REGEX_CACHE, normalizedVersion, new RegExp(`(^|[^0-9a-z])${escapeRegexLiteral(normalizedVersion)}(?![0-9a-z]|\\.[0-9])`, "i"));
|
|
58
59
|
return pattern.test(normalizedPath);
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* True when a path carries the NeoForge/Forge loader version that corresponds
|
|
63
|
+
* 1:1 to `mcVersion`.
|
|
64
|
+
*
|
|
65
|
+
* ModDevGradle names every artifact after the LOADER version and never after
|
|
66
|
+
* Minecraft: MC 1.21.11 produces `build/moddev/artifacts/neoforge-21.11.38-beta-merged.jar`.
|
|
67
|
+
* A plain `hasExactVersionToken(path, "1.21.11")` therefore rejected every
|
|
68
|
+
* artifact of the canonical NeoForge workspace, which made
|
|
69
|
+
* validate-access-transformer unusable there.
|
|
70
|
+
*
|
|
71
|
+
* NeoForge derives its version from Minecraft as `<minor>.<patch>.<build>`, so
|
|
72
|
+
* `1.21.11` -> `21.11.<build>` and `1.21` -> `21.0.<build>`. The trailing dot
|
|
73
|
+
* before the build number keeps `21.1.` from matching `21.10.5`.
|
|
74
|
+
*/
|
|
75
|
+
export function hasLoaderRuntimeVersionToken(path, mcVersion) {
|
|
76
|
+
const match = /^1\.(\d+)(?:\.(\d+))?$/.exec(mcVersion.trim());
|
|
77
|
+
if (!match) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const minor = match[1];
|
|
81
|
+
const patch = match[2] ?? "0";
|
|
82
|
+
const normalizedPath = normalizePathStyle(path).toLowerCase();
|
|
83
|
+
const cacheKey = `loader:${minor}.${patch}`;
|
|
84
|
+
const pattern = LOADER_VERSION_TOKEN_REGEX_CACHE.get(cacheKey)
|
|
85
|
+
?? rememberCachedRegex(LOADER_VERSION_TOKEN_REGEX_CACHE, cacheKey, new RegExp(`(^|[^0-9a-z.])${minor}\\.${patch}\\.\\d`, "i"));
|
|
86
|
+
return pattern.test(normalizedPath);
|
|
87
|
+
}
|
|
88
|
+
const RUNTIME_JAR_VERSION_REGEX = /(?:^|[^0-9.])(1\.\d+(?:\.\d+)?)(?![0-9.])/;
|
|
89
|
+
/**
|
|
90
|
+
* Minecraft version a runtime jar path carries, or undefined when the path
|
|
91
|
+
* names none. Loom lays its cache out as
|
|
92
|
+
* `<gradle>/caches/fabric-loom/<mcVersion>/...`, so the first `1.x[.y]` token
|
|
93
|
+
* of the path is the version the jar was built for.
|
|
94
|
+
*/
|
|
95
|
+
export function inferRuntimeJarMinecraftVersion(path) {
|
|
96
|
+
return RUNTIME_JAR_VERSION_REGEX.exec(normalizePathStyle(path))?.[1];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Loader a runtime jar belongs to, read from its path.
|
|
100
|
+
*
|
|
101
|
+
* A Loom cache holds NeoForge-patched jars under a `/neoforge/` segment
|
|
102
|
+
* (`caches/fabric-loom/1.21.10/neoforge/21.10.50-beta/minecraft-merged-mojang-at-patched.jar`).
|
|
103
|
+
* Serving one of those to a Fabric workspace silently validated a Fabric access
|
|
104
|
+
* widener against NeoForge bytecode, so the loader has to travel with the jar.
|
|
105
|
+
*/
|
|
106
|
+
export function inferRuntimeJarLoader(path) {
|
|
107
|
+
const lower = normalizePathStyle(path).toLowerCase();
|
|
108
|
+
if (lower.includes("neoforge") || lower.includes("neoform") || lower.includes("moddev")) {
|
|
109
|
+
return "neoforge";
|
|
110
|
+
}
|
|
111
|
+
if (/(^|[/\-_])forge([/\-_.]|$)/.test(lower) || lower.includes("forge_gradle") || lower.includes("srg")) {
|
|
112
|
+
return "forge";
|
|
113
|
+
}
|
|
114
|
+
if (lower.includes("fabric-loom") || lower.includes("loom-cache") || lower.includes("intermediary")) {
|
|
115
|
+
return "fabric";
|
|
116
|
+
}
|
|
117
|
+
return "unknown";
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Fills in the truthful version/loader half of a runtime provenance record.
|
|
121
|
+
*
|
|
122
|
+
* `version` becomes the version the SERVED jar carries; the caller's original
|
|
123
|
+
* request is preserved under `requestedVersion` and flagged. A served loader
|
|
124
|
+
* that contradicts a KNOWN expected loader is flagged too — never silently
|
|
125
|
+
* dropped.
|
|
126
|
+
*/
|
|
127
|
+
export function describeServedRuntimeJar(input) {
|
|
128
|
+
const notes = [];
|
|
129
|
+
const servedVersion = inferRuntimeJarMinecraftVersion(input.jarPath);
|
|
130
|
+
const versionApproximated = servedVersion !== undefined && servedVersion !== input.requestedVersion.trim();
|
|
131
|
+
const servedLoader = inferRuntimeJarLoader(input.jarPath);
|
|
132
|
+
const expectedLoader = input.expectedLoader;
|
|
133
|
+
const loaderMismatch = expectedLoader !== undefined &&
|
|
134
|
+
expectedLoader !== "unknown" &&
|
|
135
|
+
servedLoader !== "unknown" &&
|
|
136
|
+
servedLoader !== expectedLoader;
|
|
137
|
+
if (versionApproximated) {
|
|
138
|
+
notes.push(`Runtime jar is Minecraft ${servedVersion}, not the requested ${input.requestedVersion}; results are approximate.`);
|
|
139
|
+
}
|
|
140
|
+
if (loaderMismatch) {
|
|
141
|
+
notes.push(`Runtime jar is a ${servedLoader} artifact while the workspace is ${expectedLoader}; its bytecode differs from the ${expectedLoader} runtime.`);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
version: versionApproximated && servedVersion ? servedVersion : input.requestedVersion,
|
|
145
|
+
...(versionApproximated ? { requestedVersion: input.requestedVersion, versionApproximated: true } : {}),
|
|
146
|
+
servedLoader,
|
|
147
|
+
...(expectedLoader ? { expectedLoader } : {}),
|
|
148
|
+
...(loaderMismatch ? { loaderMismatch: true } : {}),
|
|
149
|
+
notes
|
|
150
|
+
};
|
|
151
|
+
}
|
|
60
152
|
function inferMergedRuntimeNamespaceHint(path) {
|
|
61
153
|
const normalizedPath = normalizePathStyle(path).toLowerCase();
|
|
62
154
|
if (normalizedPath.includes("merged-intermediary-v2") ||
|
|
@@ -407,6 +499,11 @@ export async function discoverAccessTransformerRuntimeCandidates(_svc, input) {
|
|
|
407
499
|
const normalizedProjectPathLower = normalizedProjectPath
|
|
408
500
|
? normalizePathStyle(normalizedProjectPath).toLowerCase()
|
|
409
501
|
: undefined;
|
|
502
|
+
// A jar inside the caller's own build directory belongs to the version that
|
|
503
|
+
// workspace declares, whatever its filename says.
|
|
504
|
+
const projectAnchorAllowed = normalizedProjectPathLower !== undefined &&
|
|
505
|
+
input.projectMinecraftVersion !== undefined &&
|
|
506
|
+
input.projectMinecraftVersion.trim() === input.version.trim();
|
|
410
507
|
const searchRoots = buildLoaderRuntimeSearchRoots({
|
|
411
508
|
projectPath: normalizedProjectPath,
|
|
412
509
|
gradleUserHome: input.gradleUserHome
|
|
@@ -449,7 +546,17 @@ export async function discoverAccessTransformerRuntimeCandidates(_svc, input) {
|
|
|
449
546
|
}
|
|
450
547
|
seen.add(normalizedPath);
|
|
451
548
|
const lower = normalizedPath.toLowerCase();
|
|
452
|
-
|
|
549
|
+
const insideProject = normalizedProjectPathLower !== undefined && lower.startsWith(normalizedProjectPathLower);
|
|
550
|
+
// Positive version evidence is REQUIRED; the three forms are ranked so a
|
|
551
|
+
// verbatim Minecraft version always beats an inferred one.
|
|
552
|
+
const versionEvidence = hasExactVersionToken(normalizedPath, input.version)
|
|
553
|
+
? "exact-token"
|
|
554
|
+
: hasLoaderRuntimeVersionToken(normalizedPath, input.version)
|
|
555
|
+
? "loader-token"
|
|
556
|
+
: projectAnchorAllowed && insideProject
|
|
557
|
+
? "project-anchored"
|
|
558
|
+
: undefined;
|
|
559
|
+
if (!versionEvidence) {
|
|
453
560
|
continue;
|
|
454
561
|
}
|
|
455
562
|
const looksMerged = lower.includes("merged");
|
|
@@ -457,6 +564,11 @@ export async function discoverAccessTransformerRuntimeCandidates(_svc, input) {
|
|
|
457
564
|
const looksForge = lower.includes("forge");
|
|
458
565
|
const looksNeoForge = lower.includes("neoforge") || lower.includes("moddev") || lower.includes("neoform");
|
|
459
566
|
const looksPatchedRuntime = lower.includes("patched") || lower.includes("client-extra") || lower.includes("joined");
|
|
567
|
+
// client-extra / *-minecraft-resources jars carry resources ONLY, so they
|
|
568
|
+
// can never answer a class lookup. They stay selectable (a workspace that
|
|
569
|
+
// has nothing else still gets an answer) but must lose to any real
|
|
570
|
+
// classes jar.
|
|
571
|
+
const looksResourcesOnly = lower.includes("client-extra") || lower.includes("minecraft-resources");
|
|
460
572
|
const appliedScope = looksMerged
|
|
461
573
|
? "merged"
|
|
462
574
|
: "loader";
|
|
@@ -470,18 +582,21 @@ export async function discoverAccessTransformerRuntimeCandidates(_svc, input) {
|
|
|
470
582
|
continue;
|
|
471
583
|
}
|
|
472
584
|
const score = 10_000 +
|
|
473
|
-
(
|
|
585
|
+
(versionEvidence === "exact-token" ? 5_000 : versionEvidence === "loader-token" ? 3_500 : 3_000) +
|
|
586
|
+
(insideProject ? 4_000 : 0) +
|
|
474
587
|
(looksPatchedRuntime ? 3_000 : 0) +
|
|
475
588
|
(looksSrg ? 2_500 : 0) +
|
|
476
589
|
(input.loader === "forge" && looksForge ? 1_500 : 0) +
|
|
477
590
|
(input.loader === "neoforge" && looksNeoForge ? 1_500 : 0) +
|
|
478
591
|
(input.requestedScope === appliedScope ? 1_000 : 0) +
|
|
479
|
-
(looksMerged ? -500 : 0)
|
|
592
|
+
(looksMerged ? -500 : 0) +
|
|
593
|
+
(looksResourcesOnly ? -6_000 : 0);
|
|
480
594
|
candidates.push({
|
|
481
595
|
jarPath: normalizedPath,
|
|
482
596
|
score,
|
|
483
597
|
appliedScope,
|
|
484
|
-
origin: "local-jar"
|
|
598
|
+
origin: "local-jar",
|
|
599
|
+
versionEvidence
|
|
485
600
|
});
|
|
486
601
|
}
|
|
487
602
|
}
|
|
@@ -504,6 +619,9 @@ export async function resolveAccessWidenerRuntimeArtifact(svc, input) {
|
|
|
504
619
|
const detected = await svc.workspaceMappingService.detectProjectMinecraftVersion(normalizedProjectPath);
|
|
505
620
|
version = detected ?? version;
|
|
506
621
|
}
|
|
622
|
+
const expectedLoader = normalizedProjectPath
|
|
623
|
+
? await detectWorkspaceRuntimeLoader(svc, normalizedProjectPath)
|
|
624
|
+
: undefined;
|
|
507
625
|
const requestedScope = input.scope ?? (normalizedProjectPath ? "loader" : "vanilla");
|
|
508
626
|
if (requestedScope === "vanilla") {
|
|
509
627
|
const versionJar = await svc.versionService.resolveVersionJar(version);
|
|
@@ -574,9 +692,21 @@ export async function resolveAccessWidenerRuntimeArtifact(svc, input) {
|
|
|
574
692
|
notes.push(...detection.warnings);
|
|
575
693
|
}
|
|
576
694
|
}
|
|
695
|
+
// Provenance must describe the jar that was SERVED, never the request.
|
|
696
|
+
const served = describeServedRuntimeJar({
|
|
697
|
+
jarPath: discovery.selected.jarPath,
|
|
698
|
+
requestedVersion: version,
|
|
699
|
+
expectedLoader
|
|
700
|
+
});
|
|
701
|
+
notes.push(...served.notes);
|
|
577
702
|
return {
|
|
578
|
-
version,
|
|
703
|
+
version: served.version,
|
|
579
704
|
jarPath: discovery.selected.jarPath,
|
|
705
|
+
...(served.requestedVersion ? { requestedVersion: served.requestedVersion } : {}),
|
|
706
|
+
...(served.versionApproximated ? { versionApproximated: true } : {}),
|
|
707
|
+
servedLoader: served.servedLoader,
|
|
708
|
+
...(served.expectedLoader ? { expectedLoader: served.expectedLoader } : {}),
|
|
709
|
+
...(served.loaderMismatch ? { loaderMismatch: true } : {}),
|
|
580
710
|
requestedScope,
|
|
581
711
|
appliedScope,
|
|
582
712
|
requestedMapping: input.awNamespace,
|
|
@@ -586,6 +716,28 @@ export async function resolveAccessWidenerRuntimeArtifact(svc, input) {
|
|
|
586
716
|
scopeFallback
|
|
587
717
|
};
|
|
588
718
|
}
|
|
719
|
+
/**
|
|
720
|
+
* Loader a workspace declares, normalized onto {@link RuntimeLoader}. Quilt is
|
|
721
|
+
* Fabric-compatible for runtime-jar purposes; anything undetected stays
|
|
722
|
+
* "unknown" so no mismatch is ever asserted on a guess.
|
|
723
|
+
*/
|
|
724
|
+
async function detectWorkspaceRuntimeLoader(svc, projectPath) {
|
|
725
|
+
const detection = await svc.workspaceMappingService.detectProjectLoader(projectPath);
|
|
726
|
+
if (!detection.resolved) {
|
|
727
|
+
return "unknown";
|
|
728
|
+
}
|
|
729
|
+
switch (detection.loader) {
|
|
730
|
+
case "fabric":
|
|
731
|
+
case "quilt":
|
|
732
|
+
return "fabric";
|
|
733
|
+
case "forge":
|
|
734
|
+
return "forge";
|
|
735
|
+
case "neoforge":
|
|
736
|
+
return "neoforge";
|
|
737
|
+
default:
|
|
738
|
+
return "unknown";
|
|
739
|
+
}
|
|
740
|
+
}
|
|
589
741
|
export async function resolveAccessTransformerNamespace(svc, input) {
|
|
590
742
|
const explicit = normalizeAccessTransformerNamespace(input.atNamespace);
|
|
591
743
|
if (explicit) {
|
|
@@ -622,9 +774,15 @@ export async function resolveAccessTransformerNamespace(svc, input) {
|
|
|
622
774
|
export async function resolveAccessTransformerRuntimeArtifact(svc, input) {
|
|
623
775
|
const normalizedProjectPath = normalizeOptionalProjectPath(input.projectPath);
|
|
624
776
|
let version = input.version;
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
777
|
+
// The workspace's own declared version is read whenever a project is given:
|
|
778
|
+
// preferProjectVersion decides whether it OVERRIDES the requested version,
|
|
779
|
+
// but discovery needs it either way to anchor project-local artifacts whose
|
|
780
|
+
// filenames carry only a loader version.
|
|
781
|
+
const projectMinecraftVersion = normalizedProjectPath
|
|
782
|
+
? await svc.workspaceMappingService.detectProjectMinecraftVersion(normalizedProjectPath)
|
|
783
|
+
: undefined;
|
|
784
|
+
if (input.preferProjectVersion && projectMinecraftVersion) {
|
|
785
|
+
version = projectMinecraftVersion;
|
|
628
786
|
}
|
|
629
787
|
const requestedScope = input.scope ?? (normalizedProjectPath ? "loader" : "vanilla");
|
|
630
788
|
if (requestedScope === "vanilla") {
|
|
@@ -655,7 +813,8 @@ export async function resolveAccessTransformerRuntimeArtifact(svc, input) {
|
|
|
655
813
|
gradleUserHome: input.gradleUserHome,
|
|
656
814
|
requestedScope,
|
|
657
815
|
atNamespace: input.atNamespace,
|
|
658
|
-
loader
|
|
816
|
+
loader,
|
|
817
|
+
projectMinecraftVersion
|
|
659
818
|
});
|
|
660
819
|
if (!discovery.selected) {
|
|
661
820
|
throw createError({
|
|
@@ -670,7 +829,13 @@ export async function resolveAccessTransformerRuntimeArtifact(svc, input) {
|
|
|
670
829
|
candidateArtifacts: discovery.candidateArtifacts,
|
|
671
830
|
loaderEvidence: loaderDetection.evidence,
|
|
672
831
|
loaderWarnings: loaderDetection.warnings,
|
|
673
|
-
|
|
832
|
+
...(projectMinecraftVersion ? { projectMinecraftVersion } : {}),
|
|
833
|
+
// An error must never ask for something the caller already sent.
|
|
834
|
+
nextAction: normalizedProjectPath
|
|
835
|
+
? `Searched the workspace "${normalizedProjectPath}" and the Gradle caches but found no runtime jar for Minecraft ${version}${projectMinecraftVersion && projectMinecraftVersion !== version
|
|
836
|
+
? ` (the workspace declares ${projectMinecraftVersion}; retry with version="${projectMinecraftVersion}" or preferProjectVersion=true)`
|
|
837
|
+
: ""}. Run the Gradle task that populates transformed runtime artifacts (NeoForge/ModDevGradle writes them under build/moddev/artifacts), then retry.`
|
|
838
|
+
: "Provide projectPath for a Forge/NeoForge workspace with generated runtime jars, or run the Gradle tasks that populate transformed runtime artifacts before retrying."
|
|
674
839
|
}
|
|
675
840
|
});
|
|
676
841
|
}
|
|
@@ -690,15 +855,38 @@ export async function resolveAccessTransformerRuntimeArtifact(svc, input) {
|
|
|
690
855
|
: "Resolved the closest transformed runtime artifact for validation."
|
|
691
856
|
}
|
|
692
857
|
: undefined;
|
|
858
|
+
const resolutionNotes = [
|
|
859
|
+
...(scopeFallback ? [scopeFallback.reason] : []),
|
|
860
|
+
...(selected.versionEvidence && selected.versionEvidence !== "exact-token"
|
|
861
|
+
? [
|
|
862
|
+
selected.versionEvidence === "loader-token"
|
|
863
|
+
? `Runtime jar matched Minecraft ${version} through its loader version token (ModDevGradle names artifacts after the loader, not Minecraft).`
|
|
864
|
+
: `Runtime jar matched Minecraft ${version} because it lives in the workspace build directory of a project declaring that version.`
|
|
865
|
+
]
|
|
866
|
+
: [])
|
|
867
|
+
];
|
|
868
|
+
const servedAt = describeServedRuntimeJar({
|
|
869
|
+
jarPath: selected.jarPath,
|
|
870
|
+
requestedVersion: version,
|
|
871
|
+
// An access transformer is a Forge/NeoForge artifact; the workspace loader
|
|
872
|
+
// refines that when it is known.
|
|
873
|
+
expectedLoader: loader === "forge" ? "forge" : loader === "neoforge" ? "neoforge" : undefined
|
|
874
|
+
});
|
|
875
|
+
resolutionNotes.push(...servedAt.notes);
|
|
693
876
|
return {
|
|
694
|
-
version,
|
|
877
|
+
version: servedAt.version,
|
|
695
878
|
jarPath: selected.jarPath,
|
|
879
|
+
...(servedAt.requestedVersion ? { requestedVersion: servedAt.requestedVersion } : {}),
|
|
880
|
+
...(servedAt.versionApproximated ? { versionApproximated: true } : {}),
|
|
881
|
+
servedLoader: servedAt.servedLoader,
|
|
882
|
+
...(servedAt.expectedLoader ? { expectedLoader: servedAt.expectedLoader } : {}),
|
|
883
|
+
...(servedAt.loaderMismatch ? { loaderMismatch: true } : {}),
|
|
696
884
|
requestedScope,
|
|
697
885
|
appliedScope: selected.appliedScope,
|
|
698
886
|
requestedMapping: input.atNamespace,
|
|
699
887
|
mappingApplied,
|
|
700
888
|
origin: selected.origin,
|
|
701
|
-
resolutionNotes:
|
|
889
|
+
resolutionNotes: resolutionNotes.length > 0 ? resolutionNotes : undefined,
|
|
702
890
|
scopeFallback
|
|
703
891
|
};
|
|
704
892
|
}
|
|
@@ -748,7 +936,7 @@ export async function resolveBinaryFallbackArtifact(svc, input) {
|
|
|
748
936
|
return undefined;
|
|
749
937
|
}
|
|
750
938
|
try {
|
|
751
|
-
const fallbackResolved = await resolveSourceTargetInternal({ kind: "jar", value: binaryJarPath }, { allowDecompile: true, preferBinaryOnly: true }, svc.config);
|
|
939
|
+
const fallbackResolved = await resolveSourceTargetInternal({ kind: "jar", value: binaryJarPath }, { allowDecompile: input.allowDecompile ?? true, preferBinaryOnly: true }, svc.config);
|
|
752
940
|
fallbackResolved.version = fallbackResolved.version ?? input.version;
|
|
753
941
|
fallbackResolved.coordinate = fallbackResolved.coordinate ?? input.coordinate;
|
|
754
942
|
fallbackResolved.requestedMapping = input.requestedMapping;
|
|
@@ -844,8 +1032,19 @@ async function computeBinaryRemapGate(svc, input) {
|
|
|
844
1032
|
warnings: baseline.warnings
|
|
845
1033
|
};
|
|
846
1034
|
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Describe what an artifact's indexed contents are.
|
|
1037
|
+
*
|
|
1038
|
+
* `sourceKind` is a derivation question — was the text produced by decompiling
|
|
1039
|
+
* bytecode? — and only the persisted `isDecompiled` flag answers it. `origin`
|
|
1040
|
+
* records provenance (where the bytes came from) and is deliberately not read:
|
|
1041
|
+
* the two axes disagree in practice, most visibly for a Jar-in-Jar shell, whose
|
|
1042
|
+
* row keeps origin "decompiled" while ingest clears the derivation flag. It
|
|
1043
|
+
* stays in the input shape only because every caller already carries it
|
|
1044
|
+
* alongside the fields that are read.
|
|
1045
|
+
*/
|
|
847
1046
|
export function buildArtifactContentsSummary(_svc, input) {
|
|
848
|
-
const sourceKind = input.isDecompiled ||
|
|
1047
|
+
const sourceKind = input.isDecompiled || !normalizeOptionalString(input.sourceJarPath)
|
|
849
1048
|
? "decompiled-binary"
|
|
850
1049
|
: "source-jar";
|
|
851
1050
|
const sourceCoverage = hasPartialNetMinecraftCoverage(input.qualityFlags) ? "partial" : "full";
|
|
@@ -1233,7 +1432,20 @@ export async function resolveArtifact(svc, input) {
|
|
|
1233
1432
|
});
|
|
1234
1433
|
}
|
|
1235
1434
|
resolved.qualityFlags.push("version-approximated");
|
|
1236
|
-
|
|
1435
|
+
// Provenance must name the version that was SERVED. Echoing the request
|
|
1436
|
+
// here made a fallback indistinguishable from an exact hit, and left
|
|
1437
|
+
// downstream version context pointing at a version the jar is not.
|
|
1438
|
+
const servedVersion = inferRuntimeJarMinecraftVersion(versionSourceDiscovery.selectedSourceJarPath);
|
|
1439
|
+
provenance.versionApproximation = {
|
|
1440
|
+
requestedVersion: value,
|
|
1441
|
+
...(servedVersion ? { servedVersion } : {}),
|
|
1442
|
+
sourceJarPath: versionSourceDiscovery.selectedSourceJarPath
|
|
1443
|
+
};
|
|
1444
|
+
if (servedVersion) {
|
|
1445
|
+
provenance.resolvedFrom.version = servedVersion;
|
|
1446
|
+
}
|
|
1447
|
+
warnings.push(`Requested version "${value}" but resolved source jar does not contain exact version string: ${versionSourceDiscovery.selectedSourceJarPath}` +
|
|
1448
|
+
(servedVersion ? ` (serving Minecraft ${servedVersion})` : ""));
|
|
1237
1449
|
}
|
|
1238
1450
|
}
|
|
1239
1451
|
resolved.qualityFlags = dedupeQualityFlags(resolved.qualityFlags);
|
|
@@ -40,10 +40,46 @@ export declare function buildFallbackProvenance(svc: SourceService, input: {
|
|
|
40
40
|
export declare function buildClassSourceNotFoundError(svc: SourceService, input: {
|
|
41
41
|
className: string;
|
|
42
42
|
lookupClassName: string;
|
|
43
|
+
/**
|
|
44
|
+
* Artifact the lookup ended on. TWO internal paths move it off the requested
|
|
45
|
+
* artifact: the binary fallback, and the nested-jar redirect that follows a
|
|
46
|
+
* shell jar's bundled inner jar.
|
|
47
|
+
*/
|
|
43
48
|
artifactId: string;
|
|
49
|
+
/**
|
|
50
|
+
* Artifact the caller actually asked about. Both internal redirects swap the
|
|
51
|
+
* active artifact mid-lookup, but the error must keep answering about the
|
|
52
|
+
* requested one: reporting the redirect target sends the caller to an artifact
|
|
53
|
+
* they never named. Defaults to `artifactId` for paths with no redirect.
|
|
54
|
+
*/
|
|
55
|
+
requestedArtifactId?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Mapping and quality flags OF THE REQUESTED ARTIFACT. `details.artifactId`
|
|
58
|
+
* names the requested artifact, so `details.mapping` (which reaches
|
|
59
|
+
* `error.context` through the allowlist) and `details.qualityFlags` have to
|
|
60
|
+
* describe that same artifact. The nested-jar redirect REPLACES the active
|
|
61
|
+
* values with the inner jar's, which would otherwise publish one artifact's
|
|
62
|
+
* identity beside another's namespace and quality — and point the
|
|
63
|
+
* `suggestedCall` at an index holding neither the class nor its siblings.
|
|
64
|
+
*/
|
|
44
65
|
mappingApplied: SourceMapping;
|
|
45
66
|
requestedMapping: SourceMapping;
|
|
46
67
|
qualityFlags: string[];
|
|
68
|
+
/**
|
|
69
|
+
* The mapping the CALLER wrote in the request, undefined when they omitted it.
|
|
70
|
+
* Distinct from `requestedMapping`, which falls back to the artifact's own
|
|
71
|
+
* namespace: only the caller-supplied value can tell whether the obfuscated
|
|
72
|
+
* namespace hint would be re-asking for an argument that is already present.
|
|
73
|
+
*/
|
|
74
|
+
callerSuppliedMapping?: SourceMapping;
|
|
75
|
+
/**
|
|
76
|
+
* Whether the REQUESTED artifact is a native dependency, i.e. its provenance
|
|
77
|
+
* carries `dependencyResolution`. Such artifacts are handed
|
|
78
|
+
* `mappingApplied: "obfuscated"` by substitution rather than by being an
|
|
79
|
+
* obfuscated index, which the obfuscated namespace hint must not mistake for
|
|
80
|
+
* a missing mapping argument.
|
|
81
|
+
*/
|
|
82
|
+
nativeDependency?: boolean;
|
|
47
83
|
attemptedBinaryFallback: boolean;
|
|
48
84
|
filePath?: string;
|
|
49
85
|
targetKind?: string;
|