@adhisang/minecraft-modding-mcp 4.0.0 → 4.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.
Files changed (174) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +36 -23
  3. package/dist/build-suggested-call.d.ts +29 -0
  4. package/dist/build-suggested-call.js +58 -0
  5. package/dist/cache-registry.d.ts +3 -1
  6. package/dist/cache-registry.js +50 -6
  7. package/dist/entry-tools/analyze-symbol-service.d.ts +16 -16
  8. package/dist/entry-tools/batch-class-members-service.d.ts +34 -0
  9. package/dist/entry-tools/batch-class-members-service.js +97 -0
  10. package/dist/entry-tools/batch-class-source-service.d.ts +37 -0
  11. package/dist/entry-tools/batch-class-source-service.js +100 -0
  12. package/dist/entry-tools/batch-mappings-service.d.ts +36 -0
  13. package/dist/entry-tools/batch-mappings-service.js +66 -0
  14. package/dist/entry-tools/batch-runner.d.ts +72 -0
  15. package/dist/entry-tools/batch-runner.js +90 -0
  16. package/dist/entry-tools/batch-symbol-exists-service.d.ts +46 -0
  17. package/dist/entry-tools/batch-symbol-exists-service.js +113 -0
  18. package/dist/entry-tools/compare-minecraft-service.d.ts +6 -6
  19. package/dist/entry-tools/inspect-minecraft/handlers/artifact.d.ts +5 -0
  20. package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +83 -0
  21. package/dist/entry-tools/inspect-minecraft/handlers/class-members.d.ts +6 -0
  22. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +80 -0
  23. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.d.ts +5 -0
  24. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +248 -0
  25. package/dist/entry-tools/inspect-minecraft/handlers/class-source.d.ts +5 -0
  26. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +60 -0
  27. package/dist/entry-tools/inspect-minecraft/handlers/file.d.ts +5 -0
  28. package/dist/entry-tools/inspect-minecraft/handlers/file.js +54 -0
  29. package/dist/entry-tools/inspect-minecraft/handlers/list-files.d.ts +5 -0
  30. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +100 -0
  31. package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +5 -0
  32. package/dist/entry-tools/inspect-minecraft/handlers/search.js +155 -0
  33. package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +6 -0
  34. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +49 -0
  35. package/dist/entry-tools/inspect-minecraft/internal.d.ts +1042 -0
  36. package/dist/entry-tools/inspect-minecraft/internal.js +448 -0
  37. package/dist/entry-tools/inspect-minecraft-service.d.ts +193 -308
  38. package/dist/entry-tools/inspect-minecraft-service.js +20 -1244
  39. package/dist/entry-tools/manage-cache-service.d.ts +16 -16
  40. package/dist/entry-tools/validate-project/cases/access-transformer.d.ts +6 -0
  41. package/dist/entry-tools/validate-project/cases/access-transformer.js +106 -0
  42. package/dist/entry-tools/validate-project/cases/access-widener.d.ts +6 -0
  43. package/dist/entry-tools/validate-project/cases/access-widener.js +86 -0
  44. package/dist/entry-tools/validate-project/cases/mixin.d.ts +6 -0
  45. package/dist/entry-tools/validate-project/cases/mixin.js +90 -0
  46. package/dist/entry-tools/validate-project/cases/project-summary.d.ts +97 -0
  47. package/dist/entry-tools/validate-project/cases/project-summary.js +346 -0
  48. package/dist/entry-tools/validate-project/internal.d.ts +135 -0
  49. package/dist/entry-tools/validate-project/internal.js +287 -0
  50. package/dist/entry-tools/validate-project-service.d.ts +63 -47
  51. package/dist/entry-tools/validate-project-service.js +12 -562
  52. package/dist/entry-tools/verify-mixin-target-service.d.ts +133 -0
  53. package/dist/entry-tools/verify-mixin-target-service.js +323 -0
  54. package/dist/error-mapping.d.ts +40 -0
  55. package/dist/error-mapping.js +139 -0
  56. package/dist/errors.d.ts +6 -0
  57. package/dist/errors.js +6 -0
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.js +142 -1352
  60. package/dist/mapping/internal-types.d.ts +54 -0
  61. package/dist/mapping/internal-types.js +14 -0
  62. package/dist/mapping/loaders/mojang.d.ts +2 -0
  63. package/dist/mapping/loaders/mojang.js +64 -0
  64. package/dist/mapping/loaders/tiny-loom.d.ts +2 -0
  65. package/dist/mapping/loaders/tiny-loom.js +73 -0
  66. package/dist/mapping/loaders/tiny-maven.d.ts +2 -0
  67. package/dist/mapping/loaders/tiny-maven.js +104 -0
  68. package/dist/mapping/loaders/types.d.ts +14 -0
  69. package/dist/mapping/loaders/types.js +2 -0
  70. package/dist/mapping/lookup.d.ts +52 -0
  71. package/dist/mapping/lookup.js +496 -0
  72. package/dist/mapping/parsers/normalize.d.ts +10 -0
  73. package/dist/mapping/parsers/normalize.js +52 -0
  74. package/dist/mapping/parsers/proguard.d.ts +20 -0
  75. package/dist/mapping/parsers/proguard.js +138 -0
  76. package/dist/mapping/parsers/symbol-records.d.ts +27 -0
  77. package/dist/mapping/parsers/symbol-records.js +216 -0
  78. package/dist/mapping/parsers/tiny.d.ts +9 -0
  79. package/dist/mapping/parsers/tiny.js +96 -0
  80. package/dist/mapping/types.d.ts +147 -0
  81. package/dist/mapping/types.js +2 -0
  82. package/dist/mapping-pipeline-service.js +3 -2
  83. package/dist/mapping-service.d.ts +3 -144
  84. package/dist/mapping-service.js +19 -1201
  85. package/dist/mixin/access-validators.d.ts +9 -0
  86. package/dist/mixin/access-validators.js +257 -0
  87. package/dist/mixin/annotation-validators.d.ts +5 -0
  88. package/dist/mixin/annotation-validators.js +162 -0
  89. package/dist/mixin/helpers.d.ts +28 -0
  90. package/dist/mixin/helpers.js +315 -0
  91. package/dist/mixin/parsed-validator.d.ts +8 -0
  92. package/dist/mixin/parsed-validator.js +337 -0
  93. package/dist/mixin/types.d.ts +208 -0
  94. package/dist/mixin/types.js +28 -0
  95. package/dist/mixin-validator.d.ts +9 -201
  96. package/dist/mixin-validator.js +8 -1020
  97. package/dist/source/access-validate.d.ts +4 -0
  98. package/dist/source/access-validate.js +254 -0
  99. package/dist/source/artifact-resolver.d.ts +110 -0
  100. package/dist/source/artifact-resolver.js +1174 -0
  101. package/dist/source/cache-metrics.d.ts +26 -0
  102. package/dist/source/cache-metrics.js +172 -0
  103. package/dist/source/class-source/members-builder.d.ts +34 -0
  104. package/dist/source/class-source/members-builder.js +46 -0
  105. package/dist/source/class-source/snippet-builder.d.ts +19 -0
  106. package/dist/source/class-source/snippet-builder.js +46 -0
  107. package/dist/source/class-source-helpers.d.ts +34 -0
  108. package/dist/source/class-source-helpers.js +140 -0
  109. package/dist/source/class-source.d.ts +42 -0
  110. package/dist/source/class-source.js +883 -0
  111. package/dist/source/descriptor-utils.d.ts +6 -0
  112. package/dist/source/descriptor-utils.js +37 -0
  113. package/dist/source/file-access.d.ts +4 -0
  114. package/dist/source/file-access.js +102 -0
  115. package/dist/source/indexer.d.ts +82 -0
  116. package/dist/source/indexer.js +505 -0
  117. package/dist/source/lifecycle/diff-utils.d.ts +9 -0
  118. package/dist/source/lifecycle/diff-utils.js +107 -0
  119. package/dist/source/lifecycle/diff.d.ts +2 -0
  120. package/dist/source/lifecycle/diff.js +265 -0
  121. package/dist/source/lifecycle/mapping-helpers.d.ts +22 -0
  122. package/dist/source/lifecycle/mapping-helpers.js +327 -0
  123. package/dist/source/lifecycle/runtime-check.d.ts +2 -0
  124. package/dist/source/lifecycle/runtime-check.js +142 -0
  125. package/dist/source/lifecycle/trace.d.ts +2 -0
  126. package/dist/source/lifecycle/trace.js +231 -0
  127. package/dist/source/lifecycle.d.ts +4 -0
  128. package/dist/source/lifecycle.js +5 -0
  129. package/dist/source/search.d.ts +51 -0
  130. package/dist/source/search.js +676 -0
  131. package/dist/source/shared-utils.d.ts +6 -0
  132. package/dist/source/shared-utils.js +55 -0
  133. package/dist/source/state.d.ts +21 -0
  134. package/dist/source/state.js +19 -0
  135. package/dist/source/symbol-resolver.d.ts +3 -0
  136. package/dist/source/symbol-resolver.js +212 -0
  137. package/dist/source/validate-mixin/pipeline/mapping-health.d.ts +3 -0
  138. package/dist/source/validate-mixin/pipeline/mapping-health.js +41 -0
  139. package/dist/source/validate-mixin/pipeline/parse.d.ts +2 -0
  140. package/dist/source/validate-mixin/pipeline/parse.js +10 -0
  141. package/dist/source/validate-mixin/pipeline/resolve.d.ts +3 -0
  142. package/dist/source/validate-mixin/pipeline/resolve.js +78 -0
  143. package/dist/source/validate-mixin/pipeline/target-lookup.d.ts +6 -0
  144. package/dist/source/validate-mixin/pipeline/target-lookup.js +260 -0
  145. package/dist/source/validate-mixin/pipeline-context.d.ts +72 -0
  146. package/dist/source/validate-mixin/pipeline-context.js +93 -0
  147. package/dist/source/validate-mixin.d.ts +22 -0
  148. package/dist/source/validate-mixin.js +799 -0
  149. package/dist/source/workspace-target.d.ts +18 -0
  150. package/dist/source/workspace-target.js +305 -0
  151. package/dist/source-service.d.ts +147 -170
  152. package/dist/source-service.js +67 -6116
  153. package/dist/stage-emitter.d.ts +13 -0
  154. package/dist/stage-emitter.js +30 -0
  155. package/dist/stdio-supervisor.d.ts +61 -0
  156. package/dist/stdio-supervisor.js +326 -9
  157. package/dist/tool-contract-manifest.d.ts +1 -1
  158. package/dist/tool-contract-manifest.js +23 -6
  159. package/dist/tool-guidance.d.ts +82 -0
  160. package/dist/tool-guidance.js +734 -0
  161. package/dist/tool-schema-registry.d.ts +16 -0
  162. package/dist/tool-schema-registry.js +37 -0
  163. package/dist/tool-schemas.d.ts +3518 -0
  164. package/dist/tool-schemas.js +813 -0
  165. package/dist/types.d.ts +36 -0
  166. package/dist/version-service.js +7 -6
  167. package/dist/workspace-context-cache.d.ts +32 -0
  168. package/dist/workspace-context-cache.js +66 -0
  169. package/dist/workspace-mapping-service.d.ts +16 -0
  170. package/dist/workspace-mapping-service.js +173 -1
  171. package/docs/README-ja.md +414 -0
  172. package/docs/examples.md +483 -0
  173. package/docs/tool-reference.md +459 -0
  174. package/package.json +3 -2
