@adhisang/minecraft-modding-mcp 4.2.1 → 6.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.
Files changed (144) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +5 -4
  3. package/dist/access-transformer-parser.d.ts +2 -1
  4. package/dist/access-transformer-parser.js +10 -1
  5. package/dist/access-widener-parser.d.ts +1 -0
  6. package/dist/access-widener-parser.js +6 -3
  7. package/dist/build-suggested-call.js +31 -10
  8. package/dist/cache-registry.d.ts +8 -0
  9. package/dist/cache-registry.js +50 -32
  10. package/dist/config.d.ts +1 -0
  11. package/dist/config.js +4 -0
  12. package/dist/decompiler/vineflower.js +8 -2
  13. package/dist/entry-tools/analyze-mod-service.d.ts +24 -24
  14. package/dist/entry-tools/analyze-mod-service.js +2 -1
  15. package/dist/entry-tools/analyze-symbol-service.d.ts +57 -22
  16. package/dist/entry-tools/analyze-symbol-service.js +139 -34
  17. package/dist/entry-tools/batch-class-members-service.d.ts +3 -1
  18. package/dist/entry-tools/batch-class-members-service.js +6 -6
  19. package/dist/entry-tools/batch-class-source-service.d.ts +3 -1
  20. package/dist/entry-tools/batch-class-source-service.js +5 -6
  21. package/dist/entry-tools/batch-mappings-service.d.ts +3 -1
  22. package/dist/entry-tools/batch-mappings-service.js +4 -5
  23. package/dist/entry-tools/batch-symbol-exists-service.d.ts +3 -1
  24. package/dist/entry-tools/batch-symbol-exists-service.js +4 -5
  25. package/dist/entry-tools/compare-minecraft-service.d.ts +10 -10
  26. package/dist/entry-tools/compare-minecraft-service.js +1 -1
  27. package/dist/entry-tools/entry-tool-schema.d.ts +1 -1
  28. package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +1 -3
  29. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +4 -3
  30. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +0 -5
  31. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +0 -1
  32. package/dist/entry-tools/inspect-minecraft/handlers/file.js +26 -2
  33. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +0 -1
  34. package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +8 -0
  35. package/dist/entry-tools/inspect-minecraft/handlers/search.js +13 -2
  36. package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +1 -1
  37. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +3 -2
  38. package/dist/entry-tools/inspect-minecraft/internal.d.ts +90 -89
  39. package/dist/entry-tools/inspect-minecraft/internal.js +32 -14
  40. package/dist/entry-tools/inspect-minecraft-service.d.ts +218 -218
  41. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  42. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  43. package/dist/entry-tools/response-contract.d.ts +3 -1
  44. package/dist/entry-tools/response-contract.js +3 -2
  45. package/dist/entry-tools/validate-project/cases/mixin.js +2 -1
  46. package/dist/entry-tools/validate-project/cases/project-summary.js +5 -3
  47. package/dist/entry-tools/validate-project-service.d.ts +42 -36
  48. package/dist/entry-tools/validate-project-service.js +3 -1
  49. package/dist/entry-tools/verify-mixin-target-service.d.ts +30 -0
  50. package/dist/entry-tools/verify-mixin-target-service.js +120 -29
  51. package/dist/error-mapping.d.ts +51 -0
  52. package/dist/error-mapping.js +157 -2
  53. package/dist/index.js +147 -76
  54. package/dist/java-process.js +1 -1
  55. package/dist/json-rpc-framing.d.ts +4 -0
  56. package/dist/json-rpc-framing.js +23 -1
  57. package/dist/mapping/internal-types.d.ts +24 -0
  58. package/dist/mapping/loaders/tiny-maven.js +46 -20
  59. package/dist/mapping/lookup.d.ts +13 -2
  60. package/dist/mapping/lookup.js +60 -2
  61. package/dist/mapping/types.d.ts +6 -0
  62. package/dist/mapping-service.d.ts +26 -2
  63. package/dist/mapping-service.js +212 -55
  64. package/dist/mcp-helpers.d.ts +1 -0
  65. package/dist/mcp-helpers.js +25 -3
  66. package/dist/minecraft-explorer-service.js +24 -11
  67. package/dist/mixin/access-validators.js +33 -1
  68. package/dist/mixin/annotation-validators.js +73 -9
  69. package/dist/mixin/parsed-validator.js +3 -2
  70. package/dist/mixin-parser.js +119 -7
  71. package/dist/mod-decompile-service.d.ts +2 -0
  72. package/dist/mod-decompile-service.js +21 -3
  73. package/dist/mod-remap-service.d.ts +20 -1
  74. package/dist/mod-remap-service.js +101 -45
  75. package/dist/mojang-tiny-mapping-service.js +5 -2
  76. package/dist/nbt/java-nbt-codec.js +46 -16
  77. package/dist/nbt/json-patch.js +51 -12
  78. package/dist/nbt/typed-json.d.ts +1 -0
  79. package/dist/nbt/typed-json.js +12 -2
  80. package/dist/nbt/types.d.ts +2 -2
  81. package/dist/observability.d.ts +6 -0
  82. package/dist/observability.js +10 -0
  83. package/dist/page-cursor.d.ts +17 -0
  84. package/dist/page-cursor.js +0 -0
  85. package/dist/path-converter.js +10 -3
  86. package/dist/registry-service.d.ts +2 -0
  87. package/dist/registry-service.js +41 -2
  88. package/dist/repo-downloader.js +4 -3
  89. package/dist/resources.js +45 -9
  90. package/dist/response-utils.d.ts +29 -4
  91. package/dist/response-utils.js +95 -5
  92. package/dist/source/access-validate.js +12 -2
  93. package/dist/source/artifact-resolver.js +2 -2
  94. package/dist/source/class-source/members-builder.d.ts +44 -1
  95. package/dist/source/class-source/members-builder.js +51 -4
  96. package/dist/source/class-source/snippet-builder.d.ts +13 -0
  97. package/dist/source/class-source/snippet-builder.js +54 -4
  98. package/dist/source/class-source-helpers.d.ts +4 -4
  99. package/dist/source/class-source-helpers.js +77 -20
  100. package/dist/source/class-source.d.ts +19 -0
  101. package/dist/source/class-source.js +144 -40
  102. package/dist/source/file-access.js +3 -2
  103. package/dist/source/indexer.js +29 -9
  104. package/dist/source/lifecycle/mapping-helpers.js +28 -3
  105. package/dist/source/lifecycle/runtime-check.js +20 -6
  106. package/dist/source/search.d.ts +1 -1
  107. package/dist/source/search.js +117 -30
  108. package/dist/source/validate-mixin/pipeline/resolve.js +23 -3
  109. package/dist/source/validate-mixin.d.ts +2 -1
  110. package/dist/source/validate-mixin.js +45 -4
  111. package/dist/source/workspace-target.js +17 -10
  112. package/dist/source-jar-reader.d.ts +54 -1
  113. package/dist/source-jar-reader.js +121 -10
  114. package/dist/source-resolver.js +2 -2
  115. package/dist/source-service.d.ts +28 -7
  116. package/dist/source-service.js +9 -1
  117. package/dist/stdio-supervisor.d.ts +2 -2
  118. package/dist/stdio-supervisor.js +29 -9
  119. package/dist/storage/db.js +24 -1
  120. package/dist/storage/files-repo.d.ts +15 -0
  121. package/dist/storage/files-repo.js +67 -37
  122. package/dist/storage/symbols-repo.d.ts +15 -0
  123. package/dist/storage/symbols-repo.js +53 -19
  124. package/dist/symbols/symbol-extractor.js +35 -6
  125. package/dist/text-truncate.d.ts +7 -0
  126. package/dist/text-truncate.js +21 -0
  127. package/dist/tiny-remapper-resolver.js +10 -0
  128. package/dist/tool-contract-manifest.js +2 -2
  129. package/dist/tool-execution-gate.js +12 -1
  130. package/dist/tool-guidance.d.ts +6 -2
  131. package/dist/tool-guidance.js +63 -13
  132. package/dist/tool-schemas.d.ts +561 -496
  133. package/dist/tool-schemas.js +175 -139
  134. package/dist/types.d.ts +1 -0
  135. package/dist/version-diff-service.js +5 -0
  136. package/dist/version-service.d.ts +3 -0
  137. package/dist/version-service.js +18 -2
  138. package/dist/warning-details.d.ts +30 -0
  139. package/dist/warning-details.js +80 -0
  140. package/dist/workspace-mapping-service.js +9 -0
  141. package/docs/README-ja.md +2 -2
  142. package/docs/examples.md +26 -2
  143. package/docs/tool-reference.md +22 -17
  144. package/package.json +1 -1
