@adhisang/minecraft-modding-mcp 6.0.0 → 6.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 +19 -0
- package/dist/config.js +1 -1
- package/dist/entry-tools/batch-class-members-service.d.ts +2 -0
- package/dist/entry-tools/batch-class-members-service.js +1 -0
- package/dist/entry-tools/validate-project/cases/project-summary.js +30 -12
- package/dist/index.js +1 -0
- package/dist/mapping-service.js +1 -1
- package/dist/minecraft-explorer-service.js +2 -1
- package/dist/source/class-source/members-builder.d.ts +26 -0
- package/dist/source/class-source/members-builder.js +31 -4
- package/dist/source/class-source.js +39 -5
- package/dist/source/indexer.js +1 -1
- package/dist/source/member-pattern.d.ts +16 -0
- package/dist/source/member-pattern.js +27 -0
- package/dist/source-service.d.ts +8 -4
- package/dist/source-service.js +1 -1
- package/dist/tool-guidance.js +1 -1
- package/dist/tool-schemas.d.ts +13 -2
- package/dist/tool-schemas.js +13 -8
- package/docs/tool-reference.md +23 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project aims to follow [Semantic Versioning](https://semver.org/spec/v2
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [6.1.0] - 2026-06-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `get-class-members` / `batch-class-members` accept a `projection` parameter — `"names"` (member names only), `"signatures"` (name + `javaSignature`, no `jvmDescriptor`), or `"full"` (default; the complete member shape). Use the leaner projections to cut response tokens for "does this member exist?" / signature-only checks. Default `"full"` output is unchanged.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `get-class-source` responses for a decompiled artifact now carry a `decompiled-source-signatures-unverified` quality flag and a warning that decompiled method/accessor names may differ from the jar the workspace actually compiles against (e.g. a decompiled `getGameRenderState()` vs the runtime `gameRenderState()`); confirm signatures with `get-class-members` (bytecode-derived) before copying names from the source.
|
|
19
|
+
- Inspecting a Fabric / loader dependency class like vanilla is documented and surfaced: the `target` descriptions, `dependency` target fields, the `get-class-source` / `get-class-members` target-shape error guidance, and `docs/tool-reference.md` now show passing `target: { kind: "dependency", group, name, versionFromProject }` straight to the class tools (no separate lookup tool needed).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `memberPattern` (`get-class-members` / `batch-class-members`) treats `"|"` as OR alternation, so a natural pattern like `"getStateForPlacement|canSurvive|setPlacedBy"` matches any of those members. Previously the pattern was matched as a single literal substring, so a piped pattern searched for a name containing a literal `"|"` and returned zero members on large vanilla classes such as `Block` and `EntityRenderer`. Single-token patterns keep their case-insensitive substring behavior. The parameter description now documents the substring + OR semantics.
|
|
24
|
+
|
|
25
|
+
### Performance
|
|
26
|
+
|
|
27
|
+
- `validate-project` (`project-summary`) validates discovered mixin configs with bounded concurrency (default 4) instead of one at a time; aggregate counts and warning order are identical to the previous sequential behavior.
|
|
28
|
+
|
|
10
29
|
## [6.0.0] - 2026-06-25
|
|
11
30
|
|
|
12
31
|
### Changed
|
package/dist/config.js
CHANGED
|
@@ -211,7 +211,7 @@ function aliasJarBase(jarPath) {
|
|
|
211
211
|
// to earlier callers. Two distinct artifactIds whose readable tokens collide and
|
|
212
212
|
// whose first 48 hash bits also collide would trip the schema-v4 alias UNIQUE
|
|
213
213
|
// constraint at upsert time — a hard error, not silent drift.
|
|
214
|
-
//
|
|
214
|
+
// Currently display-only; a later change stores it for lookup.
|
|
215
215
|
export function buildArtifactAlias(input) {
|
|
216
216
|
const tokens = [];
|
|
217
217
|
if (input.kind === "version") {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ResponseDetailLevel } from "../response-utils.js";
|
|
2
2
|
import type { GetClassMembersInput, GetClassMembersOutput, ResolveArtifactInput, ResolveArtifactOutput } from "../source-service.js";
|
|
3
3
|
import type { ArtifactScope, MappingSourcePriority, ResolveArtifactTargetInput, SourceMapping } from "../types.js";
|
|
4
|
+
import type { MemberProjection } from "../source/class-source/members-builder.js";
|
|
4
5
|
import { type BatchOutput } from "./batch-runner.js";
|
|
5
6
|
export type BatchClassMembersDeps = {
|
|
6
7
|
resolveArtifact: (input: ResolveArtifactInput) => Promise<ResolveArtifactOutput>;
|
|
@@ -27,6 +28,7 @@ export type BatchClassMembersInput = {
|
|
|
27
28
|
concurrency?: number;
|
|
28
29
|
failFast?: boolean;
|
|
29
30
|
detail?: ResponseDetailLevel;
|
|
31
|
+
projection?: MemberProjection;
|
|
30
32
|
include?: readonly string[];
|
|
31
33
|
entries: readonly BatchClassMembersEntry[];
|
|
32
34
|
};
|
|
@@ -54,6 +54,7 @@ export class BatchClassMembersService {
|
|
|
54
54
|
includeInherited: entry.includeInherited,
|
|
55
55
|
memberPattern: entry.memberPattern,
|
|
56
56
|
maxMembers: entry.maxMembers,
|
|
57
|
+
projection: input.projection,
|
|
57
58
|
includeDescriptors: include.has("descriptors"),
|
|
58
59
|
mapping: input.mapping,
|
|
59
60
|
sourcePriority: input.sourcePriority,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { mapWithConcurrencyLimit } from "../../../concurrency.js";
|
|
2
3
|
import { buildEntryToolResult, createSummarySubject } from "../../response-contract.js";
|
|
3
4
|
import { ERROR_CODES, createError } from "../../../errors.js";
|
|
4
5
|
import { buildEarlyTasksForBlocked, buildFullTaskStatusReport } from "../internal.js";
|
|
@@ -199,7 +200,14 @@ export async function handleProjectSummary(deps, input, detail, include, options
|
|
|
199
200
|
await safeEmit(options.stageEmitter, "validate-project:mixin-validation", {
|
|
200
201
|
targetTotal: mixinConfigs.length
|
|
201
202
|
});
|
|
202
|
-
|
|
203
|
+
// Validate mixin configs with bounded concurrency (default 4, matching the
|
|
204
|
+
// batch tools). Each unit returns its own counts/warnings; aggregation happens
|
|
205
|
+
// afterward in input order so totals and warning order are identical to a
|
|
206
|
+
// sequential run. Concurrent validateMixin against one SourceService is already
|
|
207
|
+
// exercised by the batch-class-* tools (shared artifact resolution, idempotent
|
|
208
|
+
// caches, synchronous SQLite), so this adds no new shared-state hazard.
|
|
209
|
+
const MIXIN_VALIDATION_CONCURRENCY = 4;
|
|
210
|
+
const mixinResults = await mapWithConcurrencyLimit(mixinConfigs, MIXIN_VALIDATION_CONCURRENCY, async (configPath, mixinIndex) => {
|
|
203
211
|
try {
|
|
204
212
|
await safeEmit(options.stageEmitter, "validate-project:mixin-validation", {
|
|
205
213
|
targetIndex: mixinIndex + 1,
|
|
@@ -232,20 +240,30 @@ export async function handleProjectSummary(deps, input, detail, include, options
|
|
|
232
240
|
stageEmitter: wrappedEmitter
|
|
233
241
|
});
|
|
234
242
|
const summary = mixinResult.summary;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
243
|
+
return {
|
|
244
|
+
valid: summary?.valid ?? 0,
|
|
245
|
+
partial: summary?.partial ?? 0,
|
|
246
|
+
invalid: summary?.invalid ?? 0,
|
|
247
|
+
caught: 0,
|
|
248
|
+
warnings: Array.isArray(mixinResult.warnings) ? [...mixinResult.warnings] : []
|
|
249
|
+
};
|
|
241
250
|
}
|
|
242
251
|
catch (error) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
252
|
+
return {
|
|
253
|
+
valid: 0,
|
|
254
|
+
partial: 0,
|
|
255
|
+
invalid: 1,
|
|
256
|
+
caught: 1,
|
|
257
|
+
warnings: error instanceof Error ? [`${configPath}: ${error.message}`] : []
|
|
258
|
+
};
|
|
248
259
|
}
|
|
260
|
+
});
|
|
261
|
+
for (const result of mixinResults) {
|
|
262
|
+
validMixins += result.valid;
|
|
263
|
+
partialMixins += result.partial;
|
|
264
|
+
invalidMixins += result.invalid;
|
|
265
|
+
mixinCaughtErrors += result.caught;
|
|
266
|
+
warnings.push(...result.warnings);
|
|
249
267
|
}
|
|
250
268
|
const mixinDurationMs = Date.now() - mixinDurationStart;
|
|
251
269
|
const awDurationStart = Date.now();
|
package/dist/index.js
CHANGED
|
@@ -573,6 +573,7 @@ expertTool("get-class-members", "Get fields/methods/constructors for one class f
|
|
|
573
573
|
includeInherited: input.includeInherited,
|
|
574
574
|
memberPattern: input.memberPattern,
|
|
575
575
|
maxMembers: input.maxMembers,
|
|
576
|
+
projection: input.projection,
|
|
576
577
|
cursor: input.cursor,
|
|
577
578
|
projectPath: input.projectPath,
|
|
578
579
|
gradleUserHome: input.gradleUserHome,
|
package/dist/mapping-service.js
CHANGED
|
@@ -581,7 +581,7 @@ export class MappingService {
|
|
|
581
581
|
const nextCursor = rowsTruncated ? encodeOffsetCursor(consumedRows, rowCursorContext) : undefined;
|
|
582
582
|
// Map ONLY the requested window. Per-row mapping cost is therefore O(window),
|
|
583
583
|
// not O(rowCount). warnings/ambiguousRowCount are accordingly page-scoped on
|
|
584
|
-
// paginated calls
|
|
584
|
+
// paginated calls and byte-identical to the old full-set values when
|
|
585
585
|
// no maxRows/cursor narrows the window.
|
|
586
586
|
const rows = [];
|
|
587
587
|
let ambiguousRowCount = 0;
|
|
@@ -2,6 +2,7 @@ import { createError, ERROR_CODES } from "./errors.js";
|
|
|
2
2
|
import { loadConfig } from "./config.js";
|
|
3
3
|
import { artifactSignatureFromFile, normalizeJarPath } from "./path-resolver.js";
|
|
4
4
|
import { createJarEntryReader } from "./source-jar-reader.js";
|
|
5
|
+
import { matchesMemberPattern } from "./source/member-pattern.js";
|
|
5
6
|
const CLASSFILE_MAGIC = 0xcafebabe;
|
|
6
7
|
const MAX_INHERITANCE_DEPTH = 64;
|
|
7
8
|
const ACC_PUBLIC = 0x0001;
|
|
@@ -603,7 +604,7 @@ export class MinecraftExplorerService {
|
|
|
603
604
|
if (access === "public" && !hasPublicVisibility(member.accessFlags)) {
|
|
604
605
|
return false;
|
|
605
606
|
}
|
|
606
|
-
if (memberPattern && !
|
|
607
|
+
if (memberPattern && !matchesMemberPattern(member.name, memberPattern)) {
|
|
607
608
|
return false;
|
|
608
609
|
}
|
|
609
610
|
return true;
|
|
@@ -76,3 +76,29 @@ export declare function projectMembersForWire(slice: {
|
|
|
76
76
|
fields: SignatureMember[];
|
|
77
77
|
methods: SignatureMember[];
|
|
78
78
|
}, includeInherited: boolean, keepFieldDescriptors?: boolean): WireMembersBlock;
|
|
79
|
+
/**
|
|
80
|
+
* Token-projection level for a member listing, narrowing the per-member fields
|
|
81
|
+
* an agent receives:
|
|
82
|
+
* - `full` (default): the complete {@link WireMember} shape (current behavior).
|
|
83
|
+
* - `signatures`: name + javaSignature (drops jvmDescriptor) — enough to read
|
|
84
|
+
* the API without overload descriptors.
|
|
85
|
+
* - `names`: member name only — enough for an "does this member exist?" check.
|
|
86
|
+
* The block-level hoisted `ownerFqn` and any per-member `ownerFqn` (the
|
|
87
|
+
* multi-owner / includeInherited case) are preserved in every level so members
|
|
88
|
+
* stay attributable.
|
|
89
|
+
*/
|
|
90
|
+
export type MemberProjection = "names" | "signatures" | "full";
|
|
91
|
+
export type ProjectedMember = {
|
|
92
|
+
name: string;
|
|
93
|
+
javaSignature?: string;
|
|
94
|
+
jvmDescriptor?: string;
|
|
95
|
+
ownerFqn?: string;
|
|
96
|
+
isSynthetic?: boolean;
|
|
97
|
+
};
|
|
98
|
+
export type ProjectedMembersBlock = {
|
|
99
|
+
ownerFqn?: string;
|
|
100
|
+
constructors: ProjectedMember[];
|
|
101
|
+
fields: ProjectedMember[];
|
|
102
|
+
methods: ProjectedMember[];
|
|
103
|
+
};
|
|
104
|
+
export declare function projectMembersByLevel(block: WireMembersBlock, level: MemberProjection): ProjectedMembersBlock;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { matchesMemberPattern } from "../member-pattern.js";
|
|
1
2
|
export async function remapAndCountMembers(svc, input) {
|
|
2
3
|
const remap = async (members, kind) => {
|
|
3
4
|
if (input.version == null) {
|
|
@@ -10,10 +11,10 @@ export async function remapAndCountMembers(svc, input) {
|
|
|
10
11
|
let fields = await remap(input.signatureFields, "field");
|
|
11
12
|
let methods = await remap(input.signatureMethods, "method");
|
|
12
13
|
if (input.requestedMapping !== input.mappingApplied && input.memberPattern) {
|
|
13
|
-
const
|
|
14
|
-
constructors = constructors.filter((m) => m.name
|
|
15
|
-
fields = fields.filter((m) => m.name
|
|
16
|
-
methods = methods.filter((m) => m.name
|
|
14
|
+
const pattern = input.memberPattern;
|
|
15
|
+
constructors = constructors.filter((m) => matchesMemberPattern(m.name, pattern));
|
|
16
|
+
fields = fields.filter((m) => matchesMemberPattern(m.name, pattern));
|
|
17
|
+
methods = methods.filter((m) => matchesMemberPattern(m.name, pattern));
|
|
17
18
|
}
|
|
18
19
|
const counts = {
|
|
19
20
|
constructors: constructors.length,
|
|
@@ -90,4 +91,30 @@ export function projectMembersForWire(slice, includeInherited, keepFieldDescript
|
|
|
90
91
|
methods: slice.methods.map((m) => toWire(m, true))
|
|
91
92
|
};
|
|
92
93
|
}
|
|
94
|
+
export function projectMembersByLevel(block, level) {
|
|
95
|
+
if (level === "full") {
|
|
96
|
+
return block;
|
|
97
|
+
}
|
|
98
|
+
const reduce = (m) => {
|
|
99
|
+
if (level === "names") {
|
|
100
|
+
return {
|
|
101
|
+
name: m.name,
|
|
102
|
+
...(m.ownerFqn ? { ownerFqn: m.ownerFqn } : {})
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// "signatures": keep the readable signature, drop the JVM descriptor.
|
|
106
|
+
return {
|
|
107
|
+
name: m.name,
|
|
108
|
+
javaSignature: m.javaSignature,
|
|
109
|
+
...(m.ownerFqn ? { ownerFqn: m.ownerFqn } : {}),
|
|
110
|
+
...(m.isSynthetic ? { isSynthetic: true } : {})
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
...(block.ownerFqn ? { ownerFqn: block.ownerFqn } : {}),
|
|
115
|
+
constructors: block.constructors.map(reduce),
|
|
116
|
+
fields: block.fields.map(reduce),
|
|
117
|
+
methods: block.methods.map(reduce)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
93
120
|
//# sourceMappingURL=members-builder.js.map
|
|
@@ -5,7 +5,8 @@ import { ERROR_CODES, createError, isAppError } from "../errors.js";
|
|
|
5
5
|
import * as artifactResolver from "./artifact-resolver.js";
|
|
6
6
|
import * as classSourceHelpers from "./class-source-helpers.js";
|
|
7
7
|
import { buildClassSourceSnippet } from "./class-source/snippet-builder.js";
|
|
8
|
-
import { remapAndCountMembers, sliceMembersWithLimit, projectMembersForWire } from "./class-source/members-builder.js";
|
|
8
|
+
import { remapAndCountMembers, sliceMembersWithLimit, projectMembersForWire, projectMembersByLevel } from "./class-source/members-builder.js";
|
|
9
|
+
import { matchesMemberPattern } from "./member-pattern.js";
|
|
9
10
|
import { buildPageContextKey, encodeOffsetCursor, resolveCursorOffset } from "../page-cursor.js";
|
|
10
11
|
import { dedupeQualityFlags, normalizeMapping, normalizeOptionalString, normalizePathStyle } from "./shared-utils.js";
|
|
11
12
|
import { isUnobfuscatedVersion } from "../version-service.js";
|
|
@@ -239,8 +240,7 @@ export function buildDecompiledFallback(svc, artifactId, lookupClassName, member
|
|
|
239
240
|
if (!memberPattern) {
|
|
240
241
|
return list;
|
|
241
242
|
}
|
|
242
|
-
|
|
243
|
-
return list.filter((entry) => entry.name.toLowerCase().includes(lower));
|
|
243
|
+
return list.filter((entry) => matchesMemberPattern(entry.name, memberPattern));
|
|
244
244
|
};
|
|
245
245
|
let constructors = filterByPattern(extracted.constructors);
|
|
246
246
|
let fields = filterByPattern(extracted.fields);
|
|
@@ -280,6 +280,25 @@ export function buildDecompiledFallback(svc, artifactId, lookupClassName, member
|
|
|
280
280
|
truncated: totalBefore > maxMembers
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Apply a member projection to the decompiled fallback so it honors the same
|
|
285
|
+
* `projection` contract as the bytecode members block. The fallback only carries
|
|
286
|
+
* names + source line + kind (no signatures), so any non-"full" level reduces to
|
|
287
|
+
* the member name (the array it lives in already conveys the kind). Keeps the
|
|
288
|
+
* full shape for the default "full" level.
|
|
289
|
+
*/
|
|
290
|
+
function projectDecompiledFallback(fallback, level) {
|
|
291
|
+
if (level === "full") {
|
|
292
|
+
return fallback;
|
|
293
|
+
}
|
|
294
|
+
const reduce = (member) => ({ name: member.name });
|
|
295
|
+
return {
|
|
296
|
+
constructors: fallback.constructors.map(reduce),
|
|
297
|
+
fields: fallback.fields.map(reduce),
|
|
298
|
+
methods: fallback.methods.map(reduce),
|
|
299
|
+
origin: fallback.origin
|
|
300
|
+
};
|
|
301
|
+
}
|
|
283
302
|
// The class-like symbol kinds findClass returns. MUST stay in sync with the JS-side
|
|
284
303
|
// isTypeSymbol checks below; pushed down to SQL so non-type rows are never fetched.
|
|
285
304
|
const TYPE_SYMBOL_KINDS = ["class", "interface", "enum", "record"];
|
|
@@ -652,6 +671,20 @@ export async function getClassSource(svc, input) {
|
|
|
652
671
|
}
|
|
653
672
|
})
|
|
654
673
|
: undefined;
|
|
674
|
+
// Decompiled source text can use different method/accessor names than the jar
|
|
675
|
+
// the workspace actually compiles against (e.g. `getGameRenderState()` in the
|
|
676
|
+
// decompiled source vs `gameRenderState()` in the runtime jar). Flag it so
|
|
677
|
+
// callers verify names against get-class-members (bytecode-derived) before
|
|
678
|
+
// copying signatures out of this source.
|
|
679
|
+
if (activeOrigin === "decompiled") {
|
|
680
|
+
activeQualityFlags = dedupeQualityFlags([
|
|
681
|
+
...activeQualityFlags,
|
|
682
|
+
"decompiled-source-signatures-unverified"
|
|
683
|
+
]);
|
|
684
|
+
warnings.push("Source is decompiled: method/accessor names may differ from the jar the workspace "
|
|
685
|
+
+ "compiles against. Confirm signatures with get-class-members (bytecode-derived) "
|
|
686
|
+
+ "before copying names from this source.");
|
|
687
|
+
}
|
|
655
688
|
return {
|
|
656
689
|
className,
|
|
657
690
|
mode,
|
|
@@ -889,7 +922,8 @@ export async function getClassMembers(svc, input) {
|
|
|
889
922
|
// Slim the wire member shape: hoist a shared ownerFqn, drop accessFlags, omit
|
|
890
923
|
// isSynthetic:false, and drop FIELD jvmDescriptor unless includeDescriptors.
|
|
891
924
|
// Internal SignatureMember arrays above stay intact.
|
|
892
|
-
const
|
|
925
|
+
const projection = input.projection ?? "full";
|
|
926
|
+
const projectedMembers = projectMembersByLevel(projectMembersForWire({ constructors, fields, methods }, includeInherited, input.includeDescriptors ?? false), projection);
|
|
893
927
|
const truncated = sliced.truncated;
|
|
894
928
|
const nextCursor = sliced.nextOffset != null ? encodeOffsetCursor(sliced.nextOffset, memberCursorContext) : undefined;
|
|
895
929
|
const normalizedProvenance = provenance ??
|
|
@@ -907,7 +941,7 @@ export async function getClassMembers(svc, input) {
|
|
|
907
941
|
const fallbackPattern = namespaceMismatch ? undefined : memberPattern;
|
|
908
942
|
const sourceFallback = buildDecompiledFallback(svc, artifactId, lookupClassName, fallbackPattern, maxMembers);
|
|
909
943
|
if (sourceFallback) {
|
|
910
|
-
decompiledFallback = sourceFallback.fallback;
|
|
944
|
+
decompiledFallback = projectDecompiledFallback(sourceFallback.fallback, projection);
|
|
911
945
|
decompiledMemberCounts = sourceFallback.counts;
|
|
912
946
|
fallbackQualityFlags = dedupeQualityFlags([
|
|
913
947
|
...qualityFlags,
|
package/dist/source/indexer.js
CHANGED
|
@@ -213,7 +213,7 @@ export async function buildRebuiltArtifactData(svc, resolved) {
|
|
|
213
213
|
// Decompilation failed BEFORE the artifact was ever upserted, so there is no
|
|
214
214
|
// queryable artifact. Deliberately omit artifactId from the error: exposing the
|
|
215
215
|
// would-be id led callers to pass it to find-class/get-class-*, which then failed
|
|
216
|
-
// with "Artifact not found. Resolve context first."
|
|
216
|
+
// with "Artifact not found. Resolve context first." — a state inconsistency.
|
|
217
217
|
const priorDetails = { ...(caughtError.details ?? {}) };
|
|
218
218
|
delete priorDetails.artifactId;
|
|
219
219
|
throw createError({
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match a class-member name against a `memberPattern` filter.
|
|
3
|
+
*
|
|
4
|
+
* Matching is case-insensitive substring. A `|` splits the pattern into OR
|
|
5
|
+
* alternatives, so `"getStateForPlacement|canSurvive|setPlacedBy"` matches a
|
|
6
|
+
* name that contains ANY of those tokens. Before this, the pattern was matched
|
|
7
|
+
* as a single literal substring, so a piped pattern searched for a name
|
|
8
|
+
* containing a literal `|` and matched nothing — which made member listing
|
|
9
|
+
* return zero on large vanilla classes when callers used the natural OR syntax.
|
|
10
|
+
*
|
|
11
|
+
* Java member names never contain `|`, so treating `|` as OR never collides with
|
|
12
|
+
* a legitimate substring search. Empty or whitespace-only alternatives are
|
|
13
|
+
* dropped; a pattern with no usable alternative matches nothing (a non-empty
|
|
14
|
+
* filter that excludes everything), matching the prior empty-filter behavior.
|
|
15
|
+
*/
|
|
16
|
+
export declare function matchesMemberPattern(name: string, pattern: string): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match a class-member name against a `memberPattern` filter.
|
|
3
|
+
*
|
|
4
|
+
* Matching is case-insensitive substring. A `|` splits the pattern into OR
|
|
5
|
+
* alternatives, so `"getStateForPlacement|canSurvive|setPlacedBy"` matches a
|
|
6
|
+
* name that contains ANY of those tokens. Before this, the pattern was matched
|
|
7
|
+
* as a single literal substring, so a piped pattern searched for a name
|
|
8
|
+
* containing a literal `|` and matched nothing — which made member listing
|
|
9
|
+
* return zero on large vanilla classes when callers used the natural OR syntax.
|
|
10
|
+
*
|
|
11
|
+
* Java member names never contain `|`, so treating `|` as OR never collides with
|
|
12
|
+
* a legitimate substring search. Empty or whitespace-only alternatives are
|
|
13
|
+
* dropped; a pattern with no usable alternative matches nothing (a non-empty
|
|
14
|
+
* filter that excludes everything), matching the prior empty-filter behavior.
|
|
15
|
+
*/
|
|
16
|
+
export function matchesMemberPattern(name, pattern) {
|
|
17
|
+
const alternatives = pattern
|
|
18
|
+
.split("|")
|
|
19
|
+
.map((part) => part.trim().toLowerCase())
|
|
20
|
+
.filter((part) => part.length > 0);
|
|
21
|
+
if (alternatives.length === 0) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const lowerName = name.toLowerCase();
|
|
25
|
+
return alternatives.some((alt) => lowerName.includes(alt));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=member-pattern.js.map
|
package/dist/source-service.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import * as indexer from "./source/indexer.js";
|
|
|
11
11
|
import * as workspaceTarget from "./source/workspace-target.js";
|
|
12
12
|
import * as validateMixinModule from "./source/validate-mixin.js";
|
|
13
13
|
import * as artifactResolver from "./source/artifact-resolver.js";
|
|
14
|
-
import type {
|
|
14
|
+
import type { MemberProjection, ProjectedMembersBlock } from "./source/class-source/members-builder.js";
|
|
15
15
|
import { type StageEmitter } from "./stage-emitter.js";
|
|
16
16
|
import { WorkspaceMappingService, type WorkspaceCompileMappingOutput } from "./workspace-mapping-service.js";
|
|
17
17
|
import { type WorkspaceContextCache } from "./workspace-context-cache.js";
|
|
@@ -266,11 +266,15 @@ export type GetClassMembersInput = {
|
|
|
266
266
|
strictVersion?: boolean;
|
|
267
267
|
/** When true, keep jvmDescriptor on FIELD members (always kept on methods/constructors). */
|
|
268
268
|
includeDescriptors?: boolean;
|
|
269
|
+
/** Narrow the per-member fields returned: "names" | "signatures" | "full" (default "full"). */
|
|
270
|
+
projection?: MemberProjection;
|
|
269
271
|
};
|
|
270
272
|
export type DecompiledMember = {
|
|
271
273
|
name: string;
|
|
272
|
-
line
|
|
273
|
-
|
|
274
|
+
/** Source line of the declaration. Omitted under a non-"full" projection. */
|
|
275
|
+
line?: number;
|
|
276
|
+
/** Member kind. Omitted under a non-"full" projection (the array conveys it). */
|
|
277
|
+
kind?: "constructor" | "field" | "method";
|
|
274
278
|
};
|
|
275
279
|
export type DecompiledFallback = {
|
|
276
280
|
constructors: DecompiledMember[];
|
|
@@ -281,7 +285,7 @@ export type DecompiledFallback = {
|
|
|
281
285
|
export type GetClassMembersStatus = "ok" | "members_unavailable" | "partial";
|
|
282
286
|
export type GetClassMembersOutput = {
|
|
283
287
|
className: string;
|
|
284
|
-
members:
|
|
288
|
+
members: ProjectedMembersBlock;
|
|
285
289
|
counts: {
|
|
286
290
|
constructors: number;
|
|
287
291
|
fields: number;
|
package/dist/source-service.js
CHANGED
|
@@ -146,7 +146,7 @@ export class SourceService {
|
|
|
146
146
|
// Classes/fields surface as `mapping_unavailable` when the graph yields nothing, but
|
|
147
147
|
// a method query with a non-empty graph returns `not_found` (empty member lookup) —
|
|
148
148
|
// which previously skipped the runtime fallback and produced false negatives for
|
|
149
|
-
// methods that genuinely exist
|
|
149
|
+
// methods that genuinely exist. Treat `not_found` methods as fallback-eligible.
|
|
150
150
|
const fallbackEligible = result.status === "mapping_unavailable" ||
|
|
151
151
|
(result.status === "not_found" && input.kind === "method");
|
|
152
152
|
if (!fallbackEligible ||
|
package/dist/tool-guidance.js
CHANGED
|
@@ -672,7 +672,7 @@ export function buildInvalidInputGuidance(tool, normalizedInput) {
|
|
|
672
672
|
}
|
|
673
673
|
if (tool === "get-class-source" || tool === "get-class-members") {
|
|
674
674
|
return gatedGuidance(tool, [
|
|
675
|
-
`${tool}.target must be an object: {"kind":"version|jar|coordinate","value":"..."} or {"kind":"artifact","artifactId":"..."} (same shape as resolve-artifact).`,
|
|
675
|
+
`${tool}.target must be an object: {"kind":"version|jar|coordinate","value":"..."}, {"kind":"workspace"}, {"kind":"dependency","group":"...","name":"...","versionFromProject":true} (inspect a Fabric/loader dependency like vanilla), or {"kind":"artifact","artifactId":"..."} (same shape as resolve-artifact).`,
|
|
676
676
|
"Bare string targets are not accepted; wrap the value under target.kind/target.value."
|
|
677
677
|
], buildSourceLookupSuggestedParams(tool, normalizedInput));
|
|
678
678
|
}
|
package/dist/tool-schemas.d.ts
CHANGED
|
@@ -211,9 +211,12 @@ export declare const sourceLookupTargetSchema: z.ZodDiscriminatedUnion<"kind", [
|
|
|
211
211
|
kind: "artifact";
|
|
212
212
|
artifactId: string;
|
|
213
213
|
}>]>;
|
|
214
|
-
export declare const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = "Object, not string. e.g. {\"kind\":\"version\",\"value\":\"1.21.10\"}, {\"kind\":\"workspace\"}, {\"kind\":\"dependency\",\"group\":\"
|
|
215
|
-
export declare const SOURCE_LOOKUP_TARGET_DESCRIPTION = "Same shape as resolve-artifact target, plus {\"kind\":\"artifact\",\"artifactId\":\"...\"} to reuse a resolved artifact. Object, not string.";
|
|
214
|
+
export declare const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = "Object, not string. e.g. {\"kind\":\"version\",\"value\":\"1.21.10\"}, {\"kind\":\"workspace\"}, or to inspect a loader/Fabric dependency like vanilla: {\"kind\":\"dependency\",\"group\":\"net.fabricmc.fabric-api\",\"name\":\"fabric-api\",\"versionFromProject\":true} (needs projectPath) or with an explicit \"version\".";
|
|
215
|
+
export declare const SOURCE_LOOKUP_TARGET_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.";
|
|
216
216
|
export declare const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = merged runtime discovery; loader = loader-transformed runtime jars.";
|
|
217
|
+
export declare const MEMBER_PATTERN_DESCRIPTION = "Case-insensitive substring filter on member names. Use \"|\" for OR alternatives, e.g. \"getStateForPlacement|canSurvive|setPlacedBy\" (each token is matched as a substring, not a regex).";
|
|
218
|
+
export declare const memberProjectionSchema: z.ZodEnum<["names", "signatures", "full"]>;
|
|
219
|
+
export declare const MEMBER_PROJECTION_DESCRIPTION = "Per-member field projection: \"names\" (member name only), \"signatures\" (name + javaSignature, no jvmDescriptor), or \"full\" (default; complete member shape). Use \"names\"/\"signatures\" to cut response tokens for existence/signature checks.";
|
|
217
220
|
export declare const SIGNATURE_MODE_DESCRIPTION = "exact: descriptor required for kind=method; name-only (default): match by owner+name only.";
|
|
218
221
|
export declare const NAME_MODE_DESCRIPTION = "auto (default): FQCN, or dotless name where allowed; fqcn: require FQCN.";
|
|
219
222
|
export declare const listVersionsShape: {
|
|
@@ -850,6 +853,7 @@ export declare const getClassMembersShape: {
|
|
|
850
853
|
includeSynthetic: z.ZodDefault<z.ZodBoolean>;
|
|
851
854
|
includeInherited: z.ZodDefault<z.ZodBoolean>;
|
|
852
855
|
memberPattern: z.ZodOptional<z.ZodString>;
|
|
856
|
+
projection: z.ZodOptional<z.ZodEnum<["names", "signatures", "full"]>>;
|
|
853
857
|
maxMembers: z.ZodOptional<z.ZodNumber>;
|
|
854
858
|
cursor: z.ZodOptional<z.ZodString>;
|
|
855
859
|
projectPath: z.ZodOptional<z.ZodString>;
|
|
@@ -938,6 +942,7 @@ export declare const getClassMembersSchema: z.ZodObject<{
|
|
|
938
942
|
includeSynthetic: z.ZodDefault<z.ZodBoolean>;
|
|
939
943
|
includeInherited: z.ZodDefault<z.ZodBoolean>;
|
|
940
944
|
memberPattern: z.ZodOptional<z.ZodString>;
|
|
945
|
+
projection: z.ZodOptional<z.ZodEnum<["names", "signatures", "full"]>>;
|
|
941
946
|
maxMembers: z.ZodOptional<z.ZodNumber>;
|
|
942
947
|
cursor: z.ZodOptional<z.ZodString>;
|
|
943
948
|
projectPath: z.ZodOptional<z.ZodString>;
|
|
@@ -992,6 +997,7 @@ export declare const getClassMembersSchema: z.ZodObject<{
|
|
|
992
997
|
memberPattern?: string | undefined;
|
|
993
998
|
include?: ("entries" | "workspace" | "warnings" | "source" | "registry" | "preview" | "files" | "samples" | "timings" | "issues" | "recovery" | "paths" | "members" | "provenance" | "artifact" | "candidates" | "classes" | "timeline" | "descriptors" | "diff" | "matrix" | "health" | "owners" | "cacheEntries")[] | undefined;
|
|
994
999
|
gradleUserHome?: string | undefined;
|
|
1000
|
+
projection?: "full" | "names" | "signatures" | undefined;
|
|
995
1001
|
}, {
|
|
996
1002
|
className: string;
|
|
997
1003
|
target: {
|
|
@@ -1034,6 +1040,7 @@ export declare const getClassMembersSchema: z.ZodObject<{
|
|
|
1034
1040
|
include?: ("entries" | "workspace" | "warnings" | "source" | "registry" | "preview" | "files" | "samples" | "timings" | "issues" | "recovery" | "paths" | "members" | "provenance" | "artifact" | "candidates" | "classes" | "timeline" | "descriptors" | "diff" | "matrix" | "health" | "owners" | "cacheEntries")[] | undefined;
|
|
1035
1041
|
gradleUserHome?: string | undefined;
|
|
1036
1042
|
includeProvenance?: boolean | undefined;
|
|
1043
|
+
projection?: "full" | "names" | "signatures" | undefined;
|
|
1037
1044
|
includeDescriptors?: boolean | undefined;
|
|
1038
1045
|
}>;
|
|
1039
1046
|
export declare const verifyMixinTargetMemberSchema: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
|
|
@@ -1811,6 +1818,7 @@ export declare const batchClassMembersShape: {
|
|
|
1811
1818
|
concurrency: z.ZodOptional<z.ZodNumber>;
|
|
1812
1819
|
failFast: z.ZodOptional<z.ZodBoolean>;
|
|
1813
1820
|
detail: z.ZodDefault<z.ZodEnum<["summary", "standard", "full"]>>;
|
|
1821
|
+
projection: z.ZodOptional<z.ZodEnum<["names", "signatures", "full"]>>;
|
|
1814
1822
|
include: z.ZodOptional<z.ZodArray<z.ZodEnum<["warnings", "provenance", "candidates", "members", "descriptors", "source", "files", "samples", "diff", "issues", "timeline", "matrix", "entries", "workspace", "health", "recovery", "paths", "owners", "preview", "cacheEntries", "timings", "artifact", "classes", "registry"]>, "many">>;
|
|
1815
1823
|
entries: z.ZodArray<z.ZodObject<{
|
|
1816
1824
|
className: z.ZodString;
|
|
@@ -1905,6 +1913,7 @@ export declare const batchClassMembersSchema: z.ZodObject<{
|
|
|
1905
1913
|
concurrency: z.ZodOptional<z.ZodNumber>;
|
|
1906
1914
|
failFast: z.ZodOptional<z.ZodBoolean>;
|
|
1907
1915
|
detail: z.ZodDefault<z.ZodEnum<["summary", "standard", "full"]>>;
|
|
1916
|
+
projection: z.ZodOptional<z.ZodEnum<["names", "signatures", "full"]>>;
|
|
1908
1917
|
include: z.ZodOptional<z.ZodArray<z.ZodEnum<["warnings", "provenance", "candidates", "members", "descriptors", "source", "files", "samples", "diff", "issues", "timeline", "matrix", "entries", "workspace", "health", "recovery", "paths", "owners", "preview", "cacheEntries", "timings", "artifact", "classes", "registry"]>, "many">>;
|
|
1909
1918
|
entries: z.ZodArray<z.ZodObject<{
|
|
1910
1919
|
className: z.ZodString;
|
|
@@ -1967,6 +1976,7 @@ export declare const batchClassMembersSchema: z.ZodObject<{
|
|
|
1967
1976
|
sourcePriority?: "loom-first" | "maven-first" | undefined;
|
|
1968
1977
|
include?: ("entries" | "workspace" | "warnings" | "source" | "registry" | "preview" | "files" | "samples" | "timings" | "issues" | "recovery" | "paths" | "members" | "provenance" | "artifact" | "candidates" | "classes" | "timeline" | "descriptors" | "diff" | "matrix" | "health" | "owners" | "cacheEntries")[] | undefined;
|
|
1969
1978
|
gradleUserHome?: string | undefined;
|
|
1979
|
+
projection?: "full" | "names" | "signatures" | undefined;
|
|
1970
1980
|
concurrency?: number | undefined;
|
|
1971
1981
|
failFast?: boolean | undefined;
|
|
1972
1982
|
}, {
|
|
@@ -2008,6 +2018,7 @@ export declare const batchClassMembersSchema: z.ZodObject<{
|
|
|
2008
2018
|
detail?: "summary" | "standard" | "full" | undefined;
|
|
2009
2019
|
include?: ("entries" | "workspace" | "warnings" | "source" | "registry" | "preview" | "files" | "samples" | "timings" | "issues" | "recovery" | "paths" | "members" | "provenance" | "artifact" | "candidates" | "classes" | "timeline" | "descriptors" | "diff" | "matrix" | "health" | "owners" | "cacheEntries")[] | undefined;
|
|
2010
2020
|
gradleUserHome?: string | undefined;
|
|
2021
|
+
projection?: "full" | "names" | "signatures" | undefined;
|
|
2011
2022
|
concurrency?: number | undefined;
|
|
2012
2023
|
failFast?: boolean | undefined;
|
|
2013
2024
|
}>;
|
package/dist/tool-schemas.js
CHANGED
|
@@ -64,10 +64,10 @@ export const workspaceTargetSchema = z.object({
|
|
|
64
64
|
});
|
|
65
65
|
export const dependencyTargetSchema = z.object({
|
|
66
66
|
kind: z.literal("dependency"),
|
|
67
|
-
group: nonEmptyString,
|
|
68
|
-
name: nonEmptyString,
|
|
69
|
-
version: z.string().trim().min(1).optional(),
|
|
70
|
-
versionFromProject: z.boolean().optional()
|
|
67
|
+
group: nonEmptyString.describe('Maven group, e.g. "net.fabricmc.fabric-api" or "dev.architectury".'),
|
|
68
|
+
name: nonEmptyString.describe('Maven artifact name, e.g. "fabric-api" or "architectury".'),
|
|
69
|
+
version: z.string().trim().min(1).optional().describe("Explicit version; omit and set versionFromProject to resolve it from the workspace."),
|
|
70
|
+
versionFromProject: z.boolean().optional().describe("Resolve the version from the project's gradle.properties / gradle cache (requires projectPath).")
|
|
71
71
|
});
|
|
72
72
|
export const resolveArtifactTargetSchema = z.discriminatedUnion("kind", [
|
|
73
73
|
z.object({ kind: z.literal("version"), value: nonEmptyString }),
|
|
@@ -89,11 +89,14 @@ export const sourceLookupTargetSchema = z.discriminatedUnion("kind", [
|
|
|
89
89
|
dependencyTargetSchema,
|
|
90
90
|
z.object({ kind: z.literal("artifact"), artifactId: nonEmptyString })
|
|
91
91
|
]);
|
|
92
|
-
export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object, not string. e.g. {"kind":"version","value":"1.21.10"}, {"kind":"workspace"}, {"kind":"dependency","group":"
|
|
93
|
-
export const SOURCE_LOOKUP_TARGET_DESCRIPTION = 'Same shape as resolve-artifact target, plus {"kind":"artifact","artifactId":"..."} to reuse a resolved artifact. Object, not string.';
|
|
92
|
+
export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object, not string. e.g. {"kind":"version","value":"1.21.10"}, {"kind":"workspace"}, or to inspect a loader/Fabric dependency like vanilla: {"kind":"dependency","group":"net.fabricmc.fabric-api","name":"fabric-api","versionFromProject":true} (needs projectPath) or with an explicit "version".';
|
|
93
|
+
export const SOURCE_LOOKUP_TARGET_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.';
|
|
94
94
|
export const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = merged runtime discovery; loader = loader-transformed runtime jars.";
|
|
95
95
|
// Shared describe() text reused by every symbol-lookup tool so the contract reads
|
|
96
96
|
// identically on find-mapping and check-symbol-exists (and any future sibling).
|
|
97
|
+
export const MEMBER_PATTERN_DESCRIPTION = 'Case-insensitive substring filter on member names. Use "|" for OR alternatives, e.g. "getStateForPlacement|canSurvive|setPlacedBy" (each token is matched as a substring, not a regex).';
|
|
98
|
+
export const memberProjectionSchema = z.enum(["names", "signatures", "full"]);
|
|
99
|
+
export const MEMBER_PROJECTION_DESCRIPTION = 'Per-member field projection: "names" (member name only), "signatures" (name + javaSignature, no jvmDescriptor), or "full" (default; complete member shape). Use "names"/"signatures" to cut response tokens for existence/signature checks.';
|
|
97
100
|
export const SIGNATURE_MODE_DESCRIPTION = "exact: descriptor required for kind=method; name-only (default): match by owner+name only.";
|
|
98
101
|
export const NAME_MODE_DESCRIPTION = "auto (default): FQCN, or dotless name where allowed; fqcn: require FQCN.";
|
|
99
102
|
export const listVersionsShape = {
|
|
@@ -158,7 +161,8 @@ export const getClassMembersShape = {
|
|
|
158
161
|
access: memberAccessSchema.default("public"),
|
|
159
162
|
includeSynthetic: z.boolean().default(false),
|
|
160
163
|
includeInherited: z.boolean().default(false),
|
|
161
|
-
memberPattern: optionalNonEmptyString,
|
|
164
|
+
memberPattern: optionalNonEmptyString.describe(MEMBER_PATTERN_DESCRIPTION),
|
|
165
|
+
projection: memberProjectionSchema.optional().describe(MEMBER_PROJECTION_DESCRIPTION),
|
|
162
166
|
maxMembers: optionalPositiveInt.describe("default 150, max 5000. Page beyond the first 150 with cursor."),
|
|
163
167
|
cursor: optionalNonEmptyString.describe("nextCursor from the previous response."),
|
|
164
168
|
projectPath: optionalNonEmptyString,
|
|
@@ -262,7 +266,7 @@ export const batchClassMembersEntrySchema = z.object({
|
|
|
262
266
|
access: memberAccessSchema.optional(),
|
|
263
267
|
includeSynthetic: z.boolean().optional(),
|
|
264
268
|
includeInherited: z.boolean().optional(),
|
|
265
|
-
memberPattern: optionalNonEmptyString,
|
|
269
|
+
memberPattern: optionalNonEmptyString.describe(MEMBER_PATTERN_DESCRIPTION),
|
|
266
270
|
maxMembers: optionalPositiveInt
|
|
267
271
|
});
|
|
268
272
|
export const batchClassMembersShape = {
|
|
@@ -278,6 +282,7 @@ export const batchClassMembersShape = {
|
|
|
278
282
|
concurrency: z.number().int().min(1).max(8).optional(),
|
|
279
283
|
failFast: z.boolean().optional(),
|
|
280
284
|
detail: detailParam("summary"),
|
|
285
|
+
projection: memberProjectionSchema.optional().describe(MEMBER_PROJECTION_DESCRIPTION),
|
|
281
286
|
include: responseIncludeParam,
|
|
282
287
|
entries: z.array(batchClassMembersEntrySchema).min(1).max(50)
|
|
283
288
|
};
|
package/docs/tool-reference.md
CHANGED
|
@@ -67,6 +67,29 @@ Start here when you are not sure which tool to reach for. In every row, the left
|
|
|
67
67
|
| `{ kind: "workspace", scope?, strict? }` | When the caller already passes a `projectPath` and wants the tool to detect Minecraft version, compile mapping, and loader from `gradle.properties` and `build.gradle(.kts)`. | `projectPath` | Synthesised to `{ kind: "version", value: <detected> }`. Scope precedence is `target.scope` → top-level `scope` → loader-derived default (`"merged"` when a loader is detected, `"vanilla"` otherwise). When the version is not detected, raises `ERR_WORKSPACE_VERSION_UNRESOLVED` regardless of `strict`. Detected facts surface on `provenance.workspaceResolution`. |
|
|
68
68
|
| `{ kind: "dependency", group, name, version?, versionFromProject? }` | When the caller wants to resolve a Maven-coordinate dependency (e.g. `dev.architectury:architectury`) without computing the exact version themselves. | `projectPath` (unless `version` is given) | Synthesised to `{ kind: "coordinate", value: "<group>:<name>:<version>" }`. The dependency JAR is treated as non-vanilla: binary remap is suppressed. When the caller asks for a non-obfuscated mapping the resolver returns the JAR with `mappingApplied: "obfuscated"` and `qualityFlags: ["dependency-mapping-unverified"]`, plus a warning that the caller must validate symbol availability. Resolution metadata appears on `provenance.dependencyResolution`. |
|
|
69
69
|
|
|
70
|
+
### Inspecting a Fabric / loader dependency like vanilla
|
|
71
|
+
|
|
72
|
+
To read members or source of a Fabric API (or any loader/Maven dependency) class
|
|
73
|
+
the same way you read vanilla, pass a `dependency` target straight to
|
|
74
|
+
`get-class-members` / `get-class-source` — no separate lookup tool is needed:
|
|
75
|
+
|
|
76
|
+
```jsonc
|
|
77
|
+
// members of a Fabric API class, version taken from the workspace
|
|
78
|
+
{
|
|
79
|
+
"tool": "get-class-members",
|
|
80
|
+
"className": "net.fabricmc.fabric.api.event.player.UseEntityCallback",
|
|
81
|
+
"target": { "kind": "dependency", "group": "net.fabricmc.fabric-api", "name": "fabric-api", "versionFromProject": true },
|
|
82
|
+
"projectPath": "/path/to/workspace"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use an explicit `"version"` instead of `versionFromProject` when you already
|
|
87
|
+
know it. Because dependency JARs are not remapped, members come back in the
|
|
88
|
+
dependency's own namespace with `qualityFlags: ["dependency-mapping-unverified"]`;
|
|
89
|
+
treat the names as the JAR's compiled names. For repeated lookups against the
|
|
90
|
+
same dependency, call `resolve-artifact` once and reuse the returned
|
|
91
|
+
`artifactId` via `target: { kind: "artifact", artifactId }`.
|
|
92
|
+
|
|
70
93
|
Workspace detection is memoised in a process-resident `WorkspaceContextCache` (16-entry LRU, 5-minute TTL). The cache is observable through `manage-cache` with `cacheKinds: ["workspace"]`, and individual entries can be invalidated via `selector.projectPath`.
|
|
71
94
|
|
|
72
95
|
`target.kind="dependency"` resolution probes four de-duplicated `gradle.properties` keys in order — `name_version`, `camelCaseVersion`, `lastSegment(group)_name_version`, and `camelCase(lastSegment(group)_name)Version` — before falling back to the modules-2 cache layout `~/.gradle/caches/modules-2/files-2.1/<group>/<name>/`. Version tokens that contain path separators, `..`, NUL, control characters, or any character outside `[A-Za-z0-9._+-]` are rejected; in `gradle.properties` the rejection is recorded under `attempts[]` as `gradle.properties:<key>:rejected-unsafe-version` and the next key is tried. Snapshot and dev directories are excluded by default. The modules-2 fallback only resolves when exactly one valid entry remains; multiple entries raise `ERR_DEPENDENCY_VERSION_UNRESOLVED` so a global cache cannot supply a version the workspace did not declare.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhisang/minecraft-modding-mcp",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"description": "MCP server for AI-assisted Minecraft modding: inspect decompiled source, resolve Mojang/Yarn/Intermediary mappings, diff versions, analyze Fabric/Forge/NeoForge mod JARs, and validate Mixin, Access Widener, and Access Transformer files.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|