@adhisang/minecraft-modding-mcp 3.1.1 → 4.0.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 +49 -0
- package/README.md +37 -18
- package/dist/access-transformer-parser.d.ts +17 -0
- package/dist/access-transformer-parser.js +97 -0
- package/dist/cache-registry.d.ts +1 -1
- package/dist/cache-registry.js +10 -2
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +24 -0
- package/dist/config.d.ts +10 -1
- package/dist/config.js +52 -1
- package/dist/decompiler/vineflower.js +22 -21
- package/dist/entry-tools/analyze-mod-service.d.ts +4 -4
- package/dist/entry-tools/analyze-symbol-service.d.ts +22 -22
- package/dist/entry-tools/analyze-symbol-service.js +13 -2
- package/dist/entry-tools/inspect-minecraft-service.d.ts +168 -168
- package/dist/entry-tools/inspect-minecraft-service.js +8 -2
- package/dist/entry-tools/manage-cache-service.d.ts +4 -4
- package/dist/entry-tools/validate-project-service.d.ts +153 -16
- package/dist/entry-tools/validate-project-service.js +442 -25
- package/dist/gradle-paths.d.ts +4 -0
- package/dist/gradle-paths.js +57 -0
- package/dist/index.js +148 -30
- package/dist/lru-list.d.ts +31 -0
- package/dist/lru-list.js +102 -0
- package/dist/mapping-pipeline-service.d.ts +12 -1
- package/dist/mapping-pipeline-service.js +28 -1
- package/dist/mapping-service.d.ts +16 -0
- package/dist/mapping-service.js +405 -68
- package/dist/minecraft-explorer-service.d.ts +13 -0
- package/dist/minecraft-explorer-service.js +8 -4
- package/dist/mixin-validator.d.ts +33 -2
- package/dist/mixin-validator.js +218 -17
- package/dist/mod-analyzer.d.ts +1 -0
- package/dist/mod-analyzer.js +17 -1
- package/dist/mod-decompile-service.js +4 -4
- package/dist/mod-remap-service.js +1 -54
- package/dist/mod-search-service.d.ts +1 -0
- package/dist/mod-search-service.js +84 -51
- package/dist/observability.d.ts +18 -1
- package/dist/observability.js +44 -1
- package/dist/response-utils.d.ts +69 -0
- package/dist/response-utils.js +227 -0
- package/dist/source-jar-reader.d.ts +16 -0
- package/dist/source-jar-reader.js +103 -1
- package/dist/source-resolver.d.ts +9 -1
- package/dist/source-resolver.js +23 -16
- package/dist/source-service.d.ts +119 -3
- package/dist/source-service.js +1836 -218
- package/dist/storage/artifacts-repo.d.ts +4 -1
- package/dist/storage/artifacts-repo.js +33 -5
- package/dist/storage/files-repo.d.ts +0 -2
- package/dist/storage/files-repo.js +0 -11
- package/dist/storage/migrations.d.ts +1 -1
- package/dist/storage/migrations.js +10 -2
- package/dist/storage/schema.d.ts +2 -0
- package/dist/storage/schema.js +25 -0
- package/dist/tool-contract-manifest.js +8 -6
- package/dist/types.d.ts +20 -0
- package/dist/workspace-mapping-service.d.ts +13 -0
- package/dist/workspace-mapping-service.js +146 -14
- package/package.json +3 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { dirname, isAbsolute, resolve as resolvePath } from "node:path";
|
|
3
|
+
import { normalizePathForHost } from "./path-converter.js";
|
|
4
|
+
export function normalizeOptionalProjectPath(projectPath) {
|
|
5
|
+
if (!projectPath) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const trimmed = projectPath.trim();
|
|
9
|
+
if (!trimmed) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const normalized = normalizePathForHost(trimmed, undefined, "projectPath");
|
|
13
|
+
return isAbsolute(normalized) ? normalized : resolvePath(process.cwd(), normalized);
|
|
14
|
+
}
|
|
15
|
+
export function resolveGradleUserHomePath() {
|
|
16
|
+
const configured = process.env.GRADLE_USER_HOME?.trim();
|
|
17
|
+
if (!configured) {
|
|
18
|
+
return resolvePath(homedir(), ".gradle");
|
|
19
|
+
}
|
|
20
|
+
const normalized = normalizePathForHost(configured, undefined, "GRADLE_USER_HOME");
|
|
21
|
+
return isAbsolute(normalized) ? normalized : resolvePath(process.cwd(), normalized);
|
|
22
|
+
}
|
|
23
|
+
export function buildVersionSourceSearchRoots(projectPath) {
|
|
24
|
+
const roots = new Set();
|
|
25
|
+
if (projectPath) {
|
|
26
|
+
roots.add(resolvePath(projectPath, ".gradle", "loom-cache"));
|
|
27
|
+
roots.add(resolvePath(projectPath, ".gradle-user", "caches", "fabric-loom"));
|
|
28
|
+
roots.add(resolvePath(projectPath, ".gradle", "caches", "fabric-loom"));
|
|
29
|
+
const projectParent = dirname(projectPath);
|
|
30
|
+
roots.add(resolvePath(projectParent, ".gradle-user-home", "loom-cache"));
|
|
31
|
+
roots.add(resolvePath(projectParent, ".gradle-user-home", "caches", "fabric-loom"));
|
|
32
|
+
}
|
|
33
|
+
const homeGradle = resolveGradleUserHomePath();
|
|
34
|
+
roots.add(resolvePath(homeGradle, "loom-cache"));
|
|
35
|
+
roots.add(resolvePath(homeGradle, "caches", "fabric-loom"));
|
|
36
|
+
return [...roots];
|
|
37
|
+
}
|
|
38
|
+
export function buildLoaderRuntimeSearchRoots(projectPath) {
|
|
39
|
+
const roots = new Set();
|
|
40
|
+
if (projectPath) {
|
|
41
|
+
roots.add(resolvePath(projectPath, "build"));
|
|
42
|
+
roots.add(resolvePath(projectPath, ".gradle"));
|
|
43
|
+
roots.add(resolvePath(projectPath, ".gradle", "forge-userdev"));
|
|
44
|
+
roots.add(resolvePath(projectPath, ".gradle", "neogradle"));
|
|
45
|
+
roots.add(resolvePath(projectPath, ".gradle", "caches", "forge_gradle"));
|
|
46
|
+
roots.add(resolvePath(projectPath, ".gradle", "caches", "neogradle"));
|
|
47
|
+
roots.add(resolvePath(projectPath, ".gradle", "caches", "neoformruntime"));
|
|
48
|
+
roots.add(resolvePath(projectPath, ".gradle", "caches", "moddev"));
|
|
49
|
+
}
|
|
50
|
+
const homeGradle = resolveGradleUserHomePath();
|
|
51
|
+
roots.add(resolvePath(homeGradle, "caches", "forge_gradle"));
|
|
52
|
+
roots.add(resolvePath(homeGradle, "caches", "neogradle"));
|
|
53
|
+
roots.add(resolvePath(homeGradle, "caches", "neoformruntime"));
|
|
54
|
+
roots.add(resolvePath(homeGradle, "caches", "moddev"));
|
|
55
|
+
return [...roots];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=gradle-paths.js.map
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ZodError, z } from "zod";
|
|
|
4
4
|
import { CompatStdioServerTransport } from "./compat-stdio-transport.js";
|
|
5
5
|
import { objectResult } from "./mcp-helpers.js";
|
|
6
6
|
import { prepareToolInput } from "./tool-input.js";
|
|
7
|
+
import { isCompactEnabled, COMPACT_MAPPING_TOOL_NAMES, COMPACT_SOURCE_TOOL_NAMES, COMPACT_MEMBERS_TOOL_NAMES, COMPACT_LIGHT_TOOL_NAMES, TOOL_PRESERVE_PAYLOAD_KEYS, compactResponse, compactArtifactResponse, compactMappingResponse, compactSourceResponse, compactMembersResponse, compactLightResponse } from "./response-utils.js";
|
|
7
8
|
import { loadConfig } from "./config.js";
|
|
8
9
|
import { createError, ERROR_CODES, isAppError } from "./errors.js";
|
|
9
10
|
import { log } from "./logger.js";
|
|
@@ -18,7 +19,7 @@ import { InspectMinecraftService, inspectMinecraftSchema, inspectMinecraftShape
|
|
|
18
19
|
import { AnalyzeSymbolService, analyzeSymbolSchema, analyzeSymbolShape } from "./entry-tools/analyze-symbol-service.js";
|
|
19
20
|
import { CompareMinecraftService, compareMinecraftSchema, compareMinecraftShape } from "./entry-tools/compare-minecraft-service.js";
|
|
20
21
|
import { AnalyzeModService, analyzeModSchema, analyzeModShape } from "./entry-tools/analyze-mod-service.js";
|
|
21
|
-
import { ValidateProjectService, validateProjectSchema, validateProjectShape, discoverWorkspaceAccessWideners, discoverWorkspaceMixins } from "./entry-tools/validate-project-service.js";
|
|
22
|
+
import { ValidateProjectService, validateProjectSchema, validateProjectShape, discoverWorkspaceAccessTransformers, discoverWorkspaceAccessWideners, discoverWorkspaceMixins } from "./entry-tools/validate-project-service.js";
|
|
22
23
|
import { ManageCacheService, manageCacheSchema, manageCacheShape } from "./entry-tools/manage-cache-service.js";
|
|
23
24
|
import { createCacheRegistry } from "./cache-registry.js";
|
|
24
25
|
import { buildEntryToolMeta } from "./entry-tools/response-contract.js";
|
|
@@ -59,6 +60,19 @@ const heavyToolExecutionGate = new ToolExecutionGate({ maxConcurrent: 1, maxQueu
|
|
|
59
60
|
const nonEmptyString = z.string().trim().min(1);
|
|
60
61
|
const optionalNonEmptyString = z.string().trim().min(1).optional();
|
|
61
62
|
const optionalPositiveInt = z.number().int().positive().optional();
|
|
63
|
+
// Optional descriptor: "" and whitespace-only strings are normalized to undefined so that
|
|
64
|
+
// tools with signatureMode="name-only" can accept "caller omitted descriptor" inputs whether
|
|
65
|
+
// the caller passed an empty string or omitted the field entirely. Malformed descriptors are
|
|
66
|
+
// still rejected downstream by normalizeMethodDescriptor in mapping-service.
|
|
67
|
+
const optionalDescriptorString = z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.transform((value) => {
|
|
71
|
+
if (value === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
const trimmed = value.trim();
|
|
74
|
+
return trimmed.length === 0 ? undefined : trimmed;
|
|
75
|
+
});
|
|
62
76
|
const sourceMappingSchema = z.enum(SOURCE_MAPPINGS);
|
|
63
77
|
const mappingSourcePrioritySchema = z.enum(SOURCE_PRIORITIES);
|
|
64
78
|
const targetKindSchema = z.enum(TARGET_KINDS);
|
|
@@ -89,7 +103,7 @@ const sourceLookupTargetSchema = z.discriminatedUnion("type", [
|
|
|
89
103
|
]);
|
|
90
104
|
const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = "Object with kind and value. Example: {\"kind\":\"version\",\"value\":\"1.21.10\"}. Must be an object, not a string.";
|
|
91
105
|
const SOURCE_LOOKUP_TARGET_DESCRIPTION = "Object: {\"type\":\"resolve\",\"kind\":\"version\",\"value\":\"1.21.10\"} or {\"type\":\"artifact\",\"artifactId\":\"...\"}. Must be an object, not a string.";
|
|
92
|
-
const SOURCE_SCOPE_DESCRIPTION =
|
|
106
|
+
const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = source-oriented merged runtime discovery; loader = loader/runtime artifact discovery when the workspace exposes transformed runtime jars.";
|
|
93
107
|
const SUGGESTED_CALL_DEFAULTS = {
|
|
94
108
|
allowDecompile: true,
|
|
95
109
|
preferProjectVersion: false,
|
|
@@ -129,7 +143,10 @@ const resolveArtifactShape = {
|
|
|
129
143
|
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
|
|
130
144
|
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
131
145
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
|
|
132
|
-
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
|
|
146
|
+
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
|
|
147
|
+
compact: z.boolean().default(true).describe("Return minimal fields (artifactId, origin, isDecompiled, version, requestedMapping, mappingApplied, qualityFlags). "
|
|
148
|
+
+ "Omit provenance, artifactContents, sampleEntries, adjacentSourceCandidates, binaryJarPath, coordinate, repoUrl, resolvedSourceJarPath. "
|
|
149
|
+
+ "Enabled by default; set to false for full output.")
|
|
133
150
|
};
|
|
134
151
|
const resolveArtifactSchema = z.object(resolveArtifactShape);
|
|
135
152
|
const getClassSourceShape = {
|
|
@@ -147,7 +164,8 @@ const getClassSourceShape = {
|
|
|
147
164
|
endLine: optionalPositiveInt,
|
|
148
165
|
maxLines: optionalPositiveInt,
|
|
149
166
|
maxChars: optionalPositiveInt.describe("Hard character limit on sourceText; truncates if exceeded"),
|
|
150
|
-
outputFile: optionalNonEmptyString.describe("Write source to this file path and return metadata-only response")
|
|
167
|
+
outputFile: optionalNonEmptyString.describe("Write source to this file path and return metadata-only response"),
|
|
168
|
+
compact: z.boolean().default(false).describe("When true, strip debug metadata (provenance, artifactContents, qualityFlags) and empty fields from the response. Default false.")
|
|
151
169
|
};
|
|
152
170
|
const getClassSourceSchema = z
|
|
153
171
|
.object(getClassSourceShape)
|
|
@@ -176,7 +194,8 @@ const getClassMembersShape = {
|
|
|
176
194
|
projectPath: optionalNonEmptyString,
|
|
177
195
|
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
178
196
|
preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
|
|
179
|
-
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
|
|
197
|
+
strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
|
|
198
|
+
compact: z.boolean().default(false).describe("When true, strip debug metadata (provenance, artifactContents, qualityFlags, context) and empty fields from the response. Default false.")
|
|
180
199
|
};
|
|
181
200
|
const getClassMembersSchema = z.object(getClassMembersShape);
|
|
182
201
|
const searchClassSourceShape = {
|
|
@@ -189,7 +208,10 @@ const searchClassSourceShape = {
|
|
|
189
208
|
symbolKind: searchSymbolKindSchema.optional().describe("class | interface | enum | record | method | field"),
|
|
190
209
|
queryMode: z.enum(["auto", "token", "literal"]).default("auto").describe("auto: indexed search, including separator queries like foo.bar; token: indexed-only; literal: explicit substring scan only"),
|
|
191
210
|
limit: optionalPositiveInt.default(20),
|
|
192
|
-
cursor: optionalNonEmptyString
|
|
211
|
+
cursor: optionalNonEmptyString,
|
|
212
|
+
queryNamespace: sourceMappingSchema.optional().describe("Namespace of the query. When set and intent='symbol' with a fully-qualified class name, the query is translated through find-mapping before searching the artifact namespace. Ignored for text/path intents (warning surfaced)."),
|
|
213
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first. Used only when queryNamespace triggers translation."),
|
|
214
|
+
compact: z.boolean().default(false).describe("When true, strip the artifactContents summary and empty fields from the response. Default false.")
|
|
193
215
|
};
|
|
194
216
|
const searchClassSourceSchema = z.object(searchClassSourceShape).superRefine((value, ctx) => {
|
|
195
217
|
if (value.symbolKind && value.intent && value.intent !== "symbol") {
|
|
@@ -210,12 +232,13 @@ const listArtifactFilesShape = {
|
|
|
210
232
|
artifactId: nonEmptyString,
|
|
211
233
|
prefix: optionalNonEmptyString,
|
|
212
234
|
limit: optionalPositiveInt,
|
|
213
|
-
cursor: optionalNonEmptyString
|
|
235
|
+
cursor: optionalNonEmptyString,
|
|
236
|
+
compact: z.boolean().default(false).describe("When true, strip the artifactContents summary and empty fields from the response. Default false.")
|
|
214
237
|
};
|
|
215
238
|
const listArtifactFilesSchema = z.object(listArtifactFilesShape);
|
|
216
239
|
const traceSymbolLifecycleShape = {
|
|
217
240
|
symbol: nonEmptyString.describe("fully.qualified.Class.method"),
|
|
218
|
-
descriptor:
|
|
241
|
+
descriptor: optionalDescriptorString.describe('optional JVM descriptor, e.g. "(I)V". Empty strings are treated as omitted.'),
|
|
219
242
|
fromVersion: optionalNonEmptyString,
|
|
220
243
|
toVersion: optionalNonEmptyString,
|
|
221
244
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
|
|
@@ -239,10 +262,12 @@ const findMappingShape = {
|
|
|
239
262
|
kind: workspaceSymbolKindSchema.describe("class | field | method"),
|
|
240
263
|
name: nonEmptyString,
|
|
241
264
|
owner: optionalNonEmptyString,
|
|
242
|
-
descriptor:
|
|
265
|
+
descriptor: optionalDescriptorString.describe("JVM descriptor. Optional when signatureMode='name-only' (default). Empty strings are treated as omitted."),
|
|
243
266
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
244
267
|
targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
245
268
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
269
|
+
signatureMode: z.enum(["exact", "name-only"]).default("name-only")
|
|
270
|
+
.describe("exact: descriptor required for kind=method; name-only (default): match by owner+name only"),
|
|
246
271
|
disambiguation: z
|
|
247
272
|
.object({
|
|
248
273
|
ownerHint: optionalNonEmptyString,
|
|
@@ -250,7 +275,10 @@ const findMappingShape = {
|
|
|
250
275
|
})
|
|
251
276
|
.partial()
|
|
252
277
|
.optional(),
|
|
253
|
-
maxCandidates: optionalPositiveInt.default(
|
|
278
|
+
maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
|
|
279
|
+
compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
|
|
280
|
+
+ "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
|
|
281
|
+
+ "Enabled by default; set to false for full output.")
|
|
254
282
|
};
|
|
255
283
|
const findMappingSchema = z.object(findMappingShape).superRefine((value, ctx) => {
|
|
256
284
|
if (value.kind === "class") {
|
|
@@ -301,10 +329,10 @@ const findMappingSchema = z.object(findMappingShape).superRefine((value, ctx) =>
|
|
|
301
329
|
}
|
|
302
330
|
return;
|
|
303
331
|
}
|
|
304
|
-
if (!value.descriptor) {
|
|
332
|
+
if (!value.descriptor && value.signatureMode !== "name-only") {
|
|
305
333
|
ctx.addIssue({
|
|
306
334
|
code: z.ZodIssueCode.custom,
|
|
307
|
-
message: "descriptor is required when kind=method.",
|
|
335
|
+
message: "descriptor is required when kind=method (use signatureMode='name-only' to match by name only).",
|
|
308
336
|
path: ["descriptor"]
|
|
309
337
|
});
|
|
310
338
|
}
|
|
@@ -317,7 +345,10 @@ const resolveMethodMappingExactShape = {
|
|
|
317
345
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
318
346
|
targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
319
347
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
320
|
-
maxCandidates: optionalPositiveInt.default(
|
|
348
|
+
maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
|
|
349
|
+
compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
|
|
350
|
+
+ "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
|
|
351
|
+
+ "Enabled by default; set to false for full output.")
|
|
321
352
|
};
|
|
322
353
|
const resolveMethodMappingExactSchema = z
|
|
323
354
|
.object(resolveMethodMappingExactShape)
|
|
@@ -365,10 +396,13 @@ const resolveWorkspaceSymbolShape = {
|
|
|
365
396
|
kind: workspaceSymbolKindSchema.describe("class | field | method"),
|
|
366
397
|
name: nonEmptyString,
|
|
367
398
|
owner: optionalNonEmptyString,
|
|
368
|
-
descriptor:
|
|
399
|
+
descriptor: optionalDescriptorString.describe("JVM descriptor. Empty strings are treated as omitted."),
|
|
369
400
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
370
401
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
371
|
-
maxCandidates: optionalPositiveInt.default(
|
|
402
|
+
maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates for field/method lookups (default 5, max 200). Raise when you need the full candidate list."),
|
|
403
|
+
compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
|
|
404
|
+
+ "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
|
|
405
|
+
+ "Enabled by default; set to false for full output.")
|
|
372
406
|
};
|
|
373
407
|
const resolveWorkspaceSymbolSchema = z
|
|
374
408
|
.object(resolveWorkspaceSymbolShape)
|
|
@@ -434,13 +468,16 @@ const checkSymbolExistsShape = {
|
|
|
434
468
|
kind: workspaceSymbolKindSchema.describe("class | field | method"),
|
|
435
469
|
owner: optionalNonEmptyString,
|
|
436
470
|
name: nonEmptyString,
|
|
437
|
-
descriptor:
|
|
471
|
+
descriptor: optionalDescriptorString.describe("required for kind=method unless signatureMode=name-only. Empty strings are treated as omitted."),
|
|
438
472
|
sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
|
|
439
473
|
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
440
474
|
nameMode: classNameModeSchema.default("fqcn").describe("fqcn | auto"),
|
|
441
475
|
signatureMode: z.enum(["exact", "name-only"]).default("exact")
|
|
442
476
|
.describe("exact: require descriptor for methods; name-only: match by owner+name only"),
|
|
443
|
-
maxCandidates: optionalPositiveInt.default(
|
|
477
|
+
maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
|
|
478
|
+
compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
|
|
479
|
+
+ "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
|
|
480
|
+
+ "Enabled by default; set to false for full output.")
|
|
444
481
|
};
|
|
445
482
|
const checkSymbolExistsSchema = z.object(checkSymbolExistsShape).superRefine((value, ctx) => {
|
|
446
483
|
if (value.kind === "class") {
|
|
@@ -581,9 +618,24 @@ const validateAccessWidenerShape = {
|
|
|
581
618
|
content: nonEmptyString.describe("Access Widener file content"),
|
|
582
619
|
version: nonEmptyString.describe("Minecraft version"),
|
|
583
620
|
mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
|
|
584
|
-
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first")
|
|
621
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
622
|
+
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted runtime validation"),
|
|
623
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
624
|
+
preferProjectVersion: z.boolean().default(false)
|
|
625
|
+
.describe("When true, detect MC version from gradle.properties and override version")
|
|
585
626
|
};
|
|
586
627
|
const validateAccessWidenerSchema = z.object(validateAccessWidenerShape);
|
|
628
|
+
const validateAccessTransformerShape = {
|
|
629
|
+
content: nonEmptyString.describe("Access Transformer file content"),
|
|
630
|
+
version: nonEmptyString.describe("Minecraft version"),
|
|
631
|
+
atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional().describe("srg | mojang | obfuscated"),
|
|
632
|
+
sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
|
|
633
|
+
projectPath: optionalNonEmptyString.describe("Optional workspace root path for Forge/NeoForge runtime validation"),
|
|
634
|
+
scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
|
|
635
|
+
preferProjectVersion: z.boolean().default(false)
|
|
636
|
+
.describe("When true, detect MC version from gradle.properties and override version")
|
|
637
|
+
};
|
|
638
|
+
const validateAccessTransformerSchema = z.object(validateAccessTransformerShape);
|
|
587
639
|
const analyzeModJarShape = {
|
|
588
640
|
jarPath: nonEmptyString.describe("Local path to the mod JAR file"),
|
|
589
641
|
includeClasses: z.boolean().default(false).describe("Include full class listing")
|
|
@@ -715,8 +767,11 @@ const analyzeModService = new AnalyzeModService({
|
|
|
715
767
|
const validateProjectService = new ValidateProjectService({
|
|
716
768
|
validateMixin: (input) => sourceService.validateMixin(input),
|
|
717
769
|
validateAccessWidener: (input) => sourceService.validateAccessWidener(input),
|
|
770
|
+
validateAccessTransformer: (input) => sourceService.validateAccessTransformer(input),
|
|
718
771
|
discoverMixins: discoverWorkspaceMixins,
|
|
719
|
-
discoverAccessWideners: discoverWorkspaceAccessWideners
|
|
772
|
+
discoverAccessWideners: discoverWorkspaceAccessWideners,
|
|
773
|
+
discoverAccessTransformers: discoverWorkspaceAccessTransformers,
|
|
774
|
+
detectProjectMinecraftVersion: (projectPath) => workspaceMappingService.detectProjectMinecraftVersion(projectPath)
|
|
720
775
|
});
|
|
721
776
|
const manageCacheService = new ManageCacheService({
|
|
722
777
|
registry: createCacheRegistry({
|
|
@@ -857,6 +912,16 @@ function statusForErrorCode(code) {
|
|
|
857
912
|
}
|
|
858
913
|
return 500;
|
|
859
914
|
}
|
|
915
|
+
function extractFailedStageFromDetails(details) {
|
|
916
|
+
if (typeof details !== "object" || details == null) {
|
|
917
|
+
return undefined;
|
|
918
|
+
}
|
|
919
|
+
const maybeStage = details.failedStage;
|
|
920
|
+
if (typeof maybeStage === "string" && maybeStage.trim().length > 0) {
|
|
921
|
+
return maybeStage;
|
|
922
|
+
}
|
|
923
|
+
return undefined;
|
|
924
|
+
}
|
|
860
925
|
function extractFieldErrorsFromDetails(details) {
|
|
861
926
|
if (typeof details !== "object" || details == null) {
|
|
862
927
|
return undefined;
|
|
@@ -1379,7 +1444,7 @@ function buildInvalidInputGuidance(tool, normalizedInput) {
|
|
|
1379
1444
|
if (tool === "validate-project") {
|
|
1380
1445
|
return {
|
|
1381
1446
|
hints: [
|
|
1382
|
-
"validate-project.subject must be an object with subject.kind=workspace|mixin|access-widener.",
|
|
1447
|
+
"validate-project.subject must be an object with subject.kind=workspace|mixin|access-widener|access-transformer.",
|
|
1383
1448
|
"task=\"project-summary\" uses {\"subject\":{\"kind\":\"workspace\",\"projectPath\":\"/workspace\"}}.",
|
|
1384
1449
|
"Legacy include names like projectSummary/detectedConfig/validationSummary are not accepted; use include:[\"workspace\"] only when you need discovery details."
|
|
1385
1450
|
],
|
|
@@ -1418,11 +1483,18 @@ function mapErrorToProblem(caughtError, requestId, context) {
|
|
|
1418
1483
|
instance: requestId,
|
|
1419
1484
|
fieldErrors: toFieldErrorsFromZod(caughtError),
|
|
1420
1485
|
hints: guidance?.hints ?? ["Check fieldErrors and submit a valid tool argument payload."],
|
|
1421
|
-
...(guidance?.suggestedCall ? { suggestedCall: guidance.suggestedCall } : {})
|
|
1486
|
+
...(guidance?.suggestedCall ? { suggestedCall: guidance.suggestedCall } : {}),
|
|
1487
|
+
...(context?.tool === "validate-mixin" ? { failedStage: "input-validation" } : {})
|
|
1422
1488
|
};
|
|
1423
1489
|
}
|
|
1424
1490
|
if (isAppError(caughtError)) {
|
|
1425
1491
|
const suggestedCall = toSuggestedCall(caughtError.details);
|
|
1492
|
+
let failedStage = extractFailedStageFromDetails(caughtError.details);
|
|
1493
|
+
if (!failedStage
|
|
1494
|
+
&& context?.tool === "validate-mixin"
|
|
1495
|
+
&& caughtError.code === ERROR_CODES.INVALID_INPUT) {
|
|
1496
|
+
failedStage = "input-validation";
|
|
1497
|
+
}
|
|
1426
1498
|
return {
|
|
1427
1499
|
type: `https://minecraft-modding-mcp.dev/problems/${caughtError.code.toLowerCase()}`,
|
|
1428
1500
|
title: "Tool execution error",
|
|
@@ -1432,7 +1504,8 @@ function mapErrorToProblem(caughtError, requestId, context) {
|
|
|
1432
1504
|
instance: requestId,
|
|
1433
1505
|
fieldErrors: extractFieldErrorsFromDetails(caughtError.details),
|
|
1434
1506
|
hints: toHints(caughtError.details),
|
|
1435
|
-
...(suggestedCall ? { suggestedCall } : {})
|
|
1507
|
+
...(suggestedCall ? { suggestedCall } : {}),
|
|
1508
|
+
...(failedStage ? { failedStage } : {})
|
|
1436
1509
|
};
|
|
1437
1510
|
}
|
|
1438
1511
|
return {
|
|
@@ -1502,6 +1575,26 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
1502
1575
|
? heavyToolExecutionGate.run(tool, () => action(parsedInput))
|
|
1503
1576
|
: action(parsedInput));
|
|
1504
1577
|
const { result, warnings, meta: resultMeta } = splitWarnings(payload);
|
|
1578
|
+
const isCompact = isCompactEnabled(tool, parsedInput);
|
|
1579
|
+
let projectedResult = result;
|
|
1580
|
+
if (isCompact) {
|
|
1581
|
+
if (tool === "resolve-artifact") {
|
|
1582
|
+
projectedResult = compactArtifactResponse(projectedResult);
|
|
1583
|
+
}
|
|
1584
|
+
if (COMPACT_MAPPING_TOOL_NAMES.has(tool)) {
|
|
1585
|
+
projectedResult = compactMappingResponse(projectedResult);
|
|
1586
|
+
}
|
|
1587
|
+
if (COMPACT_SOURCE_TOOL_NAMES.has(tool)) {
|
|
1588
|
+
projectedResult = compactSourceResponse(projectedResult);
|
|
1589
|
+
}
|
|
1590
|
+
if (COMPACT_MEMBERS_TOOL_NAMES.has(tool)) {
|
|
1591
|
+
projectedResult = compactMembersResponse(projectedResult);
|
|
1592
|
+
}
|
|
1593
|
+
if (COMPACT_LIGHT_TOOL_NAMES.has(tool)) {
|
|
1594
|
+
projectedResult = compactLightResponse(projectedResult);
|
|
1595
|
+
}
|
|
1596
|
+
projectedResult = compactResponse(projectedResult, TOOL_PRESERVE_PAYLOAD_KEYS[tool]);
|
|
1597
|
+
}
|
|
1505
1598
|
const entryMeta = ENTRY_TOOL_NAMES.has(tool)
|
|
1506
1599
|
? buildEntryToolMeta({
|
|
1507
1600
|
detail: normalizedInput &&
|
|
@@ -1518,14 +1611,16 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
1518
1611
|
: undefined
|
|
1519
1612
|
})
|
|
1520
1613
|
: undefined;
|
|
1614
|
+
const durationMs = Date.now() - startedAt;
|
|
1615
|
+
sourceService.recordToolCall(tool, durationMs);
|
|
1521
1616
|
return objectResult({
|
|
1522
|
-
result,
|
|
1617
|
+
result: projectedResult,
|
|
1523
1618
|
meta: {
|
|
1524
1619
|
...(entryMeta ?? {}),
|
|
1525
1620
|
...resultMeta,
|
|
1526
1621
|
requestId,
|
|
1527
1622
|
tool,
|
|
1528
|
-
durationMs
|
|
1623
|
+
durationMs,
|
|
1529
1624
|
warnings
|
|
1530
1625
|
}
|
|
1531
1626
|
});
|
|
@@ -1565,12 +1660,14 @@ async function runTool(tool, rawInput, schema, action) {
|
|
|
1565
1660
|
reason: caughtError instanceof Error ? caughtError.message : String(caughtError)
|
|
1566
1661
|
});
|
|
1567
1662
|
}
|
|
1663
|
+
const errorDurationMs = Date.now() - startedAt;
|
|
1664
|
+
sourceService.recordToolCall(tool, errorDurationMs);
|
|
1568
1665
|
return objectResult({
|
|
1569
1666
|
error: problem,
|
|
1570
1667
|
meta: {
|
|
1571
1668
|
requestId,
|
|
1572
1669
|
tool,
|
|
1573
|
-
durationMs:
|
|
1670
|
+
durationMs: errorDurationMs,
|
|
1574
1671
|
warnings: []
|
|
1575
1672
|
}
|
|
1576
1673
|
}, { isError: true });
|
|
@@ -1584,7 +1681,7 @@ server.tool("inspect-minecraft", "High-level v3 entry tool for version discovery
|
|
|
1584
1681
|
server.tool("analyze-symbol", "High-level v3 entry tool for symbol existence, mapping, lifecycle, workspace analysis, and API overview.", analyzeSymbolShape, { readOnlyHint: true }, async (args) => runTool("analyze-symbol", args, analyzeSymbolSchema, async (input) => analyzeSymbolService.execute(input)));
|
|
1585
1682
|
server.tool("compare-minecraft", "High-level v3 entry tool for version comparisons, class diffs, registry diffs, and migration overviews.", compareMinecraftShape, { readOnlyHint: true }, async (args) => runTool("compare-minecraft", args, compareMinecraftSchema, async (input) => compareMinecraftService.execute(input)));
|
|
1586
1683
|
server.tool("analyze-mod", "High-level v3 entry tool for mod metadata inspection, decompile/search flows, class source, and safe remap previews/applies.", analyzeModShape, { readOnlyHint: false }, async (args) => runTool("analyze-mod", args, analyzeModSchema, async (input) => analyzeModService.execute(input)));
|
|
1587
|
-
server.tool("validate-project", "High-level v3 entry tool for project summary, direct mixin validation, and access widener validation.", validateProjectShape, { readOnlyHint: true }, async (args) => runTool("validate-project", args, validateProjectSchema, async (input) => validateProjectService.execute(input)));
|
|
1684
|
+
server.tool("validate-project", "High-level v3 entry tool for project summary, direct mixin validation, and access widener/access transformer validation.", validateProjectShape, { readOnlyHint: true }, async (args) => runTool("validate-project", args, validateProjectSchema, async (input) => validateProjectService.execute(input)));
|
|
1588
1685
|
server.tool("manage-cache", "High-level v3 entry tool for cache summaries, listing, verification, previewed mutation, and explicit apply operations.", manageCacheShape, { readOnlyHint: false }, async (args) => runTool("manage-cache", args, manageCacheSchema, async (input) => manageCacheService.execute(input)));
|
|
1589
1686
|
server.tool("resolve-artifact", "Resolve source artifact from a target object ({ kind, value }) and return artifact metadata. For target.kind=jar, only <basename>-sources.jar is auto-adopted; other adjacent *-sources.jar files are informational.", resolveArtifactShape, { readOnlyHint: true }, async (args) => runTool("resolve-artifact", args, resolveArtifactSchema, async (input) => sourceService.resolveArtifact({
|
|
1590
1687
|
target: input.target,
|
|
@@ -1594,7 +1691,8 @@ server.tool("resolve-artifact", "Resolve source artifact from a target object ({
|
|
|
1594
1691
|
projectPath: input.projectPath,
|
|
1595
1692
|
scope: input.scope,
|
|
1596
1693
|
preferProjectVersion: input.preferProjectVersion,
|
|
1597
|
-
strictVersion: input.strictVersion
|
|
1694
|
+
strictVersion: input.strictVersion,
|
|
1695
|
+
compact: input.compact
|
|
1598
1696
|
})));
|
|
1599
1697
|
const findClassShape = {
|
|
1600
1698
|
className: nonEmptyString.describe("Simple name (e.g. Blocks) or fully-qualified name (e.g. net.minecraft.world.level.block.Blocks)"),
|
|
@@ -1664,7 +1762,9 @@ server.tool("search-class-source", "Search indexed class source files for one ar
|
|
|
1664
1762
|
scope: scope,
|
|
1665
1763
|
queryMode: input.queryMode,
|
|
1666
1764
|
limit: input.limit,
|
|
1667
|
-
cursor: input.cursor
|
|
1765
|
+
cursor: input.cursor,
|
|
1766
|
+
queryNamespace: input.queryNamespace,
|
|
1767
|
+
sourcePriority: input.sourcePriority
|
|
1668
1768
|
});
|
|
1669
1769
|
}));
|
|
1670
1770
|
server.tool("get-artifact-file", "Get full source file content by artifactId and file path.", getArtifactFileShape, { readOnlyHint: true }, async (args) => runTool("get-artifact-file", args, getArtifactFileSchema, async (input) => sourceService.getArtifactFile({
|
|
@@ -1672,7 +1772,12 @@ server.tool("get-artifact-file", "Get full source file content by artifactId and
|
|
|
1672
1772
|
filePath: input.filePath,
|
|
1673
1773
|
maxBytes: input.maxBytes
|
|
1674
1774
|
})));
|
|
1675
|
-
server.tool("list-artifact-files", "List source file paths in an artifact with optional prefix filter and cursor-based pagination.", listArtifactFilesShape, { readOnlyHint: true }, async (args) => runTool("list-artifact-files", args, listArtifactFilesSchema, async (input) => sourceService.listArtifactFiles(
|
|
1775
|
+
server.tool("list-artifact-files", "List source file paths in an artifact with optional prefix filter and cursor-based pagination.", listArtifactFilesShape, { readOnlyHint: true }, async (args) => runTool("list-artifact-files", args, listArtifactFilesSchema, async (input) => sourceService.listArtifactFiles({
|
|
1776
|
+
artifactId: input.artifactId,
|
|
1777
|
+
prefix: input.prefix,
|
|
1778
|
+
limit: input.limit,
|
|
1779
|
+
cursor: input.cursor
|
|
1780
|
+
})));
|
|
1676
1781
|
server.tool("trace-symbol-lifecycle", "Trace which Minecraft versions contain a specific class method and report first/last seen versions.", traceSymbolLifecycleShape, { readOnlyHint: true }, async (args) => runTool("trace-symbol-lifecycle", args, traceSymbolLifecycleSchema, async (input) => sourceService.traceSymbolLifecycle({
|
|
1677
1782
|
symbol: input.symbol,
|
|
1678
1783
|
descriptor: input.descriptor,
|
|
@@ -1701,6 +1806,7 @@ server.tool("find-mapping", "Find symbol mapping candidates between namespaces u
|
|
|
1701
1806
|
sourceMapping: input.sourceMapping,
|
|
1702
1807
|
targetMapping: input.targetMapping,
|
|
1703
1808
|
sourcePriority: input.sourcePriority,
|
|
1809
|
+
signatureMode: input.signatureMode,
|
|
1704
1810
|
disambiguation: input.disambiguation,
|
|
1705
1811
|
maxCandidates: input.maxCandidates
|
|
1706
1812
|
})));
|
|
@@ -1785,7 +1891,19 @@ server.tool("validate-access-widener", "Validate Access Widener file entries aga
|
|
|
1785
1891
|
content: input.content,
|
|
1786
1892
|
version: input.version,
|
|
1787
1893
|
mapping: input.mapping,
|
|
1788
|
-
sourcePriority: input.sourcePriority
|
|
1894
|
+
sourcePriority: input.sourcePriority,
|
|
1895
|
+
projectPath: input.projectPath,
|
|
1896
|
+
scope: input.scope,
|
|
1897
|
+
preferProjectVersion: input.preferProjectVersion
|
|
1898
|
+
})));
|
|
1899
|
+
server.tool("validate-access-transformer", "Validate Access Transformer file entries against Minecraft bytecode signatures for a given version.", validateAccessTransformerShape, { readOnlyHint: true }, async (args) => runTool("validate-access-transformer", args, validateAccessTransformerSchema, async (input) => sourceService.validateAccessTransformer({
|
|
1900
|
+
content: input.content,
|
|
1901
|
+
version: input.version,
|
|
1902
|
+
atNamespace: input.atNamespace,
|
|
1903
|
+
sourcePriority: input.sourcePriority,
|
|
1904
|
+
projectPath: input.projectPath,
|
|
1905
|
+
scope: input.scope,
|
|
1906
|
+
preferProjectVersion: input.preferProjectVersion
|
|
1789
1907
|
})));
|
|
1790
1908
|
server.tool("analyze-mod-jar", "Analyze a Minecraft mod JAR to extract loader type, metadata, entrypoints, mixins, and dependencies.", analyzeModJarShape, { readOnlyHint: true }, async (args) => runTool("analyze-mod-jar", args, analyzeModJarSchema, async (input) => {
|
|
1791
1909
|
const result = await analyzeModJar(input.jarPath, {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O(1) doubly-linked list + Map LRU.
|
|
3
|
+
* head = oldest, tail = newest.
|
|
4
|
+
*/
|
|
5
|
+
export declare class LruList<T> {
|
|
6
|
+
private map;
|
|
7
|
+
private head;
|
|
8
|
+
private tail;
|
|
9
|
+
get size(): number;
|
|
10
|
+
/** O(1) — move to tail (most recent), return value reference. */
|
|
11
|
+
touch(key: string): T | undefined;
|
|
12
|
+
/** O(1) — insert or update + move to tail. Returns previous value if existed. */
|
|
13
|
+
upsert(key: string, value: T): T | undefined;
|
|
14
|
+
/** O(1) — remove by key, return removed value. */
|
|
15
|
+
remove(key: string): T | undefined;
|
|
16
|
+
/** O(1) — peek at oldest (head) without removing. */
|
|
17
|
+
peekOldest(): {
|
|
18
|
+
key: string;
|
|
19
|
+
value: T;
|
|
20
|
+
} | undefined;
|
|
21
|
+
/** O(1) — clear all entries. */
|
|
22
|
+
clear(): void;
|
|
23
|
+
/** O(n) — iterate oldest → newest. */
|
|
24
|
+
toArray(): Array<{
|
|
25
|
+
key: string;
|
|
26
|
+
value: T;
|
|
27
|
+
}>;
|
|
28
|
+
private unlink;
|
|
29
|
+
private appendToTail;
|
|
30
|
+
private moveToTail;
|
|
31
|
+
}
|
package/dist/lru-list.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O(1) doubly-linked list + Map LRU.
|
|
3
|
+
* head = oldest, tail = newest.
|
|
4
|
+
*/
|
|
5
|
+
export class LruList {
|
|
6
|
+
map = new Map();
|
|
7
|
+
head = null;
|
|
8
|
+
tail = null;
|
|
9
|
+
get size() {
|
|
10
|
+
return this.map.size;
|
|
11
|
+
}
|
|
12
|
+
/** O(1) — move to tail (most recent), return value reference. */
|
|
13
|
+
touch(key) {
|
|
14
|
+
const node = this.map.get(key);
|
|
15
|
+
if (!node) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
this.moveToTail(node);
|
|
19
|
+
return node.value;
|
|
20
|
+
}
|
|
21
|
+
/** O(1) — insert or update + move to tail. Returns previous value if existed. */
|
|
22
|
+
upsert(key, value) {
|
|
23
|
+
const existing = this.map.get(key);
|
|
24
|
+
if (existing) {
|
|
25
|
+
const prev = existing.value;
|
|
26
|
+
existing.value = value;
|
|
27
|
+
this.moveToTail(existing);
|
|
28
|
+
return prev;
|
|
29
|
+
}
|
|
30
|
+
const node = { key, value, prev: null, next: null };
|
|
31
|
+
this.map.set(key, node);
|
|
32
|
+
this.appendToTail(node);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/** O(1) — remove by key, return removed value. */
|
|
36
|
+
remove(key) {
|
|
37
|
+
const node = this.map.get(key);
|
|
38
|
+
if (!node) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
this.unlink(node);
|
|
42
|
+
this.map.delete(key);
|
|
43
|
+
return node.value;
|
|
44
|
+
}
|
|
45
|
+
/** O(1) — peek at oldest (head) without removing. */
|
|
46
|
+
peekOldest() {
|
|
47
|
+
if (!this.head) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return { key: this.head.key, value: this.head.value };
|
|
51
|
+
}
|
|
52
|
+
/** O(1) — clear all entries. */
|
|
53
|
+
clear() {
|
|
54
|
+
this.map.clear();
|
|
55
|
+
this.head = null;
|
|
56
|
+
this.tail = null;
|
|
57
|
+
}
|
|
58
|
+
/** O(n) — iterate oldest → newest. */
|
|
59
|
+
toArray() {
|
|
60
|
+
const result = [];
|
|
61
|
+
let current = this.head;
|
|
62
|
+
while (current) {
|
|
63
|
+
result.push({ key: current.key, value: current.value });
|
|
64
|
+
current = current.next;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
unlink(node) {
|
|
69
|
+
if (node.prev) {
|
|
70
|
+
node.prev.next = node.next;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.head = node.next;
|
|
74
|
+
}
|
|
75
|
+
if (node.next) {
|
|
76
|
+
node.next.prev = node.prev;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.tail = node.prev;
|
|
80
|
+
}
|
|
81
|
+
node.prev = null;
|
|
82
|
+
node.next = null;
|
|
83
|
+
}
|
|
84
|
+
appendToTail(node) {
|
|
85
|
+
if (!this.tail) {
|
|
86
|
+
this.head = node;
|
|
87
|
+
this.tail = node;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
node.prev = this.tail;
|
|
91
|
+
this.tail.next = node;
|
|
92
|
+
this.tail = node;
|
|
93
|
+
}
|
|
94
|
+
moveToTail(node) {
|
|
95
|
+
if (node === this.tail) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.unlink(node);
|
|
99
|
+
this.appendToTail(node);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=lru-list.js.map
|
|
@@ -3,6 +3,15 @@ export interface MappingPipelineInput {
|
|
|
3
3
|
requestedMapping: SourceMapping;
|
|
4
4
|
target: SourceTargetInput;
|
|
5
5
|
resolved: ResolvedSourceArtifact;
|
|
6
|
+
runtimeNamesUnobfuscated?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* When true and the mojang request lands on a binary-only artifact, the pipeline
|
|
9
|
+
* authorizes a downstream tiny-remap (obfuscated -> mojang) followed by decompile
|
|
10
|
+
* instead of throwing MAPPING_NOT_APPLIED. The caller is responsible for
|
|
11
|
+
* pre-resolving tiny-remapper jar, mojang tiny mappings, and verifying mapping
|
|
12
|
+
* health before setting this flag.
|
|
13
|
+
*/
|
|
14
|
+
allowBinaryRemap?: boolean;
|
|
6
15
|
}
|
|
7
16
|
export interface MappingPipelineResult {
|
|
8
17
|
mappingApplied: SourceMapping;
|
|
@@ -13,6 +22,8 @@ export interface MappingPipelineResult {
|
|
|
13
22
|
* Mapping pipeline for v0.3.
|
|
14
23
|
* Current implementation enforces explicit guarantees:
|
|
15
24
|
* - obfuscated: always pass-through
|
|
16
|
-
* - mojang: requires source-backed
|
|
25
|
+
* - mojang: requires source-backed artifacts on legacy obfuscated versions,
|
|
26
|
+
* but unobfuscated runtime jars can pass through directly,
|
|
27
|
+
* or binary-only artifacts may be remapped + decompiled when allowBinaryRemap=true
|
|
17
28
|
*/
|
|
18
29
|
export declare function applyMappingPipeline(input: MappingPipelineInput): MappingPipelineResult;
|