@@ -1,5 +1,19 @@
1
- import { isAbsolute as pathIsAbsolute, resolve as pathResolve } from "node:path";
1
+ import { resolve as pathResolve } from "node:path";
2
2
  import { z } from "zod";
3
+ import { DETAIL_LEVELS, CANONICAL_INCLUDE_GROUPS } from "./entry-tools/response-contract.js";
4
+ // Shared response-shape controls for the expert + batch tools (replacing the old
5
+ // per-tool `compact` boolean). detail: summary|standard|full + include[] mirrors the
6
+ // entry-tool contract. Defaults are per-tool (see DEFAULT_DETAIL_BY_TOOL in response-utils):
7
+ // resolution/mapping tools + batch default "summary"; source/file tools default "standard".
8
+ const DETAIL_DESCRIPTION = "summary = terse (drops diagnostics/empties, slims candidates); standard = keeps fields, drops heavy diagnostics; full = everything.";
9
+ const RESPONSE_INCLUDE_DESCRIPTION = 'Field groups to include regardless of detail, e.g. ["provenance"].';
10
+ function detailParam(defaultLevel) {
11
+ return z.enum(DETAIL_LEVELS).default(defaultLevel).describe(DETAIL_DESCRIPTION);
12
+ }
13
+ const responseIncludeParam = z
14
+ .array(z.enum(CANONICAL_INCLUDE_GROUPS))
15
+ .optional()
16
+ .describe(RESPONSE_INCLUDE_DESCRIPTION);
3
17
  export const SOURCE_MAPPINGS = ["obfuscated", "mojang", "intermediary", "yarn"];
4
18
  export const SOURCE_PRIORITIES = ["loom-first", "maven-first"];
5
19
  export const TARGET_KINDS = ["version", "jar", "coordinate"];
@@ -16,7 +30,7 @@ export const ENCODE_COMPRESSIONS = ["none", "gzip"];
16
30
  export const nonEmptyString = z.string().trim().min(1);
17
31
  export const optionalNonEmptyString = z.string().trim().min(1).optional();
18
32
  export const optionalPositiveInt = z.number().int().positive().optional();
19
- export const gradleUserHomeSchema = optionalNonEmptyString.describe("Gradle User Home to use for Loom/Gradle cache lookups instead of the MCP process GRADLE_USER_HOME.");
33
+ export const gradleUserHomeSchema = optionalNonEmptyString.describe("Gradle user home for Loom cache lookups (overrides GRADLE_USER_HOME).");
20
34
  // Optional descriptor: "" and whitespace-only strings are normalized to undefined so that
21
35
  // tools with signatureMode="name-only" can accept "caller omitted descriptor" inputs whether
22
36
  // the caller passed an empty string or omitted the field entirely. Malformed descriptors are
@@ -62,32 +76,26 @@ export const resolveArtifactTargetSchema = z.discriminatedUnion("kind", [
62
76
  workspaceTargetSchema,
63
77
  dependencyTargetSchema
64
78
  ]);
