@adhisang/minecraft-modding-mcp 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +3 -2
- package/dist/entry-tools/analyze-mod-service.d.ts +2 -2
- package/dist/entry-tools/analyze-symbol-service.d.ts +2 -2
- package/dist/entry-tools/batch-class-members-service.d.ts +3 -2
- package/dist/entry-tools/batch-class-members-service.js +20 -6
- package/dist/entry-tools/batch-class-source-service.d.ts +3 -2
- package/dist/entry-tools/batch-class-source-service.js +10 -0
- package/dist/entry-tools/compare-minecraft-service.d.ts +27 -4
- package/dist/entry-tools/compare-minecraft-service.js +65 -4
- package/dist/entry-tools/entry-tool-schema.d.ts +2 -2
- package/dist/entry-tools/inspect-minecraft-service.d.ts +2 -2
- package/dist/entry-tools/manage-cache-service.d.ts +2 -2
- package/dist/entry-tools/validate-project/cases/project-summary.js +71 -12
- package/dist/entry-tools/validate-project-service.d.ts +2 -2
- package/dist/index.js +37 -15
- package/dist/source/artifact-resolver.d.ts +14 -0
- package/dist/source/artifact-resolver.js +106 -12
- package/dist/source/class-source/members-builder.d.ts +7 -0
- package/dist/source/class-source/members-builder.js +4 -1
- package/dist/source/class-source.d.ts +9 -2
- package/dist/source/class-source.js +173 -25
- package/dist/source/indexer.js +69 -1
- package/dist/source/lifecycle/mapping-helpers.d.ts +20 -1
- package/dist/source/lifecycle/mapping-helpers.js +29 -3
- package/dist/source/lifecycle/runtime-check.d.ts +25 -0
- package/dist/source/lifecycle/runtime-check.js +68 -39
- package/dist/source/symbol-resolver.js +88 -0
- package/dist/source-jar-reader.d.ts +33 -0
- package/dist/source-jar-reader.js +58 -0
- package/dist/source-resolver.d.ts +7 -0
- package/dist/source-resolver.js +20 -5
- package/dist/source-service.d.ts +5 -0
- package/dist/source-service.js +7 -0
- package/dist/storage/db.d.ts +62 -2
- package/dist/storage/db.js +181 -20
- package/dist/storage/sqlite.d.ts +31 -1
- package/dist/storage/sqlite.js +125 -16
- package/dist/tool-guidance.js +4 -1
- package/dist/tool-schemas.d.ts +64 -52
- package/dist/tool-schemas.js +9 -7
- package/dist/types.d.ts +9 -0
- package/dist/v1-parity-schemas.js +36 -2
- package/dist/version-diff-service.d.ts +23 -0
- package/dist/version-diff-service.js +101 -0
- package/dist/version-service.d.ts +14 -0
- package/dist/version-service.js +45 -3
- package/dist/workspace-mapping-service.d.ts +8 -0
- package/dist/workspace-mapping-service.js +35 -7
- package/docs/README-ja.md +2 -0
- package/docs/tool-reference.md +55 -11
- package/package.json +1 -1
package/dist/tool-schemas.js
CHANGED
|
@@ -99,11 +99,13 @@ export const resolveArtifactTargetSchema = z.discriminatedUnion("kind", [
|
|
|
99
99
|
workspaceTargetSchema,
|
|
100
100
|
dependencyTargetSchema
|
|
101
101
|
]);
|
|
102
|
-
// Extended target schema for the source-lookup tools (get-class-source / get-class-members)
|
|
103
|
-
// the
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
102
|
+
// Extended target schema for the source-lookup tools (get-class-source / get-class-members)
|
|
103
|
+
// and the batch tools that fan out over one shared artifact (batch-class-source /
|
|
104
|
+
// batch-class-members): the same kind-based shape as resolveArtifactTargetSchema, PLUS a
|
|
105
|
+
// `kind:"artifact"` variant that short-circuits resolution by reusing an already-resolved
|
|
106
|
+
// artifactId. The shared resolveArtifactTargetSchema is intentionally NOT widened —
|
|
107
|
+
// the artifact kind has no resolution meaning for resolve-artifact / verify-mixin-target,
|
|
108
|
+
// which resolve a target rather than reuse one.
|
|
107
109
|
export const sourceLookupTargetSchema = z.discriminatedUnion("kind", [
|
|
108
110
|
z.object({ kind: z.literal("version"), value: nonEmptyString }),
|
|
109
111
|
z.object({ kind: z.literal("jar"), value: nonEmptyString }),
|
|
@@ -238,7 +240,7 @@ export const batchClassSourceEntrySchema = z.object({
|
|
|
238
240
|
outputFile: optionalNonEmptyString
|
|
239
241
|
});
|
|
240
242
|
export const batchClassSourceShape = {
|
|
241
|
-
target:
|
|
243
|
+
target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
|
|
242
244
|
mapping: sourceMappingSchema.optional(),
|
|
243
245
|
sourcePriority: mappingSourcePrioritySchema.optional(),
|
|
244
246
|
allowDecompile: z.boolean().optional(),
|
|
@@ -294,7 +296,7 @@ export const batchClassMembersEntrySchema = z.object({
|
|
|
294
296
|
maxMembers: optionalPositiveInt
|
|
295
297
|
});
|
|
296
298
|
export const batchClassMembersShape = {
|
|
297
|
-
target:
|
|
299
|
+
target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
|
|
298
300
|
mapping: sourceMappingSchema.optional(),
|
|
299
301
|
sourcePriority: mappingSourcePrioritySchema.optional(),
|
|
300
302
|
allowDecompile: z.boolean().optional(),
|
package/dist/types.d.ts
CHANGED
|
@@ -75,6 +75,15 @@ export interface ArtifactProvenance {
|
|
|
75
75
|
repoUrl?: string;
|
|
76
76
|
};
|
|
77
77
|
transformChain: string[];
|
|
78
|
+
/**
|
|
79
|
+
* The artifact's runtime names ship unobfuscated (Minecraft 26.1+): set for a
|
|
80
|
+
* 26.1+ version target, a 26.1+ Minecraft runtime coordinate, and a jar target
|
|
81
|
+
* proven to be a 26.1+ runtime jar; absent otherwise. `mappingApplied` keeps the
|
|
82
|
+
* label the caller asked for, so on such an artifact "obfuscated" names the
|
|
83
|
+
* as-shipped names, which are already Mojang names. Same flag name as
|
|
84
|
+
* `mappingContext.unobfuscatedRuntime`.
|
|
85
|
+
*/
|
|
86
|
+
unobfuscatedRuntime?: boolean;
|
|
78
87
|
workspaceResolution?: WorkspaceResolutionProvenance;
|
|
79
88
|
dependencyResolution?: DependencyResolutionProvenance;
|
|
80
89
|
warnings?: string[];
|
|
@@ -446,9 +446,26 @@ export const V1_PARITY_SCHEMAS = {
|
|
|
446
446
|
"name"
|
|
447
447
|
],
|
|
448
448
|
"additionalProperties": false
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"type": "object",
|
|
452
|
+
"properties": {
|
|
453
|
+
"kind": {
|
|
454
|
+
"type": "string",
|
|
455
|
+
"const": "artifact"
|
|
456
|
+
},
|
|
457
|
+
"artifactId": {
|
|
458
|
+
"$ref": "#/properties/target/anyOf/0/properties/value"
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
"required": [
|
|
462
|
+
"kind",
|
|
463
|
+
"artifactId"
|
|
464
|
+
],
|
|
465
|
+
"additionalProperties": false
|
|
449
466
|
}
|
|
450
467
|
],
|
|
451
|
-
"description": "
|
|
468
|
+
"description": "Same shape as resolve-artifact target (incl. {\"kind\":\"dependency\",...} to read a Fabric/loader dependency class like vanilla), plus {\"kind\":\"artifact\",\"artifactId\":\"...\"} to reuse a resolved artifact. Object, not string."
|
|
452
469
|
},
|
|
453
470
|
"mapping": {
|
|
454
471
|
"type": "string",
|
|
@@ -706,9 +723,26 @@ export const V1_PARITY_SCHEMAS = {
|
|
|
706
723
|
"name"
|
|
707
724
|
],
|
|
708
725
|
"additionalProperties": false
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
"type": "object",
|
|
729
|
+
"properties": {
|
|
730
|
+
"kind": {
|
|
731
|
+
"type": "string",
|
|
732
|
+
"const": "artifact"
|
|
733
|
+
},
|
|
734
|
+
"artifactId": {
|
|
735
|
+
"$ref": "#/properties/target/anyOf/0/properties/value"
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
"required": [
|
|
739
|
+
"kind",
|
|
740
|
+
"artifactId"
|
|
741
|
+
],
|
|
742
|
+
"additionalProperties": false
|
|
709
743
|
}
|
|
710
744
|
],
|
|
711
|
-
"description": "
|
|
745
|
+
"description": "Same shape as resolve-artifact target (incl. {\"kind\":\"dependency\",...} to read a Fabric/loader dependency class like vanilla), plus {\"kind\":\"artifact\",\"artifactId\":\"...\"} to reuse a resolved artifact. Object, not string."
|
|
712
746
|
},
|
|
713
747
|
"mapping": {
|
|
714
748
|
"type": "string",
|
|
@@ -52,6 +52,29 @@ export type CompareVersionsOutput = {
|
|
|
52
52
|
};
|
|
53
53
|
warnings: string[];
|
|
54
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* `added`/`removed` entries are `group:artifact:<versions>`, where
|
|
57
|
+
* `<versions>` is the sorted, comma-joined set of distinct versions seen for
|
|
58
|
+
* that key on the side it was diffed from or to (a single version renders
|
|
59
|
+
* as before, e.g. "g:a:1"; multiple platform-specific versions render as
|
|
60
|
+
* "g:a:1,2").
|
|
61
|
+
*/
|
|
62
|
+
export type LibraryDiffResult = {
|
|
63
|
+
added: string[];
|
|
64
|
+
removed: string[];
|
|
65
|
+
addedCount: number;
|
|
66
|
+
removedCount: number;
|
|
67
|
+
/** Count only (per design contract) — no list of which libraries bumped. */
|
|
68
|
+
versionChangedCount: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Pure diff of two versions' `libraries` name lists, keyed by
|
|
72
|
+
* `group:artifact` so a per-release version bump or a per-platform natives
|
|
73
|
+
* classifier never reads as churn. Used by migration-overview to surface
|
|
74
|
+
* library swaps (e.g. LWJGL GLFW replaced by SDL) that a class/registry diff
|
|
75
|
+
* cannot see.
|
|
76
|
+
*/
|
|
77
|
+
export declare function diffLibraries(fromNames: string[], toNames: string[]): LibraryDiffResult;
|
|
55
78
|
export declare class VersionDiffService {
|
|
56
79
|
private readonly config;
|
|
57
80
|
private readonly versionService;
|
|
@@ -88,6 +88,107 @@ function diffSets(from, to) {
|
|
|
88
88
|
removed.sort();
|
|
89
89
|
return { added, removed, unchanged };
|
|
90
90
|
}
|
|
91
|
+
// Matches a Maven-style library coordinate "group:artifact:version" with an
|
|
92
|
+
// optional trailing classifier ("...:natives-linux"). Group/artifact/version
|
|
93
|
+
// segments must be non-empty and colon-free; anything else is not a library
|
|
94
|
+
// name this diff can key on, so it is silently ignored rather than crashing
|
|
95
|
+
// or reading as a spurious added/removed entry. A trailing "@extension"
|
|
96
|
+
// (e.g. "...@jar") is stripped by the caller before this regex runs, so it
|
|
97
|
+
// never leaks into the captured version.
|
|
98
|
+
const LIBRARY_NAME_RE = /^([^:\s]+):([^:\s]+):([^:\s]+)(?::[^:\s]*)?$/;
|
|
99
|
+
function parseLibraryName(name) {
|
|
100
|
+
// Strip a trailing "@extension" (e.g. "g:a:1@jar", "g:a:1:natives-linux@jar")
|
|
101
|
+
// before parsing, so it never gets captured as part of the version.
|
|
102
|
+
const withoutExtension = name.trim().replace(/@[^@]*$/, "");
|
|
103
|
+
const match = LIBRARY_NAME_RE.exec(withoutExtension);
|
|
104
|
+
if (!match) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const [, group, artifact, version] = match;
|
|
108
|
+
return { key: `${group}:${artifact}`, version };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Collapses a version's raw library name list to the set of distinct
|
|
112
|
+
* versions seen per `group:artifact` key, dropping the per-platform natives
|
|
113
|
+
* classifier and any entry whose name does not parse as a library
|
|
114
|
+
* coordinate. Real Mojang manifests can list the same `group:artifact` with
|
|
115
|
+
* different versions under different platform rules, so every version seen
|
|
116
|
+
* is kept (not just the first) — collapsing to one would make the diff
|
|
117
|
+
* depend on input order.
|
|
118
|
+
*/
|
|
119
|
+
function collapseLibraryNames(names) {
|
|
120
|
+
const map = new Map();
|
|
121
|
+
for (const name of names) {
|
|
122
|
+
if (typeof name !== "string") {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const parsed = parseLibraryName(name);
|
|
126
|
+
if (!parsed) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
let versions = map.get(parsed.key);
|
|
130
|
+
if (!versions) {
|
|
131
|
+
versions = new Set();
|
|
132
|
+
map.set(parsed.key, versions);
|
|
133
|
+
}
|
|
134
|
+
versions.add(parsed.version);
|
|
135
|
+
}
|
|
136
|
+
return map;
|
|
137
|
+
}
|
|
138
|
+
/** Renders a key's version set as the sorted, comma-joined suffix used in `added`/`removed`. */
|
|
139
|
+
function renderVersions(versions) {
|
|
140
|
+
return Array.from(versions).sort().join(",");
|
|
141
|
+
}
|
|
142
|
+
function versionSetsEqual(a, b) {
|
|
143
|
+
if (a.size !== b.size) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
for (const version of a) {
|
|
147
|
+
if (!b.has(version)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Pure diff of two versions' `libraries` name lists, keyed by
|
|
155
|
+
* `group:artifact` so a per-release version bump or a per-platform natives
|
|
156
|
+
* classifier never reads as churn. Used by migration-overview to surface
|
|
157
|
+
* library swaps (e.g. LWJGL GLFW replaced by SDL) that a class/registry diff
|
|
158
|
+
* cannot see.
|
|
159
|
+
*/
|
|
160
|
+
export function diffLibraries(fromNames, toNames) {
|
|
161
|
+
const fromMap = collapseLibraryNames(fromNames ?? []);
|
|
162
|
+
const toMap = collapseLibraryNames(toNames ?? []);
|
|
163
|
+
const added = [];
|
|
164
|
+
const removed = [];
|
|
165
|
+
let versionChangedCount = 0;
|
|
166
|
+
for (const [key, versions] of toMap) {
|
|
167
|
+
if (!fromMap.has(key)) {
|
|
168
|
+
added.push(`${key}:${renderVersions(versions)}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const [key, versions] of fromMap) {
|
|
172
|
+
if (!toMap.has(key)) {
|
|
173
|
+
removed.push(`${key}:${renderVersions(versions)}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const [key, fromVersions] of fromMap) {
|
|
177
|
+
const toVersions = toMap.get(key);
|
|
178
|
+
if (toVersions !== undefined && !versionSetsEqual(fromVersions, toVersions)) {
|
|
179
|
+
versionChangedCount += 1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
added.sort();
|
|
183
|
+
removed.sort();
|
|
184
|
+
return {
|
|
185
|
+
added,
|
|
186
|
+
removed,
|
|
187
|
+
addedCount: added.length,
|
|
188
|
+
removedCount: removed.length,
|
|
189
|
+
versionChangedCount
|
|
190
|
+
};
|
|
191
|
+
}
|
|
91
192
|
function diffRegistries(fromRegistries, toRegistries) {
|
|
92
193
|
const fromKeys = new Set(Object.keys(fromRegistries));
|
|
93
194
|
const toKeys = new Set(Object.keys(toRegistries));
|
|
@@ -54,6 +54,14 @@ export declare class VersionService {
|
|
|
54
54
|
listVersionIds(input?: ListVersionIdsInput): Promise<string[]>;
|
|
55
55
|
resolveVersionJar(version: string): Promise<ResolvedVersionJar>;
|
|
56
56
|
resolveVersionMappings(version: string): Promise<ResolvedVersionMappings>;
|
|
57
|
+
/**
|
|
58
|
+
* Raw `libraries[].name` coordinates (e.g. "org.lwjgl:lwjgl-glfw:3.4.1")
|
|
59
|
+
* for one version's per-version JSON, in manifest order. Entries missing a
|
|
60
|
+
* non-empty string `name` are dropped here at the JSON boundary; further
|
|
61
|
+
* validation (does the name actually parse as a library coordinate) is the
|
|
62
|
+
* caller's job — see diffLibraries in version-diff-service.ts.
|
|
63
|
+
*/
|
|
64
|
+
getVersionLibraries(version: string): Promise<string[]>;
|
|
57
65
|
resolveServerJar(version: string): Promise<ResolvedServerJar>;
|
|
58
66
|
private fetchManifest;
|
|
59
67
|
private resolveVersionJarInternal;
|
|
@@ -69,5 +77,11 @@ export declare class VersionService {
|
|
|
69
77
|
* MC 26.1+ uses new YY.N version format and ships unobfuscated source.
|
|
70
78
|
* Legacy 1.x.y versions remain obfuscated.
|
|
71
79
|
* Snapshots: "26w01a" (year >= 26) → unobfuscated, "24w01a" → obfuscated.
|
|
80
|
+
*
|
|
81
|
+
* Pre-release / rc / snapshot suffixes: Mojang's real version-manifest ids
|
|
82
|
+
* use a hyphenated "-pre-N" / "-rc-N" / "-snapshot-N" form (e.g.
|
|
83
|
+
* "26.2-pre-6", "26.2-rc-2", "26.3-snapshot-6"). The older no-hyphen
|
|
84
|
+
* "-preN"/"-rcN" form is also accepted for backwards compatibility, but an
|
|
85
|
+
* arbitrary or numberless suffix (e.g. "26.1-foo", "26.1-snapshot") is not.
|
|
72
86
|
*/
|
|
73
87
|
export declare function isUnobfuscatedVersion(version: string): boolean;
|
package/dist/version-service.js
CHANGED
|
@@ -136,6 +136,39 @@ export class VersionService {
|
|
|
136
136
|
mappingsUrl: clientMappingsUrl
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Raw `libraries[].name` coordinates (e.g. "org.lwjgl:lwjgl-glfw:3.4.1")
|
|
141
|
+
* for one version's per-version JSON, in manifest order. Entries missing a
|
|
142
|
+
* non-empty string `name` are dropped here at the JSON boundary; further
|
|
143
|
+
* validation (does the name actually parse as a library coordinate) is the
|
|
144
|
+
* caller's job — see diffLibraries in version-diff-service.ts.
|
|
145
|
+
*/
|
|
146
|
+
async getVersionLibraries(version) {
|
|
147
|
+
const normalizedVersion = version.trim();
|
|
148
|
+
if (!normalizedVersion) {
|
|
149
|
+
throw createError({
|
|
150
|
+
code: ERROR_CODES.INVALID_INPUT,
|
|
151
|
+
message: "version must be non-empty."
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const manifest = await this.fetchManifest();
|
|
155
|
+
const versionEntry = (manifest.versions ?? []).find((entry) => entry.id === normalizedVersion);
|
|
156
|
+
if (!versionEntry) {
|
|
157
|
+
throw createError({
|
|
158
|
+
code: ERROR_CODES.VERSION_NOT_FOUND,
|
|
159
|
+
message: `Minecraft version "${normalizedVersion}" was not found in version manifest.`,
|
|
160
|
+
details: {
|
|
161
|
+
version: normalizedVersion,
|
|
162
|
+
nextAction: "Use list-versions to see available Minecraft versions.",
|
|
163
|
+
...buildSuggestedCall({ tool: "list-versions", params: {} })
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const details = await this.fetchVersionDetails(versionEntry.url, normalizedVersion);
|
|
168
|
+
return (details.libraries ?? [])
|
|
169
|
+
.map((lib) => lib?.name)
|
|
170
|
+
.filter((name) => typeof name === "string" && name.length > 0);
|
|
171
|
+
}
|
|
139
172
|
async resolveServerJar(version) {
|
|
140
173
|
const normalizedVersion = version.trim();
|
|
141
174
|
if (!normalizedVersion) {
|
|
@@ -473,6 +506,12 @@ export class VersionService {
|
|
|
473
506
|
* MC 26.1+ uses new YY.N version format and ships unobfuscated source.
|
|
474
507
|
* Legacy 1.x.y versions remain obfuscated.
|
|
475
508
|
* Snapshots: "26w01a" (year >= 26) → unobfuscated, "24w01a" → obfuscated.
|
|
509
|
+
*
|
|
510
|
+
* Pre-release / rc / snapshot suffixes: Mojang's real version-manifest ids
|
|
511
|
+
* use a hyphenated "-pre-N" / "-rc-N" / "-snapshot-N" form (e.g.
|
|
512
|
+
* "26.2-pre-6", "26.2-rc-2", "26.3-snapshot-6"). The older no-hyphen
|
|
513
|
+
* "-preN"/"-rcN" form is also accepted for backwards compatibility, but an
|
|
514
|
+
* arbitrary or numberless suffix (e.g. "26.1-foo", "26.1-snapshot") is not.
|
|
476
515
|
*/
|
|
477
516
|
export function isUnobfuscatedVersion(version) {
|
|
478
517
|
if (!version)
|
|
@@ -482,9 +521,12 @@ export function isUnobfuscatedVersion(version) {
|
|
|
482
521
|
if (snapshotMatch) {
|
|
483
522
|
return Number(snapshotMatch[1]) >= 26;
|
|
484
523
|
}
|
|
485
|
-
// New format: YY.N or YY.N.P, optionally with -
|
|
486
|
-
//
|
|
487
|
-
|
|
524
|
+
// New format: YY.N or YY.N.P, optionally with a pre-release/rc/snapshot
|
|
525
|
+
// suffix in either the legacy no-hyphen form (-preN, -rcN) or Mojang's
|
|
526
|
+
// real hyphenated form (-pre-N, -rc-N, -snapshot-N).
|
|
527
|
+
// Examples: "26.1", "27.3.1", "26.1-pre1", "26.1-rc1", "26.2-pre-6",
|
|
528
|
+
// "26.2-rc-2", "26.3-snapshot-6"
|
|
529
|
+
const newFormatMatch = version.match(/^(\d{2,})\.\d+(?:\.\d+)?(?:-(?:pre|rc)\d+|-(?:pre|rc|snapshot)-\d+)?$/);
|
|
488
530
|
if (newFormatMatch) {
|
|
489
531
|
return Number(newFormatMatch[1]) >= 26;
|
|
490
532
|
}
|
|
@@ -50,6 +50,14 @@ export type DependencyVersionOptions = {
|
|
|
50
50
|
export { isSafeMavenVersionToken };
|
|
51
51
|
export declare class WorkspaceMappingService {
|
|
52
52
|
detectCompileMapping(input: WorkspaceCompileMappingInput): Promise<WorkspaceCompileMappingOutput>;
|
|
53
|
+
/**
|
|
54
|
+
* Whether `projectPath` holds at least one build.gradle(.kts) that
|
|
55
|
+
* `detectCompileMapping` reads: the same files, found the same way, and readable.
|
|
56
|
+
* `detectCompileMapping` answers "no evidence" both when a build declares no
|
|
57
|
+
* mappings and when there was no build to read (a missing, mistyped or empty
|
|
58
|
+
* directory); this tells the two apart without changing that output.
|
|
59
|
+
*/
|
|
60
|
+
hasReadableBuildScript(projectPath: string): Promise<boolean>;
|
|
53
61
|
detectProjectMinecraftVersion(projectPath: string): Promise<string | undefined>;
|
|
54
62
|
detectDependencyVersion(projectPath: string, group: string, name: string, opts?: DependencyVersionOptions): Promise<DependencyVersionResolution>;
|
|
55
63
|
detectProjectLoader(projectPath: string): Promise<WorkspaceProjectLoaderOutput>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access, readdir, readFile } from "node:fs/promises";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { resolve } from "node:path";
|
|
4
5
|
import fastGlob from "fast-glob";
|
|
@@ -271,6 +272,15 @@ function detectLoadersFromContent(content) {
|
|
|
271
272
|
}
|
|
272
273
|
return detections;
|
|
273
274
|
}
|
|
275
|
+
/** The build.gradle(.kts) files `detectCompileMapping` scans under `root`, sorted. */
|
|
276
|
+
async function listCompileMappingBuildScripts(root) {
|
|
277
|
+
return (await fastGlob.glob(["build.gradle", "build.gradle.kts", "**/build.gradle", "**/build.gradle.kts"], {
|
|
278
|
+
cwd: root,
|
|
279
|
+
absolute: true,
|
|
280
|
+
onlyFiles: true,
|
|
281
|
+
ignore: ["**/.git/**", "**/.gradle/**", "**/build/**", "**/out/**", "**/node_modules/**"]
|
|
282
|
+
})).sort((left, right) => left.localeCompare(right));
|
|
283
|
+
}
|
|
274
284
|
export class WorkspaceMappingService {
|
|
275
285
|
async detectCompileMapping(input) {
|
|
276
286
|
const projectPath = input.projectPath?.trim();
|
|
@@ -284,12 +294,7 @@ export class WorkspaceMappingService {
|
|
|
284
294
|
});
|
|
285
295
|
}
|
|
286
296
|
const root = resolve(projectPath);
|
|
287
|
-
const files =
|
|
288
|
-
cwd: root,
|
|
289
|
-
absolute: true,
|
|
290
|
-
onlyFiles: true,
|
|
291
|
-
ignore: ["**/.git/**", "**/.gradle/**", "**/build/**", "**/out/**", "**/node_modules/**"]
|
|
292
|
-
})).sort((left, right) => left.localeCompare(right));
|
|
297
|
+
const files = await listCompileMappingBuildScripts(root);
|
|
293
298
|
const evidence = (await mapWithConcurrencyLimit(files, WORKSPACE_FILE_READ_CONCURRENCY, async (filePath) => {
|
|
294
299
|
let content;
|
|
295
300
|
try {
|
|
@@ -328,6 +333,29 @@ export class WorkspaceMappingService {
|
|
|
328
333
|
warnings: []
|
|
329
334
|
};
|
|
330
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Whether `projectPath` holds at least one build.gradle(.kts) that
|
|
338
|
+
* `detectCompileMapping` reads: the same files, found the same way, and readable.
|
|
339
|
+
* `detectCompileMapping` answers "no evidence" both when a build declares no
|
|
340
|
+
* mappings and when there was no build to read (a missing, mistyped or empty
|
|
341
|
+
* directory); this tells the two apart without changing that output.
|
|
342
|
+
*/
|
|
343
|
+
async hasReadableBuildScript(projectPath) {
|
|
344
|
+
const trimmed = projectPath.trim();
|
|
345
|
+
if (!trimmed) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
for (const filePath of await listCompileMappingBuildScripts(resolve(trimmed))) {
|
|
349
|
+
try {
|
|
350
|
+
await access(filePath, constants.R_OK);
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// detectCompileMapping skips an unreadable script too.
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
331
359
|
async detectProjectMinecraftVersion(projectPath) {
|
|
332
360
|
const root = resolve(projectPath);
|
|
333
361
|
const propsPath = resolve(root, "gradle.properties");
|
package/docs/README-ja.md
CHANGED
|
@@ -161,6 +161,8 @@ stdio トランスポートは、改行区切り形式と `Content-Length` フ
|
|
|
161
161
|
- ワークスペースのソースカバレッジが部分的な場合でも、バニラクラスを確認できます。`inspect-minecraft task="list-files"` は、その場合に部分的な結果とフォローアップガイダンスを返します。
|
|
162
162
|
- `analyze-mod` と `validate-project` は、オブジェクト形式の `subject` と正規の `include` グループを要求します。古い文字列形式の `subject` やドメイン名形式の `include` には `ERR_INVALID_INPUT` と、再試行しやすい `suggestedCall` を返します。
|
|
163
163
|
- `validate-mixin` と `validate-project` は、`obfuscated` / `mojang` 検証では `mapping-health` を軽量に保ちます。`intermediary` / `yarn` 名前空間を要求しない限り、完全な Tiny マッピンググラフは読み込みません。
|
|
164
|
+
- `validate-project task="project-summary"` は `version` を省略すると `gradle.properties` から Minecraft バージョンを推定し、推定したバージョンを `warnings` に示します。推定を止めるには `preferProjectVersion: false` を指定します。その場合、`version` のない呼び出しは `status: "blocked"` を返します。解決したバージョン(明示指定または推定)は、検出したすべての Mixin / Access Widener / Access Transformer の検証に渡されます。ファイルを検出したのにバージョンを推定できない場合は、推測せずに、明示的な `version` を求める再試行案付きで `status: "blocked"` を返します。
|
|
165
|
+
- `validate-project task="project-summary"` が検証対象のファイルを 1 つも検出しなかった場合、`status` は `"ok"` のままですが、headline が `Nothing to validate: ...` となり、`warnings` にも何も検証していないことが示されます。`"ok"` だけでは、いずれかのファイルが検証に通ったことを意味しません。
|
|
164
166
|
- `validate-project task="project-summary"` の `tasks["minecraft.artifact.resolved"]` は軽量なアーティファクト probe です。probe 状態を返すためだけに Minecraft のデコンパイルやソースインデックス再構築は行いません。追加の `tasks` フィールドを省きたい場合は `VALIDATE_PROJECT_TASKS_OFF=1` を使います。
|
|
165
167
|
|
|
166
168
|
### あるバージョンの Minecraft ソースを確認する
|