@@ -0,0 +1,734 @@
1
+ import { ZodError } from "zod";
2
+ import { buildSuggestedCall } from "./build-suggested-call.js";
3
+ import { ERROR_CODES, isAppError } from "./errors.js";
4
+ import { statusForErrorCode } from "./error-mapping.js";
5
+ export const SUGGESTED_CALL_DEFAULTS = {
6
+ allowDecompile: true,
7
+ preferProjectVersion: false,
8
+ strictVersion: false,
9
+ mode: "metadata",
10
+ access: "public",
11
+ includeSynthetic: false,
12
+ includeInherited: false,
13
+ hideUncertain: false,
14
+ explain: false,
15
+ preferProjectMapping: false,
16
+ minSeverity: "all",
17
+ reportMode: "full",
18
+ treatInfoAsWarning: true,
19
+ includeIssues: true
20
+ };
21
+ export function isSuggestedCallDefault(field, value) {
22
+ return value === SUGGESTED_CALL_DEFAULTS[field];
23
+ }
24
+ export const ANALYZE_MOD_INCLUDE_GROUPS = ["warnings", "files", "source", "samples", "timings"];
25
+ export const ANALYZE_MOD_LEGACY_METADATA_INCLUDES = ["metadata", "entrypoints", "mixins", "dependencies"];
26
+ export const VALIDATE_PROJECT_INCLUDE_GROUPS = ["warnings", "issues", "workspace", "recovery"];
27
+ export const VALIDATE_PROJECT_LEGACY_WORKSPACE_INCLUDES = ["detectedConfig", "mixins", "accessWideners"];
28
+ export const VALIDATION_FALLBACK_HINT = "suggested call payload failed schema validation; using fallback examples";
29
+ export function toFieldErrorsFromZod(error) {
30
+ return error.issues.map((issue) => ({
31
+ path: issue.path.join(".") || "$",
32
+ message: issue.message,
33
+ code: issue.code
34
+ }));
35
+ }
36
+ export function toHints(details) {
37
+ if (typeof details !== "object" || details == null) {
38
+ return undefined;
39
+ }
40
+ const hints = [];
41
+ const maybeNextAction = details.nextAction;
42
+ if (typeof maybeNextAction === "string" && maybeNextAction.trim()) {
43
+ hints.push(maybeNextAction.trim());
44
+ }
45
+ if (hints.length === 0) {
46
+ return undefined;
47
+ }
48
+ return hints;
49
+ }
50
+ export function extractValidatedSuggestionAndExamples(details) {
51
+ if (typeof details !== "object" || details == null) {
52
+ return { primaryDropped: false };
53
+ }
54
+ const record = details;
55
+ let primaryDropped = record._suggestedCallPrimaryDropped === true;
56
+ let suggestedCall;
57
+ const rawSuggested = record.suggestedCall;
58
+ if (rawSuggested !== undefined) {
59
+ if (typeof rawSuggested === "object" &&
60
+ rawSuggested !== null &&
61
+ !Array.isArray(rawSuggested)) {
62
+ const call = rawSuggested;
63
+ if (typeof call.tool === "string" &&
64
+ typeof call.params === "object" &&
65
+ call.params !== null &&
66
+ !Array.isArray(call.params)) {
67
+ const validated = buildSuggestedCall({
68
+ tool: call.tool,
69
+ params: call.params
70
+ });
71
+ if (validated.suggestedCall) {
72
+ suggestedCall = validated.suggestedCall;
73
+ }
74
+ else {
75
+ primaryDropped = true;
76
+ }
77
+ }
78
+ else {
79
+ primaryDropped = true;
80
+ }
81
+ }
82
+ else {
83
+ primaryDropped = true;
84
+ }
85
+ }
86
+ let exampleCalls;
87
+ const rawExamples = record.exampleCalls;
88
+ if (Array.isArray(rawExamples)) {
89
+ const validated = [];
90
+ for (const entry of rawExamples) {
91
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
92
+ continue;
93
+ const ex = entry;
94
+ if (typeof ex.tool !== "string" ||
95
+ typeof ex.params !== "object" ||
96
+ ex.params === null ||
97
+ Array.isArray(ex.params) ||
98
+ typeof ex.reason !== "string") {
99
+ continue;
100
+ }
101
+ const result = buildSuggestedCall({
102
+ tool: ex.tool,
103
+ params: ex.params
104
+ });
105
+ if (result.suggestedCall) {
106
+ validated.push({
107
+ tool: ex.tool,
108
+ params: result.suggestedCall.params,
109
+ reason: ex.reason
110
+ });
111
+ }
112
+ }
113
+ if (validated.length > 0) {
114
+ exampleCalls = validated;
115
+ }
116
+ }
117
+ return { suggestedCall, exampleCalls, primaryDropped };
118
+ }
119
+ export function extractFailedStageFromDetails(details) {
120
+ if (typeof details !== "object" || details == null) {
121
+ return undefined;
122
+ }
123
+ const maybeStage = details.failedStage;
124
+ if (typeof maybeStage === "string" && maybeStage.trim().length > 0) {
125
+ return maybeStage;
126
+ }
127
+ return undefined;
128
+ }
129
+ export function extractFieldErrorsFromDetails(details) {
130
+ if (typeof details !== "object" || details == null) {
131
+ return undefined;
132
+ }
133
+ const maybeFieldErrors = details.fieldErrors;
134
+ if (!Array.isArray(maybeFieldErrors)) {
135
+ return undefined;
136
+ }
137
+ const normalized = maybeFieldErrors
138
+ .map((entry) => {
139
+ if (typeof entry !== "object" || entry == null) {
140
+ return undefined;
141
+ }
142
+ const asRecord = entry;
143
+ const path = asRecord.path;
144
+ const message = asRecord.message;
145
+ const code = asRecord.code;
146
+ if (typeof path !== "string" || typeof message !== "string") {
147
+ return undefined;
148
+ }
149
+ return {
150
+ path,
151
+ message,
152
+ code: typeof code === "string" ? code : undefined
153
+ };
154
+ })
155
+ .filter((entry) => entry != null);
156
+ return normalized.length > 0 ? normalized : undefined;
157
+ }
158
+ export function asObjectRecord(value) {
159
+ return typeof value === "object" && value != null && !Array.isArray(value)
160
+ ? value
161
+ : undefined;
162
+ }
163
+ export function asNonEmptyString(value) {
164
+ return typeof value === "string" && value.trim() ? value : undefined;
165
+ }
166
+ export function asStringArray(value) {
167
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.trim())
168
+ ? value
169
+ : undefined;
170
+ }
171
+ export function truncateSuggestionText(value, maxLength = 500) {
172
+ return value.length > maxLength
173
+ ? `${value.slice(0, maxLength)}...`
174
+ : value;
175
+ }
176
+ export function parseJsonObjectString(value) {
177
+ if (!value.trim().startsWith("{")) {
178
+ return undefined;
179
+ }
180
+ try {
181
+ const parsed = JSON.parse(value);
182
+ return asObjectRecord(parsed);
183
+ }
184
+ catch {
185
+ return undefined;
186
+ }
187
+ }
188
+ export function inferTargetKindFromString(value) {
189
+ if (/[\\/]/.test(value) || /\.jar$/i.test(value)) {
190
+ return "jar";
191
+ }
192
+ if (value.split(":").length >= 3) {
193
+ return "coordinate";
194
+ }
195
+ return "version";
196
+ }
197
+ export function copySourceLookupSuggestionFields(tool, source) {
198
+ const result = {};
199
+ const stringFields = tool === "get-class-source"
200
+ ? ["className", "mode", "mapping", "sourcePriority", "projectPath", "scope", "outputFile"]
201
+ : ["className", "mapping", "sourcePriority", "projectPath", "scope", "access", "memberPattern"];
202
+ for (const field of stringFields) {
203
+ const value = source[field];
204
+ if (typeof value === "string" &&
205
+ value.trim() &&
206
+ (!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
207
+ !isSuggestedCallDefault(field, value))) {
208
+ result[field] = value;
209
+ }
210
+ }
211
+ const numericFields = tool === "get-class-source"
212
+ ? ["startLine", "endLine", "maxLines", "maxChars"]
213
+ : ["maxMembers"];
214
+ for (const field of numericFields) {
215
+ const value = source[field];
216
+ if (typeof value === "number" && Number.isFinite(value)) {
217
+ result[field] = value;
218
+ }
219
+ }
220
+ const booleanFields = tool === "get-class-source"
221
+ ? ["allowDecompile", "preferProjectVersion", "strictVersion"]
222
+ : ["allowDecompile", "preferProjectVersion", "strictVersion", "includeSynthetic", "includeInherited"];
223
+ for (const field of booleanFields) {
224
+ const value = source[field];
225
+ if (typeof value === "boolean" &&
226
+ (!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
227
+ !isSuggestedCallDefault(field, value))) {
228
+ result[field] = value;
229
+ }
230
+ }
231
+ return result;
232
+ }
233
+ export function copyValidateMixinSharedParams(source) {
234
+ const result = {};
235
+ const stringFields = [
236
+ "version",
237
+ "mapping",
238
+ "sourcePriority",
239
+ "scope",
240
+ "projectPath",
241
+ "minSeverity",
242
+ "warningMode",
243
+ "reportMode"
244
+ ];
245
+ for (const field of stringFields) {
246
+ const value = source[field];
247
+ if (typeof value === "string" &&
248
+ value.trim() &&
249
+ (!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
250
+ !isSuggestedCallDefault(field, value))) {
251
+ result[field] = value;
252
+ }
253
+ }
254
+ const booleanFields = [
255
+ "preferProjectVersion",
256
+ "hideUncertain",
257
+ "explain",
258
+ "preferProjectMapping",
259
+ "treatInfoAsWarning",
260
+ "includeIssues"
261
+ ];
262
+ for (const field of booleanFields) {
263
+ const value = source[field];
264
+ if (typeof value === "boolean" &&
265
+ (!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
266
+ !isSuggestedCallDefault(field, value))) {
267
+ result[field] = value;
268
+ }
269
+ }
270
+ const sourceRoots = asStringArray(source.sourceRoots);
271
+ if (sourceRoots) {
272
+ result.sourceRoots = sourceRoots;
273
+ }
274
+ const warningCategoryFilter = asStringArray(source.warningCategoryFilter);
275
+ if (warningCategoryFilter) {
276
+ result.warningCategoryFilter = warningCategoryFilter;
277
+ }
278
+ return result;
279
+ }
280
+ export function buildValidateMixinSuggestedParams(normalizedInput) {
281
+ const record = asObjectRecord(normalizedInput);
282
+ if (!record) {
283
+ return {
284
+ input: {
285
+ mode: "inline",
286
+ source: "<Mixin Java source>"
287
+ },
288
+ version: "<minecraft-version>"
289
+ };
290
+ }
291
+ const inputRecord = asObjectRecord(record.input);
292
+ const shared = copyValidateMixinSharedParams(record);
293
+ const version = asNonEmptyString(record.version) ?? "<minecraft-version>";
294
+ const inlineSource = asNonEmptyString(record.input) ??
295
+ asNonEmptyString(inputRecord?.source) ??
296
+ asNonEmptyString(record.source);
297
+ if (inlineSource) {
298
+ const parsedInlineObject = parseJsonObjectString(inlineSource);
299
+ if (parsedInlineObject && typeof parsedInlineObject.mode === "string") {
300
+ return {
301
+ ...shared,
302
+ input: parsedInlineObject,
303
+ version
304
+ };
305
+ }
306
+ return {
307
+ ...shared,
308
+ input: {
309
+ mode: "inline",
310
+ source: truncateSuggestionText(inlineSource)
311
+ },
312
+ version
313
+ };
314
+ }
315
+ const path = asNonEmptyString(inputRecord?.path) ??
316
+ asNonEmptyString(record.sourcePath);
317
+ if (path) {
318
+ return {
319
+ ...shared,
320
+ input: {
321
+ mode: "path",
322
+ path
323
+ },
324
+ version
325
+ };
326
+ }
327
+ const paths = asStringArray(inputRecord?.paths) ??
328
+ asStringArray(record.sourcePaths);
329
+ if (paths) {
330
+ return {
331
+ ...shared,
332
+ input: {
333
+ mode: "paths",
334
+ paths
335
+ },
336
+ version
337
+ };
338
+ }
339
+ const configPaths = asStringArray(inputRecord?.configPaths) ??
340
+ (asNonEmptyString(record.mixinConfigPath) ? [record.mixinConfigPath] : undefined);
341
+ if (configPaths) {
342
+ return {
343
+ ...shared,
344
+ input: {
345
+ mode: "config",
346
+ configPaths
347
+ },
348
+ version
349
+ };
350
+ }
351
+ const projectPath = asNonEmptyString(record.projectPath) ??
352
+ (inputRecord?.mode === "project" ? asNonEmptyString(inputRecord.path) : undefined);
353
+ if (projectPath) {
354
+ return {
355
+ ...shared,
356
+ input: {
357
+ mode: "project",
358
+ path: projectPath
359
+ },
360
+ version
361
+ };
362
+ }
363
+ return {
364
+ ...shared,
365
+ input: {
366
+ mode: "inline",
367
+ source: "<Mixin Java source>"
368
+ },
369
+ version
370
+ };
371
+ }
372
+ export function buildResolveArtifactSuggestedParams(normalizedInput) {
373
+ const record = asObjectRecord(normalizedInput);
374
+ if (!record) {
375
+ return {
376
+ target: {
377
+ kind: "version",
378
+ value: "<minecraft-version>"
379
+ }
380
+ };
381
+ }
382
+ const targetValue = asNonEmptyString(record.target);
383
+ const result = {
384
+ target: targetValue
385
+ ? {
386
+ kind: inferTargetKindFromString(targetValue),
387
+ value: targetValue
388
+ }
389
+ : {
390
+ kind: "version",
391
+ value: "<minecraft-version>"
392
+ }
393
+ };
394
+ const stringFields = ["mapping", "sourcePriority", "projectPath", "scope"];
395
+ for (const field of stringFields) {
396
+ const value = record[field];
397
+ if (typeof value === "string" && value.trim()) {
398
+ result[field] = value;
399
+ }
400
+ }
401
+ const booleanFields = ["allowDecompile", "preferProjectVersion", "strictVersion"];
402
+ for (const field of booleanFields) {
403
+ const value = record[field];
404
+ if (typeof value === "boolean" &&
405
+ !isSuggestedCallDefault(field, value)) {
406
+ result[field] = value;
407
+ }
408
+ }
409
+ return result;
410
+ }
411
+ export function buildSourceLookupSuggestedParams(tool, normalizedInput) {
412
+ const record = asObjectRecord(normalizedInput);
413
+ const result = record ? copySourceLookupSuggestionFields(tool, record) : {};
414
+ const targetValue = asNonEmptyString(record?.target);
415
+ result.target = targetValue
416
+ ? {
417
+ type: "resolve",
418
+ kind: inferTargetKindFromString(targetValue),
419
+ value: targetValue
420
+ }
421
+ : {
422
+ type: "resolve",
423
+ kind: "version",
424
+ value: "<minecraft-version>"
425
+ };
426
+ if (!asNonEmptyString(result.className)) {
427
+ result.className = "<fully-qualified-class-name>";
428
+ }
429
+ return result;
430
+ }
431
+ export function filterAllowedIncludeValues(values, allowed) {
432
+ if (!values?.length) {
433
+ return [];
434
+ }
435
+ const allowedSet = new Set(allowed);
436
+ const filtered = values.filter((value) => allowedSet.has(value));
437
+ return [...new Set(filtered)];
438
+ }
439
+ export function buildAnalyzeModSuggestedParams(normalizedInput) {
440
+ const record = asObjectRecord(normalizedInput);
441
+ if (!record) {
442
+ return {
443
+ task: "summary",
444
+ detail: "standard",
445
+ subject: {
446
+ kind: "jar",
447
+ jarPath: "<mod-jar-path>"
448
+ }
449
+ };
450
+ }
451
+ const task = asNonEmptyString(record.task) ?? "summary";
452
+ const result = { task };
453
+ const subjectRecord = asObjectRecord(record.subject);
454
+ const include = asStringArray(record.include);
455
+ const canonicalInclude = filterAllowedIncludeValues(include, ANALYZE_MOD_INCLUDE_GROUPS);
456
+ const wantsLegacyMetadata = include?.some((value) => ANALYZE_MOD_LEGACY_METADATA_INCLUDES.includes(value)) ?? false;
457
+ const detail = asNonEmptyString(record.detail);
458
+ if (task === "summary" && wantsLegacyMetadata) {
459
+ result.detail = detail && detail !== "summary" ? detail : "standard";
460
+ }
461
+ else if (detail && detail !== "summary") {
462
+ result.detail = detail;
463
+ }
464
+ if (canonicalInclude.length > 0) {
465
+ result.include = canonicalInclude;
466
+ }
467
+ if (task === "class-source") {
468
+ result.subject = {
469
+ kind: "class",
470
+ jarPath: asNonEmptyString(subjectRecord?.jarPath) ?? asNonEmptyString(record.subject) ?? "<mod-jar-path>",
471
+ className: asNonEmptyString(subjectRecord?.className) ?? asNonEmptyString(record.className) ?? "<fully-qualified-class-name>"
472
+ };
473
+ }
474
+ else {
475
+ result.subject = {
476
+ kind: "jar",
477
+ jarPath: asNonEmptyString(subjectRecord?.jarPath) ?? asNonEmptyString(record.subject) ?? asNonEmptyString(record.jarPath) ?? "<mod-jar-path>"
478
+ };
479
+ }
480
+ const stringFields = ["query", "searchType", "targetMapping", "outputJar", "executionMode"];
481
+ for (const field of stringFields) {
482
+ const value = record[field];
483
+ if (typeof value === "string" && value.trim()) {
484
+ result[field] = value;
485
+ }
486
+ }
487
+ const booleanFields = ["includeFiles"];
488
+ for (const field of booleanFields) {
489
+ const value = record[field];
490
+ if (typeof value === "boolean") {
491
+ result[field] = value;
492
+ }
493
+ }
494
+ const numericFields = ["limit", "maxFiles", "maxLines", "maxChars"];
495
+ for (const field of numericFields) {
496
+ const value = record[field];
497
+ if (typeof value === "number" && Number.isFinite(value)) {
498
+ result[field] = value;
499
+ }
500
+ }
501
+ return result;
502
+ }
503
+ export function buildValidateProjectSuggestedParams(normalizedInput) {
504
+ const record = asObjectRecord(normalizedInput);
505
+ if (!record) {
506
+ return {
507
+ task: "project-summary",
508
+ subject: {
509
+ kind: "workspace",
510
+ projectPath: "<workspace-path>"
511
+ },
512
+ preferProjectVersion: true
513
+ };
514
+ }
515
+ const task = asNonEmptyString(record.task) ?? "project-summary";
516
+ const result = { task };
517
+ const subjectRecord = asObjectRecord(record.subject);
518
+ const include = asStringArray(record.include);
519
+ const canonicalInclude = filterAllowedIncludeValues(include, VALIDATE_PROJECT_INCLUDE_GROUPS);
520
+ const wantsWorkspaceInclude = include?.some((value) => VALIDATE_PROJECT_LEGACY_WORKSPACE_INCLUDES.includes(value)) ?? false;
521
+ const detail = asNonEmptyString(record.detail);
522
+ if (detail && detail !== "summary") {
523
+ result.detail = detail;
524
+ }
525
+ const includeSuggestion = wantsWorkspaceInclude
526
+ ? [...new Set([...canonicalInclude, "workspace"])]
527
+ : canonicalInclude;
528
+ if (includeSuggestion.length > 0) {
529
+ result.include = includeSuggestion;
530
+ }
531
+ const stringFields = [
532
+ "version",
533
+ "mapping",
534
+ "sourcePriority",
535
+ "scope",
536
+ "minSeverity",
537
+ "warningMode"
538
+ ];
539
+ for (const field of stringFields) {
540
+ const value = record[field];
541
+ if (typeof value === "string" && value.trim()) {
542
+ result[field] = value;
543
+ }
544
+ }
545
+ const booleanFields = [
546
+ "preferProjectVersion",
547
+ "preferProjectMapping",
548
+ "hideUncertain",
549
+ "explain",
550
+ "treatInfoAsWarning",
551
+ "includeIssues"
552
+ ];
553
+ for (const field of booleanFields) {
554
+ const value = record[field];
555
+ if (typeof value === "boolean" &&
556
+ (!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
557
+ !isSuggestedCallDefault(field, value))) {
558
+ result[field] = value;
559
+ }
560
+ }
561
+ const sourceRoots = asStringArray(record.sourceRoots);
562
+ if (sourceRoots?.length) {
563
+ result.sourceRoots = sourceRoots;
564
+ }
565
+ const configPaths = asStringArray(record.configPaths);
566
+ if (configPaths?.length) {
567
+ result.configPaths = configPaths;
568
+ }
569
+ const warningCategoryFilter = asStringArray(record.warningCategoryFilter);
570
+ if (warningCategoryFilter?.length) {
571
+ result.warningCategoryFilter = warningCategoryFilter;
572
+ }
573
+ if (task === "project-summary") {
574
+ const subject = {
575
+ kind: "workspace",
576
+ projectPath: asNonEmptyString(subjectRecord?.projectPath) ??
577
+ asNonEmptyString(record.subject) ??
578
+ asNonEmptyString(record.projectPath) ??
579
+ "<workspace-path>"
580
+ };
581
+ const discover = asStringArray(subjectRecord?.discover);
582
+ if (discover?.length) {
583
+ subject.discover = discover;
584
+ }
585
+ result.subject = subject;
586
+ return result;
587
+ }
588
+ if (task === "mixin") {
589
+ const inputRecord = asObjectRecord(subjectRecord?.input) ?? asObjectRecord(record.input);
590
+ result.subject = {
591
+ kind: "mixin",
592
+ input: inputRecord ?? {
593
+ mode: "inline",
594
+ source: "<Mixin Java source>"
595
+ }
596
+ };
597
+ return result;
598
+ }
599
+ const inputRecord = asObjectRecord(subjectRecord?.input) ?? asObjectRecord(record.input);
600
+ result.subject = {
601
+ kind: "access-widener",
602
+ input: inputRecord ?? {
603
+ mode: "inline",
604
+ content: "<access widener contents>"
605
+ }
606
+ };
607
+ return result;
608
+ }
609
+ function gatedGuidance(tool, hints, params) {
610
+ const validated = buildSuggestedCall({ tool, params });
611
+ return {
612
+ hints,
613
+ ...validated,
614
+ primaryDropped: !validated.suggestedCall
615
+ };
616
+ }
617
+ export function buildInvalidInputGuidance(tool, normalizedInput) {
618
+ if (tool === "validate-mixin") {
619
+ return gatedGuidance(tool, [
620
+ "validate-mixin.input must be an object with input.mode = \"inline\" | \"path\" | \"paths\" | \"config\" | \"project\".",
621
+ "Whole-project example: {\"input\":{\"mode\":\"project\",\"path\":\"/workspace\"},\"version\":\"1.21.10\",\"preferProjectVersion\":true,\"preferProjectMapping\":true}.",
622
+ "Legacy top-level source/sourcePath/sourcePaths/mixinConfigPath fields are no longer accepted; wrap them under input.mode instead."
623
+ ], buildValidateMixinSuggestedParams(normalizedInput));
624
+ }
625
+ if (tool === "resolve-artifact") {
626
+ return gatedGuidance(tool, [
627
+ "resolve-artifact.target must be an object: {\"kind\":\"version|jar|coordinate\",\"value\":\"...\"}.",
628
+ "Bare string targets are not accepted; wrap the value under target.kind and target.value."
629
+ ], buildResolveArtifactSuggestedParams(normalizedInput));
630
+ }
631
+ if (tool === "get-class-source" || tool === "get-class-members") {
632
+ return gatedGuidance(tool, [
633
+ `${tool}.target must be an object: {"type":"resolve","kind":"version|jar|coordinate","value":"..."} or {"type":"artifact","artifactId":"..."}.`,
634
+ "Bare string targets are not accepted; wrap the value under target.type/target.kind/target.value."
635
+ ], buildSourceLookupSuggestedParams(tool, normalizedInput));
636
+ }
637
+ if (tool === "validate-project") {
638
+ return gatedGuidance(tool, [
639
+ "validate-project.subject must be an object with subject.kind=workspace|mixin|access-widener|access-transformer.",
640
+ "task=\"project-summary\" uses {\"subject\":{\"kind\":\"workspace\",\"projectPath\":\"/workspace\"}}.",
641
+ "Legacy include names like projectSummary/detectedConfig/validationSummary are not accepted; use include:[\"workspace\"] only when you need discovery details."
642
+ ], buildValidateProjectSuggestedParams(normalizedInput));
643
+ }
644
+ if (tool === "analyze-mod") {
645
+ return gatedGuidance(tool, [
646
+ "analyze-mod.subject must be an object with subject.kind=jar|class.",
647
+ "task=\"summary\" uses {\"subject\":{\"kind\":\"jar\",\"jarPath\":\"/path/to/mod.jar\"}}.",
648
+ "Legacy include names like metadata/entrypoints/mixins/dependencies are not accepted; use detail=\"standard\" to surface the metadata block, and canonical include groups only for warnings/files/source/samples/timings."
649
+ ], buildAnalyzeModSuggestedParams(normalizedInput));
650
+ }
651
+ return undefined;
652
+ }
653
+ export function mapErrorToProblem(caughtError, requestId, context) {
654
+ if (caughtError instanceof ZodError) {
655
+ const guidance = context?.tool
656
+ ? buildInvalidInputGuidance(context.tool, context.normalizedInput)
657
+ : undefined;
658
+ const baseHints = guidance?.hints ?? ["Check fieldErrors and submit a valid tool argument payload."];
659
+ const hintsWithFallback = guidance?.primaryDropped
660
+ ? [...baseHints, VALIDATION_FALLBACK_HINT]
661
+ : baseHints;
662
+ return {
663
+ type: "https://minecraft-modding-mcp.dev/problems/invalid-input",
664
+ title: "Invalid input",
665
+ detail: "Request validation failed.",
666
+ status: 400,
667
+ code: ERROR_CODES.INVALID_INPUT,
668
+ instance: requestId,
669
+ fieldErrors: toFieldErrorsFromZod(caughtError),
670
+ hints: hintsWithFallback,
671
+ ...(guidance?.suggestedCall ? { suggestedCall: guidance.suggestedCall } : {}),
672
+ ...(guidance?.exampleCalls ? { exampleCalls: guidance.exampleCalls } : {}),
673
+ ...(context?.tool === "validate-mixin" ? { failedStage: "input-validation" } : {})
674
+ };
675
+ }
676
+ if (isAppError(caughtError)) {
677
+ const { suggestedCall, exampleCalls, primaryDropped } = extractValidatedSuggestionAndExamples(caughtError.details);
678
+ let failedStage = extractFailedStageFromDetails(caughtError.details);
679
+ if (!failedStage
680
+ && context?.tool === "validate-mixin"
681
+ && caughtError.code === ERROR_CODES.INVALID_INPUT) {
682
+ failedStage = "input-validation";
683
+ }
684
+ const baseHints = toHints(caughtError.details);
685
+ const hintsWithFallback = primaryDropped && !suggestedCall
686
+ ? [...(baseHints ?? []), VALIDATION_FALLBACK_HINT]
687
+ : baseHints;
688
+ return {
689
+ type: `https://minecraft-modding-mcp.dev/problems/${caughtError.code.toLowerCase()}`,
690
+ title: "Tool execution error",
691
+ detail: caughtError.message,
692
+ status: statusForErrorCode(caughtError.code),
693
+ code: caughtError.code,
694
+ instance: requestId,
695
+ fieldErrors: extractFieldErrorsFromDetails(caughtError.details),
696
+ hints: hintsWithFallback,
697
+ ...(suggestedCall ? { suggestedCall } : {}),
698
+ ...(exampleCalls ? { exampleCalls } : {}),
699
+ ...(failedStage ? { failedStage } : {})
700
+ };
701
+ }
702
+ return {
703
+ type: "https://minecraft-modding-mcp.dev/problems/internal",
704
+ title: "Internal server error",
705
+ detail: "Unexpected server error.",
706
+ status: 500,
707
+ code: ERROR_CODES.INTERNAL,
708
+ instance: requestId
709
+ };
710
+ }
711
+ /**
712
+ * Copy documented error-only meta fields from AppError.details into the
713
+ * public envelope. Scoped to `ERR_STAGE_BUDGET_PRE_PARSE` per
714
+ * docs/tool-reference.md §Meta fields.
715
+ */
716
+ export function applyErrorMetaExtensions(meta, error) {
717
+ if (!isAppError(error))
718
+ return;
719
+ if (error.code !== ERROR_CODES.STAGE_BUDGET_PRE_PARSE)
720
+ return;
721
+ const details = error.details;
722
+ if (!details)
723
+ return;
724
+ if (details.stageBudgetExhausted === true) {
725
+ meta.stageBudgetExhausted = true;
726
+ }
727
+ if (typeof details.budgetMs === "number") {
728
+ meta.budgetMs = details.budgetMs;
729
+ }
730
+ if (typeof details.elapsedMs === "number") {
731
+ meta.elapsedMs = details.elapsedMs;
732
+ }
733
+ }
734
+ //# sourceMappingURL=tool-guidance.js.map