65
- export const sourceLookupTargetSchema = z.union([
66
- z.object({
67
- type: z.literal("artifact"),
68
- artifactId: nonEmptyString
69
- }),
70
- z.object({ type: z.literal("resolve"), kind: z.literal("version"), value: nonEmptyString }),
71
- z.object({ type: z.literal("resolve"), kind: z.literal("jar"), value: nonEmptyString }),
72
- z.object({ type: z.literal("resolve"), kind: z.literal("coordinate"), value: nonEmptyString }),
73
- z.object({
74
- type: z.literal("resolve"),
75
- kind: z.literal("workspace"),
76
- scope: artifactScopeSchema.optional(),
77
- strict: z.boolean().optional()
78
- }),
79
- z.object({
80
- type: z.literal("resolve"),
81
- kind: z.literal("dependency"),
82
- group: nonEmptyString,
83
- name: nonEmptyString,
84
- version: z.string().trim().min(1).optional(),
85
- versionFromProject: z.boolean().optional()
86
- })
79
+ // Extended target schema for the source-lookup tools (get-class-source / get-class-members):
80
+ // the same kind-based shape as resolveArtifactTargetSchema, PLUS a `kind:"artifact"` variant
81
+ // that short-circuits resolution by reusing an already-resolved artifactId. The shared
82
+ // resolveArtifactTargetSchema is intentionally NOT widened — the artifact kind has no
83
+ // resolution meaning for resolve-artifact / verify-mixin-target / the batch tools.
84
+ export const sourceLookupTargetSchema = z.discriminatedUnion("kind", [
85
+ z.object({ kind: z.literal("version"), value: nonEmptyString }),
86
+ z.object({ kind: z.literal("jar"), value: nonEmptyString }),
87
+ z.object({ kind: z.literal("coordinate"), value: nonEmptyString }),
88
+ workspaceTargetSchema,
89
+ dependencyTargetSchema,
90
+ z.object({ kind: z.literal("artifact"), artifactId: nonEmptyString })
87
91
  ]);
88
- export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object with kind. Examples: {"kind":"version","value":"1.21.10"}, {"kind":"workspace"} (uses projectPath), or {"kind":"dependency","group":"dev.architectury","name":"architectury"}. Must be an object, not a string.';
89
- export const SOURCE_LOOKUP_TARGET_DESCRIPTION = 'Object: {"type":"resolve","kind":"version","value":"1.21.10"} or {"type":"resolve","kind":"workspace"} or {"type":"resolve","kind":"dependency","group":"...","name":"..."} or {"type":"artifact","artifactId":"..."}. Must be an object, not a string.';
90
- export 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.";
92
+ export const RESOLVE_ARTIFACT_TARGET_DESCRIPTION = 'Object, not string. e.g. {"kind":"version","value":"1.21.10"}, {"kind":"workspace"}, {"kind":"dependency","group":"g","name":"n"}.';
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.';
94
+ export const SOURCE_SCOPE_DESCRIPTION = "vanilla = Mojang client jar only; merged = merged runtime discovery; loader = loader-transformed runtime jars.";
95
+ // Shared describe() text reused by every symbol-lookup tool so the contract reads
96
+ // identically on find-mapping and check-symbol-exists (and any future sibling).
97
+ export const SIGNATURE_MODE_DESCRIPTION = "exact: descriptor required for kind=method; name-only (default): match by owner+name only.";
98
+ export const NAME_MODE_DESCRIPTION = "auto (default): FQCN, or dotless name where allowed; fqcn: require FQCN.";
91
99
  export const listVersionsShape = {
92
100
  includeSnapshots: z.boolean().default(false),
93
101
  limit: optionalPositiveInt.default(20).describe("max 200")
@@ -95,37 +103,38 @@ export const listVersionsShape = {
95
103
  export const listVersionsSchema = z.object(listVersionsShape);
96
104
  export const resolveArtifactShape = {
97
105
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
98
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
99
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
106
+ mapping: sourceMappingSchema.optional(),
107
+ sourcePriority: mappingSourcePrioritySchema.optional(),
100
108
  allowDecompile: z.boolean().default(true),
101
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
109
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
102
110
  gradleUserHome: gradleUserHomeSchema,
103
111
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
104
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
105
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
106
- compact: z.boolean().default(true).describe("Return minimal fields (artifactId, origin, isDecompiled, version, requestedMapping, mappingApplied, qualityFlags). "
107
- + "Omit provenance, artifactContents, sampleEntries, adjacentSourceCandidates, binaryJarPath, coordinate, repoUrl, resolvedSourceJarPath. "
108
- + "Enabled by default; set to false for full output.")
112
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
113
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
114
+ detail: detailParam("summary"),
115
+ include: responseIncludeParam
109
116
  };
110
117
  export const resolveArtifactSchema = z.object(resolveArtifactShape);
111
118
  export const getClassSourceShape = {
112
119
  className: nonEmptyString,
113
120
  mode: sourceModeSchema.default("metadata").describe("metadata = symbol outline only; snippet = source with default maxLines=200; full = entire source"),
114
121
  target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
115
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
116
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
122
+ mapping: sourceMappingSchema.optional(),
123
+ sourcePriority: mappingSourcePrioritySchema.optional(),
117
124
  allowDecompile: z.boolean().default(true),
118
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
125
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
119
126
  gradleUserHome: gradleUserHomeSchema,
120
127
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
121
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
122
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
128
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
129
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
123
130
  startLine: optionalPositiveInt,
124
131
  endLine: optionalPositiveInt,
125
132
  maxLines: optionalPositiveInt,
126
133
  maxChars: optionalPositiveInt.describe("Hard character limit on sourceText; truncates if exceeded"),
127
134
  outputFile: optionalNonEmptyString.describe("Write source to this file path and return metadata-only response"),
128
- compact: z.boolean().default(false).describe("When true, strip debug metadata (provenance, artifactContents, qualityFlags) and empty fields from the response. Default false.")
135
+ detail: detailParam("standard"),
136
+ include: responseIncludeParam,
137
+ includeProvenance: z.boolean().default(false).describe('Alias for include:["provenance"] (diagnostic metadata). Default false.')
129
138
  };
130
139
  export const getClassSourceSchema = z
131
140
  .object(getClassSourceShape)
@@ -143,46 +152,51 @@ export const getClassSourceSchema = z
143
152
  export const getClassMembersShape = {
144
153
  className: nonEmptyString,
145
154
  target: sourceLookupTargetSchema.describe(SOURCE_LOOKUP_TARGET_DESCRIPTION),
146
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
147
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
155
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
156
+ sourcePriority: mappingSourcePrioritySchema.optional(),
148
157
  allowDecompile: z.boolean().default(true),
149
- access: memberAccessSchema.default("public").describe("public | all"),
158
+ access: memberAccessSchema.default("public"),
150
159
  includeSynthetic: z.boolean().default(false),
151
160
  includeInherited: z.boolean().default(false),
152
161
  memberPattern: optionalNonEmptyString,
153
- maxMembers: optionalPositiveInt.describe("default 500, max 5000"),
162
+ maxMembers: optionalPositiveInt.describe("default 150, max 5000. Page beyond the first 150 with cursor."),
163
+ cursor: optionalNonEmptyString.describe("nextCursor from the previous response."),
154
164
  projectPath: optionalNonEmptyString,
155
165
  gradleUserHome: gradleUserHomeSchema,
156
166
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
157
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
158
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false."),
159
- compact: z.boolean().default(false).describe("When true, strip debug metadata (provenance, artifactContents, qualityFlags, context) and empty fields from the response. Default false.")
167
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override version"),
168
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)"),
169
+ detail: detailParam("standard"),
170
+ include: responseIncludeParam,
171
+ includeProvenance: z.boolean().default(false).describe('Alias for include:["provenance"] (diagnostic metadata). Default false.'),
172
+ includeDescriptors: z.boolean().default(false).describe('Alias for include:["descriptors"]: also emit jvmDescriptor on FIELD members (method/constructor descriptors are always present). Default false.')
160
173
  };
161
174
  export const getClassMembersSchema = z.object(getClassMembersShape);
162
175
  export const verifyMixinTargetMemberSchema = z.discriminatedUnion("kind", [
163
176
  z.object({
164
177
  kind: z.literal("method"),
165
178
  name: nonEmptyString,
166
- descriptor: z.string().trim().min(1).optional()
179
+ descriptor: optionalDescriptorString.describe('Optional JVM method descriptor, e.g. "()V". Empty/whitespace strings are treated as omitted.')
167
180
  }),
168
181
  z.object({
169
182
  kind: z.literal("field"),
170
183
  name: nonEmptyString,
171
- descriptor: z.string().trim().min(1).optional()
184
+ descriptor: optionalDescriptorString.describe('Optional JVM field descriptor, e.g. "I". Empty/whitespace strings are treated as omitted.')
172
185
  })
173
186
  ]);
174
187
  export const verifyMixinTargetShape = {
175
- owner: nonEmptyString.describe("Fully-qualified class name of the target owner (e.g. net.minecraft.world.entity.LivingEntity)."),
176
- member: verifyMixinTargetMemberSchema.describe('Member to verify. Object with kind. Examples: {"kind":"method","name":"tick","descriptor":"()V"} or {"kind":"field","name":"airSupply"}.'),
177
- mixinMemberName: optionalNonEmptyString.describe("Optional caller-authored mixin field/method name. Drives @Accessor (getXxx/setXxx) and @Invoker (invokeXxx/callXxx) advice when the target is private."),
178
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
179
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
188
+ owner: nonEmptyString.describe("Fully-qualified target owner class name."),
189
+ member: verifyMixinTargetMemberSchema.describe('e.g. {"kind":"method","name":"tick","descriptor":"()V"} or {"kind":"field","name":"airSupply"}.'),
190
+ mixinMemberName: optionalNonEmptyString.describe("Caller-authored mixin member name; drives @Accessor/@Invoker advice when the target is private."),
191
+ mapping: sourceMappingSchema.optional(),
192
+ autoRemap: z.boolean().optional().describe("Translate owner+member via find-mapping when mapping differs from the artifact namespace (requires a version-based target)."),
193
+ sourcePriority: mappingSourcePrioritySchema.optional(),
180
194
  projectPath: optionalNonEmptyString.describe("Workspace root path for target.kind=workspace and Loom cache assistance."),
181
195
  gradleUserHome: gradleUserHomeSchema,
182
196
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
183
197
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
184
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override target.value"),
185
- strictVersion: z.boolean().optional().describe("When true, reject version-approximated results instead of returning them. Default false.")
198
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override target.value"),
199
+ strictVersion: z.boolean().optional().describe("Reject version-approximated results (default false)")
186
200
  };
187
201
  export const verifyMixinTargetSchema = z.object(verifyMixinTargetShape);
188
202
  export const batchSymbolKindSchema = z.enum(["class", "field", "method"]);
@@ -197,7 +211,7 @@ export const batchClassSourceEntrySchema = z.object({
197
211
  });
198
212
  export const batchClassSourceShape = {
199
213
  target: resolveArtifactTargetSchema.describe(RESOLVE_ARTIFACT_TARGET_DESCRIPTION),
200
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
214
+ mapping: sourceMappingSchema.optional(),
201
215
  sourcePriority: mappingSourcePrioritySchema.optional(),
202
216
  allowDecompile: z.boolean().optional(),
203
217
  projectPath: optionalNonEmptyString,
@@ -207,7 +221,8 @@ export const batchClassSourceShape = {
207
221
  strictVersion: z.boolean().optional(),
208
222
  concurrency: z.number().int().min(1).max(8).optional().describe("1..8, default 4"),
209
223
  failFast: z.boolean().optional().describe("default false"),
210
- compact: z.boolean().optional().describe("default true"),
224
+ detail: detailParam("summary"),
225
+ include: responseIncludeParam,
211
226
  entries: z
212
227
  .array(batchClassSourceEntrySchema)
213
228
  .min(1)
@@ -218,8 +233,8 @@ export const batchClassSourceSchema = z.object(batchClassSourceShape).superRefin
218
233
  // Per-entry `outputFile` is forwarded into the concurrently-dispatched
219
234
  // `getClassSource` calls; two entries resolving to the same physical file
220
235
  // would race on `writeFile`. Normalize via `path.resolve` so aliases like
221
- // `out.java` / `./out.java` / `dir/../out.java` collide as expected,
222
- // matching the writer's `isAbsolute(p) ? p : resolvePath(p)` rule.
236
+ // `out.java` / `./out.java` / `dir/../out.java` / `/tmp/dir/../out.java`
237
+ // collide as expected, covering relative and absolute spellings alike.
223
238
  const seen = new Map();
224
239
  for (let i = 0; i < value.entries.length; i += 1) {
225
240
  const entry = value.entries[i];
@@ -228,7 +243,7 @@ export const batchClassSourceSchema = z.object(batchClassSourceShape).superRefin
228
243
  const trimmed = entry.outputFile.trim();
229
244
  if (trimmed.length === 0)
230
245
  continue;
231
- const canonical = pathIsAbsolute(trimmed) ? trimmed : pathResolve(trimmed);
246
+ const canonical = pathResolve(trimmed);
232
247
  const previous = seen.get(canonical);
233
248
  if (previous !== undefined) {
234
249
  ctx.addIssue({
@@ -262,14 +277,15 @@ export const batchClassMembersShape = {
262
277
  strictVersion: z.boolean().optional(),
263
278
  concurrency: z.number().int().min(1).max(8).optional(),
264
279
  failFast: z.boolean().optional(),
265
- compact: z.boolean().optional(),
280
+ detail: detailParam("summary"),
281
+ include: responseIncludeParam,
266
282
  entries: z.array(batchClassMembersEntrySchema).min(1).max(50)
267
283
  };
268
284
  export const batchClassMembersSchema = z.object(batchClassMembersShape);
269
285
  export const batchSymbolExistsTargetSchema = z.discriminatedUnion("kind", [
270
286
  z.object({ kind: z.literal("version"), value: nonEmptyString }),
271
287
  workspaceTargetSchema
272
- ]).describe('Object with kind. Only kind="version" or kind="workspace" is accepted; dependency/jar/coordinate targets carry library versions, not Minecraft versions, and would corrupt the mapping query.');
288
+ ]).describe('Only kind="version" or kind="workspace"; other kinds carry library versions, not MC versions.');
273
289
  export const batchSymbolExistsEntrySchema = z.object({
274
290
  kind: batchSymbolKindSchema,
275
291
  name: nonEmptyString,
@@ -291,7 +307,8 @@ export const batchSymbolExistsShape = {
291
307
  strictVersion: z.boolean().optional(),
292
308
  concurrency: z.number().int().min(1).max(8).optional(),
293
309
  failFast: z.boolean().optional(),
294
- compact: z.boolean().optional(),
310
+ detail: detailParam("summary"),
311
+ include: responseIncludeParam,
295
312
  entries: z.array(batchSymbolExistsEntrySchema).min(1).max(50)
296
313
  };
297
314
  export const batchSymbolExistsSchema = z.object(batchSymbolExistsShape);
@@ -315,31 +332,33 @@ export const batchMappingsEntrySchema = z
315
332
  })
316
333
  .strict();
317
334
  export const batchMappingsShape = {
318
- version: nonEmptyString.describe("Minecraft version shared by every entry. Per-entry version is rejected; this batch shape is intentionally single-version."),
335
+ version: nonEmptyString.describe("Minecraft version shared by every entry (single-version batch)."),
319
336
  sourcePriority: mappingSourcePrioritySchema.optional(),
320
337
  projectPath: optionalNonEmptyString,
321
338
  gradleUserHome: gradleUserHomeSchema,
322
339
  concurrency: z.number().int().min(1).max(8).optional(),
323
340
  failFast: z.boolean().optional(),
324
- compact: z.boolean().optional(),
341
+ detail: detailParam("summary"),
342
+ include: responseIncludeParam,
325
343
  entries: z.array(batchMappingsEntrySchema).min(1).max(50)
326
344
  };
327
345
  export const batchMappingsSchema = z.object(batchMappingsShape);
328
346
  export const searchClassSourceShape = {
329
347
  artifactId: nonEmptyString,
330
348
  query: nonEmptyString,
331
- intent: searchIntentSchema.optional().describe("symbol | text | path"),
332
- match: searchMatchSchema.optional().describe("exact | prefix | contains | regex"),
349
+ intent: searchIntentSchema.optional(),
350
+ match: searchMatchSchema.optional(),
333
351
  packagePrefix: optionalNonEmptyString,
334
352
  fileGlob: optionalNonEmptyString,
335
- symbolKind: searchSymbolKindSchema.optional().describe("class | interface | enum | record | method | field"),
336
- 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"),
353
+ symbolKind: searchSymbolKindSchema.optional(),
354
+ queryMode: z.enum(["auto", "token", "literal"]).default("auto").describe("auto: indexed search incl. separator queries like foo.bar; token: indexed-only; literal: substring scan only"),
337
355
  limit: optionalPositiveInt.default(20),
338
356
  cursor: optionalNonEmptyString,
339
- 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)."),
340
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first. Used only when queryNamespace triggers translation."),
357
+ queryNamespace: sourceMappingSchema.optional().describe("Query namespace; symbol-intent FQCN queries are translated via find-mapping first. Ignored for text/path intents."),
358
+ sourcePriority: mappingSourcePrioritySchema.optional().describe("Used only when queryNamespace triggers translation."),
341
359
  gradleUserHome: gradleUserHomeSchema,
342
- compact: z.boolean().default(false).describe("When true, strip the artifactContents summary and empty fields from the response. Default false.")
360
+ detail: detailParam("standard"),
361
+ include: responseIncludeParam
343
362
  };
344
363
  export const searchClassSourceSchema = z.object(searchClassSourceShape).superRefine((value, ctx) => {
345
364
  if (value.symbolKind && value.intent && value.intent !== "symbol") {
@@ -361,7 +380,8 @@ export const listArtifactFilesShape = {
361
380
  prefix: optionalNonEmptyString,
362
381
  limit: optionalPositiveInt,
363
382
  cursor: optionalNonEmptyString,
364
- compact: z.boolean().default(false).describe("When true, strip the artifactContents summary and empty fields from the response. Default false.")
383
+ detail: detailParam("standard"),
384
+ include: responseIncludeParam
365
385
  };
366
386
  export const listArtifactFilesSchema = z.object(listArtifactFilesShape);
367
387
  export const traceSymbolLifecycleShape = {
@@ -369,8 +389,8 @@ export const traceSymbolLifecycleShape = {
369
389
  descriptor: optionalDescriptorString.describe('optional JVM descriptor, e.g. "(I)V". Empty strings are treated as omitted.'),
370
390
  fromVersion: optionalNonEmptyString,
371
391
  toVersion: optionalNonEmptyString,
372
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
373
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
392
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
393
+ sourcePriority: mappingSourcePrioritySchema.optional(),
374
394
  gradleUserHome: gradleUserHomeSchema,
375
395
  includeSnapshots: z.boolean().default(false),
376
396
  maxVersions: optionalPositiveInt.default(120).describe("max 400"),
@@ -381,24 +401,24 @@ export const diffClassSignaturesShape = {
381
401
  className: nonEmptyString,
382
402
  fromVersion: nonEmptyString,
383
403
  toVersion: nonEmptyString,
384
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn (default obfuscated)"),
385
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
404
+ mapping: sourceMappingSchema.optional().describe("default obfuscated"),
405
+ sourcePriority: mappingSourcePrioritySchema.optional(),
386
406
  gradleUserHome: gradleUserHomeSchema,
387
407
  includeFullDiff: z.boolean().default(true).describe("When false, omit from/to snapshots from modified entries and keep only key+changed")
388
408
  };
389
409
  export const diffClassSignaturesSchema = z.object(diffClassSignaturesShape);
390
410
  export const findMappingShape = {
391
411
  version: nonEmptyString,
392
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
412
+ kind: workspaceSymbolKindSchema,
393
413
  name: nonEmptyString,
394
414
  owner: optionalNonEmptyString,
395
- descriptor: optionalDescriptorString.describe("JVM descriptor. Optional when signatureMode='name-only' (default). Empty strings are treated as omitted."),
396
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
397
- targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
398
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
415
+ descriptor: optionalDescriptorString.describe("JVM descriptor; optional when signatureMode='name-only'. Empty = omitted."),
416
+ sourceMapping: sourceMappingSchema,
417
+ targetMapping: sourceMappingSchema,
418
+ sourcePriority: mappingSourcePrioritySchema.optional(),
399
419
  gradleUserHome: gradleUserHomeSchema,
400
- signatureMode: z.enum(["exact", "name-only"]).default("name-only")
401
- .describe("exact: descriptor required for kind=method; name-only (default): match by owner+name only"),
420
+ nameMode: classNameModeSchema.default("auto").describe(NAME_MODE_DESCRIPTION),
421
+ signatureMode: z.enum(["exact", "name-only"]).default("name-only").describe(SIGNATURE_MODE_DESCRIPTION),
402
422
  disambiguation: z
403
423
  .object({
404
424
  ownerHint: optionalNonEmptyString,
@@ -406,10 +426,9 @@ export const findMappingShape = {
406
426
  })
407
427
  .partial()
408
428
  .optional(),
409
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
410
- compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
411
- + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
412
- + "Enabled by default; set to false for full output.")
429
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
430
+ detail: detailParam("summary"),
431
+ include: responseIncludeParam
413
432
  };
414
433
  export const findMappingSchema = z.object(findMappingShape).superRefine((value, ctx) => {
415
434
  if (value.kind === "class") {
@@ -427,7 +446,7 @@ export const findMappingSchema = z.object(findMappingShape).superRefine((value,
427
446
  path: ["descriptor"]
428
447
  });
429
448
  }
430
- if (value.sourceMapping !== "obfuscated" && !value.name.includes(".")) {
449
+ if (value.nameMode !== "auto" && !value.name.includes(".")) {
431
450
  ctx.addIssue({
432
451
  code: z.ZodIssueCode.custom,
433
452
  message: "name must be fully-qualified class name when kind=class.",
@@ -468,19 +487,22 @@ export const findMappingSchema = z.object(findMappingShape).superRefine((value,
468
487
  });
469
488
  }
470
489
  });
490
+ // Strict shortcut for find-mapping(kind=method, signatureMode=exact): identical inputs,
491
+ // but requires a COMPLETE descriptor projection and returns mapping_unavailable when the
492
+ // descriptor's class references cannot all be projected (find-mapping's exact mode is more
493
+ // lenient there). Prefer find-mapping unless you need that strict-completeness guarantee.
471
494
  export const resolveMethodMappingExactShape = {
472
495
  version: nonEmptyString,
473
496
  name: nonEmptyString,
474
497
  owner: nonEmptyString,
475
498
  descriptor: nonEmptyString.describe("required JVM descriptor"),
476
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
477
- targetMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
478
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
499
+ sourceMapping: sourceMappingSchema,
500
+ targetMapping: sourceMappingSchema,
501
+ sourcePriority: mappingSourcePrioritySchema.optional(),
479
502
  gradleUserHome: gradleUserHomeSchema,
480
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
481
- compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
482
- + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
483
- + "Enabled by default; set to false for full output.")
503
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
504
+ detail: detailParam("summary"),
505
+ include: responseIncludeParam
484
506
  };
485
507
  export const resolveMethodMappingExactSchema = z
486
508
  .object(resolveMethodMappingExactShape)
@@ -516,27 +538,27 @@ export const classApiKindsSchema = z.string().superRefine((value, ctx) => {
516
538
  export const getClassApiMatrixShape = {
517
539
  version: nonEmptyString,
518
540
  className: nonEmptyString,
519
- classNameMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
541
+ classNameMapping: sourceMappingSchema,
520
542
  includeKinds: classApiKindsSchema.optional().describe("comma-separated: class,field,method"),
521
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
543
+ sourcePriority: mappingSourcePrioritySchema.optional(),
522
544
  gradleUserHome: gradleUserHomeSchema,
523
- maxRows: optionalPositiveInt.describe("Limit returned rows (max 5000)")
545
+ maxRows: optionalPositiveInt.describe("Limit returned rows (max 5000)"),
546
+ cursor: optionalNonEmptyString.describe("nextCursor from the previous response.")
524
547
  };
525
548
  export const getClassApiMatrixSchema = z.object(getClassApiMatrixShape);
526
549
  export const resolveWorkspaceSymbolShape = {
527
550
  projectPath: nonEmptyString,
528
551
  version: nonEmptyString,
529
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
552
+ kind: workspaceSymbolKindSchema,
530
553
  name: nonEmptyString,
531
554
  owner: optionalNonEmptyString,
532
555
  descriptor: optionalDescriptorString.describe("JVM descriptor. Empty strings are treated as omitted."),
533
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
534
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
556
+ sourceMapping: sourceMappingSchema,
557
+ sourcePriority: mappingSourcePrioritySchema.optional(),
535
558
  gradleUserHome: gradleUserHomeSchema,
536
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates for field/method lookups (default 5, max 200). Raise when you need the full candidate list."),
537
- compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
538
- + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
539
- + "Enabled by default; set to false for full output.")
559
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200 (field/method lookups)"),
560
+ detail: detailParam("summary"),
561
+ include: responseIncludeParam
540
562
  };
541
563
  export const resolveWorkspaceSymbolSchema = z
542
564
  .object(resolveWorkspaceSymbolShape)
@@ -599,20 +621,18 @@ export const resolveWorkspaceSymbolSchema = z
599
621
  });
600
622
  export const checkSymbolExistsShape = {
601
623
  version: nonEmptyString,
602
- kind: workspaceSymbolKindSchema.describe("class | field | method"),
624
+ kind: workspaceSymbolKindSchema,
603
625
  owner: optionalNonEmptyString,
604
626
  name: nonEmptyString,
605
- descriptor: optionalDescriptorString.describe("required for kind=method unless signatureMode=name-only. Empty strings are treated as omitted."),
606
- sourceMapping: sourceMappingSchema.describe("obfuscated | mojang | intermediary | yarn"),
607
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
627
+ descriptor: optionalDescriptorString.describe("JVM descriptor; optional when signatureMode='name-only'. Empty = omitted."),
628
+ sourceMapping: sourceMappingSchema,
629
+ sourcePriority: mappingSourcePrioritySchema.optional(),
608
630
  gradleUserHome: gradleUserHomeSchema,
609
- nameMode: classNameModeSchema.default("fqcn").describe("fqcn | auto"),
610
- signatureMode: z.enum(["exact", "name-only"]).default("exact")
611
- .describe("exact: require descriptor for methods; name-only: match by owner+name only"),
612
- maxCandidates: optionalPositiveInt.default(5).describe("Limit returned candidates (default 5, max 200). Raise when you need the full candidate list."),
613
- compact: z.boolean().default(true).describe("Omit top-level empty arrays, null/undefined values, and empty objects from the response. "
614
- + "Also omit redundant candidates array for single full-confidence exact-match resolutions. "
615
- + "Enabled by default; set to false for full output.")
631
+ nameMode: classNameModeSchema.default("auto").describe(NAME_MODE_DESCRIPTION),
632
+ signatureMode: z.enum(["exact", "name-only"]).default("name-only").describe(SIGNATURE_MODE_DESCRIPTION),
633
+ maxCandidates: optionalPositiveInt.default(5).describe("default 5, max 200"),
634
+ detail: detailParam("summary"),
635
+ include: responseIncludeParam
616
636
  };
617
637
  export const checkSymbolExistsSchema = z.object(checkSymbolExistsShape).superRefine((value, ctx) => {
618
638
  if (value.kind === "class") {
@@ -673,7 +693,7 @@ export const checkSymbolExistsSchema = z.object(checkSymbolExistsShape).superRef
673
693
  });
674
694
  export const nbtToJsonShape = {
675
695
  nbtBase64: nonEmptyString,
676
- compression: decodeCompressionSchema.default("auto").describe("none | gzip | auto")
696
+ compression: decodeCompressionSchema.default("auto")
677
697
  };
678
698
  export const nbtToJsonSchema = z.object(nbtToJsonShape);
679
699
  const nbtPatchOperationSchema = z
@@ -690,7 +710,7 @@ export const nbtApplyJsonPatchShape = {
690
710
  export const nbtApplyJsonPatchSchema = z.object(nbtApplyJsonPatchShape);
691
711
  export const jsonToNbtShape = {
692
712
  typedJson: z.unknown(),
693
- compression: encodeCompressionSchema.default("none").describe("none | gzip")
713
+ compression: encodeCompressionSchema.default("none")
694
714
  };
695
715
  export const jsonToNbtSchema = z.object(jsonToNbtShape);
696
716
  export const indexArtifactShape = {
@@ -720,16 +740,16 @@ export const validateMixinShape = {
720
740
  mode: z.literal("project"),
721
741
  path: nonEmptyString.describe("Workspace root path used to discover *.mixins.json files automatically")
722
742
  })
723
- ]).describe("One of { mode: 'inline', source }, { mode: 'path', path }, { mode: 'paths', paths[] }, { mode: 'config', configPaths[] }, or { mode: 'project', path }."),
743
+ ]).describe("mode = inline | path | paths | config | project"),
724
744
  sourceRoots: z.array(z.string().min(1)).optional()
725
- .describe("Array of source roots for multi-module projects (e.g. ['common/src/main/java', 'neoforge/src/main/java'])"),
726
- version: nonEmptyString.describe("Minecraft version"),
727
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
728
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
745
+ .describe("Source roots for multi-module projects (e.g. ['common/src/main/java'])"),
746
+ version: optionalNonEmptyString.describe("Minecraft version. Optional when input.mode='project' or preferProjectVersion=true with projectPath; required otherwise."),
747
+ mapping: sourceMappingSchema.optional(),
748
+ sourcePriority: mappingSourcePrioritySchema.optional(),
729
749
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
730
- projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted source resolution"),
750
+ projectPath: optionalNonEmptyString.describe("Workspace root for Loom cache-assisted resolution"),
731
751
  gradleUserHome: gradleUserHomeSchema,
732
- preferProjectVersion: z.boolean().optional().describe("When true, detect MC version from gradle.properties and override version"),
752
+ preferProjectVersion: z.boolean().optional().describe("Detect MC version from gradle.properties and override version"),
733
753
  minSeverity: z.enum(["error", "warning", "all"]).default("all")
734
754
  .describe("'error'=errors only, 'warning'=errors+warnings, 'all'=everything"),
735
755
  hideUncertain: z.boolean().default(false)
@@ -740,8 +760,8 @@ export const validateMixinShape = {
740
760
  .describe("'full'=all warnings; 'aggregated'=group warnings by category with counts and samples. Single validation uses the provided value as-is; batch validation defaults to 'aggregated'"),
741
761
  preferProjectMapping: z.boolean().default(false)
742
762
  .describe("When true, auto-detect mapping from project config even if mapping is explicitly provided"),
743
- reportMode: z.enum(["compact", "full", "summary-first"]).default("full")
744
- .describe("'compact' omits heavy per-result detail, 'summary-first' hoists shared provenance/warnings/incomplete reasons, 'full'=everything"),
763
+ reportMode: z.enum(["compact", "full", "summary-first"]).default("summary-first")
764
+ .describe("summary-first (default) hoists shared provenance/warnings, drops per-result heavy detail; compact omits heavy per-result detail; full = everything (required for resolvedMembers/toolHealth/resolutionTrace unless explain=true)."),
745
765
  warningCategoryFilter: z.array(z.enum(["mapping", "configuration", "validation", "resolution", "parse"])).optional()
746
766
  .describe("Only include warnings/issues matching these categories (default: all)"),
747
767
  treatInfoAsWarning: z.boolean().default(true)
@@ -749,12 +769,24 @@ export const validateMixinShape = {
749
769
  includeIssues: z.boolean().default(true)
750
770
  .describe("When false, keep summary fields but omit per-result issues[] payloads")
751
771
  };
752
- export const validateMixinSchema = z.object(validateMixinShape);
772
+ export const validateMixinSchema = z.object(validateMixinShape).superRefine((value, ctx) => {
773
+ if (value.version) {
774
+ return;
775
+ }
776
+ const canDetectVersion = value.input?.mode === "project" || (value.preferProjectVersion === true && Boolean(value.projectPath));
777
+ if (!canDetectVersion) {
778
+ ctx.addIssue({
779
+ code: z.ZodIssueCode.custom,
780
+ path: ["version"],
781
+ message: "version is required unless input.mode='project' or preferProjectVersion=true with projectPath set (so the Minecraft version can be detected from gradle.properties)."
782
+ });
783
+ }
784
+ });
753
785
  export const validateAccessWidenerShape = {
754
786
  content: nonEmptyString.describe("Access Widener file content"),
755
787
  version: nonEmptyString.describe("Minecraft version"),
756
- mapping: sourceMappingSchema.optional().describe("obfuscated | mojang | intermediary | yarn"),
757
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
788
+ mapping: sourceMappingSchema.optional(),
789
+ sourcePriority: mappingSourcePrioritySchema.optional(),
758
790
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Loom cache-assisted runtime validation"),
759
791
  gradleUserHome: gradleUserHomeSchema,
760
792
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
@@ -765,8 +797,8 @@ export const validateAccessWidenerSchema = z.object(validateAccessWidenerShape);
765
797
  export const validateAccessTransformerShape = {
766
798
  content: nonEmptyString.describe("Access Transformer file content"),
767
799
  version: nonEmptyString.describe("Minecraft version"),
768
- atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional().describe("srg | mojang | obfuscated"),
769
- sourcePriority: mappingSourcePrioritySchema.optional().describe("loom-first | maven-first"),
800
+ atNamespace: z.enum(["srg", "mojang", "obfuscated"]).optional(),
801
+ sourcePriority: mappingSourcePrioritySchema.optional(),
770
802
  projectPath: optionalNonEmptyString.describe("Optional workspace root path for Forge/NeoForge runtime validation"),
771
803
  gradleUserHome: gradleUserHomeSchema,
772
804
  scope: artifactScopeSchema.optional().describe(SOURCE_SCOPE_DESCRIPTION),
@@ -782,7 +814,7 @@ export const analyzeModJarSchema = z.object(analyzeModJarShape);
782
814
  export const getRegistryDataShape = {
783
815
  version: nonEmptyString.describe("Minecraft version (e.g. 1.21)"),
784
816
  registry: optionalNonEmptyString.describe('Optional registry name (e.g. "block", "item", "minecraft:biome"). Omit to list all registries.'),
785
- includeData: z.boolean().default(true).describe("When false, return registry names/counts without full entry bodies"),
817
+ includeData: z.boolean().default(true).describe("false = registry names/counts only (cheap discovery); true (default) = full entry bodies."),
786
818
  maxEntriesPerRegistry: optionalPositiveInt.describe("Limit returned entries per registry body")
787
819
  };
788
820
  export const getRegistryDataSchema = z.object(getRegistryDataShape);
@@ -791,7 +823,7 @@ export const compareVersionsCategorySchema = z.enum(COMPARE_VERSIONS_CATEGORIES)
791
823
  export const compareVersionsShape = {
792
824
  fromVersion: nonEmptyString.describe("Older Minecraft version (e.g. 1.20.4)"),
793
825
  toVersion: nonEmptyString.describe("Newer Minecraft version (e.g. 1.21)"),
794
- category: compareVersionsCategorySchema.default("all").describe("classes | registry | all"),
826
+ category: compareVersionsCategorySchema.default("all"),
795
827
  packageFilter: optionalNonEmptyString.describe("Filter classes to a package prefix (e.g. net.minecraft.world.item)"),
796
828
  maxClassResults: optionalPositiveInt.default(500).describe("Max class results per direction (max 5000)")
797
829
  };
@@ -816,7 +848,7 @@ export const modSearchTypeSchema = z.enum(MOD_SEARCH_TYPES);
816
848
  export const searchModSourceShape = {
817
849
  jarPath: nonEmptyString.describe("Local path to the mod JAR file"),
818
850
  query: nonEmptyString.describe("Search pattern (regex or literal string)"),
819
- searchType: modSearchTypeSchema.default("all").describe("class | method | field | content | all"),
851
+ searchType: modSearchTypeSchema.default("all"),
820
852
  limit: optionalPositiveInt.default(50).describe("Max results (max 200)")
821
853
  };
822
854
  export const searchModSourceSchema = z.object(searchModSourceShape);
@@ -826,7 +858,11 @@ export const remapModJarShape = {
826
858
  inputJar: nonEmptyString.describe("Path to the mod JAR file"),
827
859
  outputJar: optionalNonEmptyString.describe("Output path for remapped JAR (auto-generated if omitted)"),
828
860
  mcVersion: optionalNonEmptyString.describe("Minecraft version (auto-detected from mod metadata if omitted)"),
829
- targetMapping: remapTargetSchema.describe("yarn | mojang")
861
+ targetMapping: remapTargetSchema,
862
+ forceRemap: z
863
+ .boolean()
864
+ .optional()
865
+ .describe("Skip the cache and re-resolve the newest yarn build (busts a stale remap)")
830
866
  };
831
867
  export const remapModJarSchema = z.object(remapModJarShape);
832
868
  export const emptySchema = z.object({}).passthrough();