@adhisang/minecraft-modding-mcp 4.2.1 → 5.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 (114) hide show
  1. package/CHANGELOG.md +33 -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/build-suggested-call.js +31 -10
  6. package/dist/cache-registry.d.ts +8 -0
  7. package/dist/cache-registry.js +15 -1
  8. package/dist/config.d.ts +1 -0
  9. package/dist/config.js +4 -0
  10. package/dist/entry-tools/analyze-mod-service.d.ts +24 -24
  11. package/dist/entry-tools/analyze-symbol-service.d.ts +57 -22
  12. package/dist/entry-tools/analyze-symbol-service.js +124 -28
  13. package/dist/entry-tools/batch-class-members-service.d.ts +3 -1
  14. package/dist/entry-tools/batch-class-members-service.js +6 -6
  15. package/dist/entry-tools/batch-class-source-service.d.ts +3 -1
  16. package/dist/entry-tools/batch-class-source-service.js +5 -6
  17. package/dist/entry-tools/batch-mappings-service.d.ts +3 -1
  18. package/dist/entry-tools/batch-mappings-service.js +4 -5
  19. package/dist/entry-tools/batch-symbol-exists-service.d.ts +3 -1
  20. package/dist/entry-tools/batch-symbol-exists-service.js +4 -5
  21. package/dist/entry-tools/compare-minecraft-service.d.ts +10 -10
  22. package/dist/entry-tools/entry-tool-schema.d.ts +1 -1
  23. package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +1 -3
  24. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +2 -2
  25. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +0 -5
  26. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +0 -1
  27. package/dist/entry-tools/inspect-minecraft/handlers/file.js +0 -1
  28. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +0 -1
  29. package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +8 -0
  30. package/dist/entry-tools/inspect-minecraft/handlers/search.js +13 -2
  31. package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +1 -1
  32. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +1 -1
  33. package/dist/entry-tools/inspect-minecraft/internal.d.ts +90 -89
  34. package/dist/entry-tools/inspect-minecraft/internal.js +30 -14
  35. package/dist/entry-tools/inspect-minecraft-service.d.ts +218 -218
  36. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  37. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  38. package/dist/entry-tools/response-contract.d.ts +1 -1
  39. package/dist/entry-tools/response-contract.js +1 -0
  40. package/dist/entry-tools/validate-project/cases/mixin.js +2 -1
  41. package/dist/entry-tools/validate-project/cases/project-summary.js +5 -3
  42. package/dist/entry-tools/validate-project-service.d.ts +42 -36
  43. package/dist/entry-tools/validate-project-service.js +3 -1
  44. package/dist/entry-tools/verify-mixin-target-service.d.ts +30 -0
  45. package/dist/entry-tools/verify-mixin-target-service.js +113 -22
  46. package/dist/error-mapping.d.ts +51 -0
  47. package/dist/error-mapping.js +157 -2
  48. package/dist/index.js +138 -71
  49. package/dist/mapping/internal-types.d.ts +7 -0
  50. package/dist/mapping/lookup.d.ts +1 -1
  51. package/dist/mapping/lookup.js +7 -1
  52. package/dist/mapping/types.d.ts +6 -0
  53. package/dist/mapping-service.d.ts +26 -2
  54. package/dist/mapping-service.js +178 -36
  55. package/dist/mcp-helpers.d.ts +1 -0
  56. package/dist/mcp-helpers.js +25 -3
  57. package/dist/minecraft-explorer-service.js +24 -11
  58. package/dist/mixin/access-validators.js +33 -1
  59. package/dist/mixin/annotation-validators.js +53 -7
  60. package/dist/mixin/parsed-validator.js +2 -2
  61. package/dist/mixin-parser.js +48 -4
  62. package/dist/mod-decompile-service.js +2 -1
  63. package/dist/mod-remap-service.d.ts +20 -1
  64. package/dist/mod-remap-service.js +95 -40
  65. package/dist/nbt/java-nbt-codec.js +6 -0
  66. package/dist/observability.d.ts +6 -0
  67. package/dist/observability.js +10 -0
  68. package/dist/page-cursor.d.ts +17 -0
  69. package/dist/page-cursor.js +0 -0
  70. package/dist/registry-service.js +25 -1
  71. package/dist/resources.js +45 -9
  72. package/dist/response-utils.d.ts +29 -4
  73. package/dist/response-utils.js +95 -5
  74. package/dist/source/access-validate.js +12 -2
  75. package/dist/source/artifact-resolver.js +1 -1
  76. package/dist/source/class-source/members-builder.d.ts +44 -1
  77. package/dist/source/class-source/members-builder.js +51 -4
  78. package/dist/source/class-source/snippet-builder.d.ts +13 -0
  79. package/dist/source/class-source/snippet-builder.js +48 -4
  80. package/dist/source/class-source-helpers.js +67 -11
  81. package/dist/source/class-source.js +97 -20
  82. package/dist/source/indexer.js +5 -2
  83. package/dist/source/search.d.ts +1 -1
  84. package/dist/source/search.js +94 -22
  85. package/dist/source/validate-mixin.d.ts +2 -1
  86. package/dist/source/validate-mixin.js +45 -4
  87. package/dist/source/workspace-target.js +15 -9
  88. package/dist/source-jar-reader.d.ts +54 -1
  89. package/dist/source-jar-reader.js +121 -10
  90. package/dist/source-service.d.ts +28 -7
  91. package/dist/storage/files-repo.d.ts +12 -0
  92. package/dist/storage/files-repo.js +24 -0
  93. package/dist/storage/symbols-repo.d.ts +6 -0
  94. package/dist/storage/symbols-repo.js +6 -0
  95. package/dist/symbols/symbol-extractor.js +35 -6
  96. package/dist/text-truncate.d.ts +7 -0
  97. package/dist/text-truncate.js +21 -0
  98. package/dist/tiny-remapper-resolver.js +10 -0
  99. package/dist/tool-contract-manifest.js +2 -2
  100. package/dist/tool-execution-gate.js +12 -1
  101. package/dist/tool-guidance.d.ts +4 -1
  102. package/dist/tool-guidance.js +37 -12
  103. package/dist/tool-schemas.d.ts +559 -494
  104. package/dist/tool-schemas.js +99 -63
  105. package/dist/types.d.ts +1 -0
  106. package/dist/version-diff-service.js +5 -0
  107. package/dist/version-service.d.ts +3 -0
  108. package/dist/version-service.js +18 -2
  109. package/dist/warning-details.d.ts +18 -0
  110. package/dist/warning-details.js +63 -0
  111. package/docs/README-ja.md +2 -2
  112. package/docs/examples.md +26 -2
  113. package/docs/tool-reference.md +22 -17
  114. package/package.json +1 -1
@@ -3,7 +3,21 @@ import { createError, ERROR_CODES } from "../errors.js";
3
3
  import { buildIncludeSchema, detailSchema, positiveIntSchema } from "./entry-tool-schema.js";
4
4
  import { buildEntryToolResult, createSummarySubject } from "./response-contract.js";
5
5
  import { resolveDetail, resolveInclude } from "./request-normalizers.js";
6
+ import { compactMappingResponse } from "../response-utils.js";
6
7
  const nonEmptyString = z.string().trim().min(1);
8
+ /**
9
+ * Reuse the expert-tool compactMappingResponse candidate projection so the entry
10
+ * tool is as terse as the low-level one: drop the lone exact candidate that just
11
+ * duplicates `match` (resolved-exact), and slim the tail of unresolved candidate
12
+ * lists. Returns block fields to spread into buildEntryToolResult's `blocks`.
13
+ */
14
+ function projectMappingCandidates(output) {
15
+ const projected = compactMappingResponse(output);
16
+ return {
17
+ candidates: projected.candidates,
18
+ ...(projected.candidateDetailsTruncated === true ? { candidateDetailsTruncated: true } : {})
19
+ };
20
+ }
7
21
  // Descriptor field that treats empty/whitespace strings as omitted so callers can pass
8
22
  // `descriptor: ""` interchangeably with omitting the field when signatureMode="name-only".
9
23
  const optionalDescriptorString = z
@@ -15,38 +29,114 @@ const optionalDescriptorString = z
15
29
  const trimmed = value.trim();
16
30
  return trimmed.length === 0 ? undefined : trimmed;
17
31
  });
32
+ /**
33
+ * Resolve subject.kind to a concrete kind. `"symbol"` is auto-detected from the
34
+ * selector (owner+descriptor => method, owner only => field, otherwise => class)
35
+ * and the inference is surfaced as a warning so the caller can see what ran.
36
+ */
37
+ function inferSubjectKind(subject) {
38
+ if (subject.kind !== "symbol") {
39
+ return { kind: subject.kind };
40
+ }
41
+ let inferred;
42
+ if (subject.owner && subject.descriptor) {
43
+ inferred = "method";
44
+ }
45
+ else if (subject.owner) {
46
+ inferred = "field";
47
+ }
48
+ else {
49
+ inferred = "class";
50
+ }
51
+ const selectorNote = subject.owner
52
+ ? subject.descriptor
53
+ ? "owner+descriptor"
54
+ : "owner only"
55
+ : "no owner/descriptor";
56
+ return {
57
+ kind: inferred,
58
+ warning: `subject.kind="symbol" was auto-detected as "${inferred}" (${selectorNote}). Pass an explicit kind to override.`
59
+ };
60
+ }
18
61
  const INCLUDE_GROUPS = ["warnings", "candidates", "matrix", "workspace", "timings"];
19
62
  const TASKS = ["exists", "map", "exact-map", "lifecycle", "workspace", "api-overview"];
20
63
  export const analyzeSymbolShape = {
21
64
  task: z.enum(TASKS),
22
65
  subject: z.object({
23
- kind: z.enum(["class", "method", "field", "symbol"]),
66
+ kind: z
67
+ .enum(["class", "method", "field", "symbol"])
68
+ .describe("Symbol kind. Use 'symbol' to auto-detect from the selector: owner+descriptor => method, owner only => field, otherwise => class. The inferred kind is reported as a warning. For task=api-overview the inferred kind must be class."),
24
69
  name: nonEmptyString,
25
70
  owner: nonEmptyString.optional(),
26
71
  descriptor: optionalDescriptorString
27
72
  }),
28
- version: nonEmptyString.optional(),
73
+ version: nonEmptyString
74
+ .optional()
75
+ .describe("Point-in-time MC version for task=exists/map/exact-map/api-overview. For task=lifecycle it is accepted as a back-compat alias for toVersion (range end)."),
76
+ fromVersion: nonEmptyString
77
+ .optional()
78
+ .describe("task=lifecycle only: range start (oldest) version; defaults to the oldest version in the manifest."),
79
+ toVersion: nonEmptyString
80
+ .optional()
81
+ .describe("task=lifecycle only: range end (newest) version; takes precedence over version. Defaults to latest."),
82
+ maxVersions: positiveIntSchema
83
+ .max(400)
84
+ .optional()
85
+ .describe("task=lifecycle only: cap on scanned versions (service default 120, max 400)."),
86
+ includeTimeline: z
87
+ .boolean()
88
+ .optional()
89
+ .describe("task=lifecycle only: include per-version timeline entries."),
90
+ includeSnapshots: z
91
+ .boolean()
92
+ .optional()
93
+ .describe("task=lifecycle only: include snapshot versions in the scan."),
29
94
  sourceMapping: z.enum(["obfuscated", "mojang", "intermediary", "yarn"]).optional(),
30
95
  targetMapping: z.enum(["obfuscated", "mojang", "intermediary", "yarn"]).optional(),
31
96
  classNameMapping: z.enum(["obfuscated", "mojang", "intermediary", "yarn"]).optional(),
32
97
  projectPath: nonEmptyString.optional(),
33
98
  gradleUserHome: nonEmptyString.optional(),
34
99
  signatureMode: z.enum(["exact", "name-only"]).default("exact"),
35
- nameMode: z.enum(["fqcn", "auto"]).default("fqcn"),
100
+ nameMode: z.enum(["fqcn", "auto"]).default("auto"),
36
101
  includeKinds: z.array(z.enum(["class", "field", "method"])).optional(),
37
102
  maxRows: positiveIntSchema.optional(),
38
103
  maxCandidates: positiveIntSchema.default(5),
39
104
  detail: detailSchema.optional(),
40
105
  include: buildIncludeSchema(INCLUDE_GROUPS)
41
106
  };
107
+ const LIFECYCLE_ONLY_FIELDS = [
108
+ "fromVersion",
109
+ "toVersion",
110
+ "maxVersions",
111
+ "includeTimeline",
112
+ "includeSnapshots"
113
+ ];
42
114
  export const analyzeSymbolSchema = z.object(analyzeSymbolShape).superRefine((value, ctx) => {
43
- if (value.task !== "workspace" && !value.version) {
115
+ if (value.task !== "workspace" && value.task !== "lifecycle" && !value.version) {
44
116
  ctx.addIssue({
45
117
  code: z.ZodIssueCode.custom,
46
118
  path: ["version"],
47
119
  message: "version is required for non-workspace tasks."
48
120
  });
49
121
  }
122
+ if (value.task === "lifecycle" && !value.version && !value.toVersion) {
123
+ ctx.addIssue({
124
+ code: z.ZodIssueCode.custom,
125
+ path: ["toVersion"],
126
+ message: "task=lifecycle requires toVersion (or version as a back-compat alias) as the range end."
127
+ });
128
+ }
129
+ if (value.task !== "lifecycle") {
130
+ for (const field of LIFECYCLE_ONLY_FIELDS) {
131
+ if (value[field] !== undefined) {
132
+ ctx.addIssue({
133
+ code: z.ZodIssueCode.custom,
134
+ path: [field],
135
+ message: `${field} is only supported for task=lifecycle.`
136
+ });
137
+ }
138
+ }
139
+ }
50
140
  if (value.task === "workspace" && !value.projectPath) {
51
141
  ctx.addIssue({
52
142
  code: z.ZodIssueCode.custom,
@@ -54,11 +144,13 @@ export const analyzeSymbolSchema = z.object(analyzeSymbolShape).superRefine((val
54
144
  message: "projectPath is required for task=workspace."
55
145
  });
56
146
  }
57
- if (value.task === "api-overview" && value.subject.kind !== "class") {
147
+ if (value.task === "api-overview" &&
148
+ value.subject.kind !== "class" &&
149
+ value.subject.kind !== "symbol") {
58
150
  ctx.addIssue({
59
151
  code: z.ZodIssueCode.custom,
60
152
  path: ["subject", "kind"],
61
- message: "task=api-overview requires subject.kind=class."
153
+ message: "task=api-overview requires subject.kind=class (or 'symbol', which infers class)."
62
154
  });
63
155
  }
64
156
  if (value.task === "api-overview" && value.subject.owner) {
@@ -96,9 +188,7 @@ export class AnalyzeSymbolService {
96
188
  async execute(input) {
97
189
  const detail = resolveDetail(input.detail);
98
190
  const include = resolveInclude(input.include);
99
- const subjectKind = input.subject.kind === "symbol"
100
- ? "class"
101
- : input.subject.kind;
191
+ const { kind: subjectKind, warning: inferenceWarning } = inferSubjectKind(input.subject);
102
192
  switch (input.task) {
103
193
  case "exists": {
104
194
  const output = await this.deps.checkSymbolExists({
@@ -125,7 +215,7 @@ export class AnalyzeSymbolService {
125
215
  : `The symbol could not be resolved in ${output.mappingContext.version}.`,
126
216
  subject: createSummarySubject({
127
217
  task: "exists",
128
- kind: input.subject.kind,
218
+ kind: subjectKind,
129
219
  name: input.subject.name,
130
220
  owner: input.subject.owner,
131
221
  descriptor: input.subject.descriptor,
@@ -138,11 +228,11 @@ export class AnalyzeSymbolService {
138
228
  },
139
229
  blocks: {
140
230
  match: output.resolvedSymbol ?? output.querySymbol,
141
- candidates: output.candidates,
231
+ ...projectMappingCandidates(output),
142
232
  ambiguity: output.ambiguityReasons ? { reasons: output.ambiguityReasons } : undefined
143
233
  }
144
234
  }),
145
- warnings: output.warnings
235
+ warnings: inferenceWarning ? [inferenceWarning, ...output.warnings] : output.warnings
146
236
  };
147
237
  }
148
238
  case "map": {
@@ -155,6 +245,7 @@ export class AnalyzeSymbolService {
155
245
  sourceMapping: input.sourceMapping ?? "obfuscated",
156
246
  targetMapping: input.targetMapping ?? "mojang",
157
247
  ...(input.gradleUserHome !== undefined ? { gradleUserHome: input.gradleUserHome } : {}),
248
+ nameMode: input.nameMode,
158
249
  signatureMode: input.signatureMode,
159
250
  maxCandidates: input.maxCandidates
160
251
  });
@@ -170,7 +261,7 @@ export class AnalyzeSymbolService {
170
261
  : `Found ${output.candidateCount} candidate mappings.`,
171
262
  subject: createSummarySubject({
172
263
  task: "map",
173
- kind: input.subject.kind,
264
+ kind: subjectKind,
174
265
  name: input.subject.name,
175
266
  owner: input.subject.owner,
176
267
  descriptor: input.subject.descriptor,
@@ -184,11 +275,11 @@ export class AnalyzeSymbolService {
184
275
  },
185
276
  blocks: {
186
277
  match: output.resolvedSymbol,
187
- candidates: output.candidates,
278
+ ...projectMappingCandidates(output),
188
279
  ambiguity: output.ambiguityReasons ? { reasons: output.ambiguityReasons } : undefined
189
280
  }
190
281
  }),
191
- warnings: output.warnings
282
+ warnings: inferenceWarning ? [inferenceWarning, ...output.warnings] : output.warnings
192
283
  };
193
284
  }
194
285
  case "exact-map": {
@@ -220,7 +311,7 @@ export class AnalyzeSymbolService {
220
311
  : "Could not resolve the exact method mapping.",
221
312
  subject: createSummarySubject({
222
313
  task: "exact-map",
223
- kind: input.subject.kind,
314
+ kind: subjectKind,
224
315
  name: input.subject.name,
225
316
  owner: input.subject.owner,
226
317
  descriptor: input.subject.descriptor,
@@ -234,10 +325,10 @@ export class AnalyzeSymbolService {
234
325
  },
235
326
  blocks: {
236
327
  match: output.resolvedSymbol,
237
- candidates: output.candidates
328
+ ...projectMappingCandidates(output)
238
329
  }
239
330
  }),
240
- warnings: output.warnings
331
+ warnings: inferenceWarning ? [inferenceWarning, ...output.warnings] : output.warnings
241
332
  };
242
333
  }
243
334
  case "lifecycle": {
@@ -248,8 +339,11 @@ export class AnalyzeSymbolService {
248
339
  descriptor: input.subject.descriptor,
249
340
  mapping: input.sourceMapping,
250
341
  ...(input.gradleUserHome !== undefined ? { gradleUserHome: input.gradleUserHome } : {}),
251
- toVersion: input.version,
252
- maxVersions: 5
342
+ ...(input.fromVersion !== undefined ? { fromVersion: input.fromVersion } : {}),
343
+ toVersion: input.toVersion ?? input.version,
344
+ ...(input.maxVersions !== undefined ? { maxVersions: input.maxVersions } : {}),
345
+ ...(input.includeSnapshots !== undefined ? { includeSnapshots: input.includeSnapshots } : {}),
346
+ ...(input.includeTimeline !== undefined ? { includeTimeline: input.includeTimeline } : {})
253
347
  });
254
348
  return {
255
349
  ...buildEntryToolResult({
@@ -263,11 +357,11 @@ export class AnalyzeSymbolService {
263
357
  : "The symbol was not found in the scanned version range.",
264
358
  subject: createSummarySubject({
265
359
  task: "lifecycle",
266
- kind: input.subject.kind,
360
+ kind: subjectKind,
267
361
  name: input.subject.name,
268
362
  owner: input.subject.owner,
269
363
  descriptor: input.subject.descriptor,
270
- version: input.version,
364
+ version: input.toVersion ?? input.version,
271
365
  sourceMapping: input.sourceMapping ?? "obfuscated"
272
366
  }),
273
367
  counts: {
@@ -279,7 +373,7 @@ export class AnalyzeSymbolService {
279
373
  timeline: output.timeline
280
374
  }
281
375
  }),
282
- warnings: output.warnings
376
+ warnings: inferenceWarning ? [inferenceWarning, ...output.warnings] : output.warnings
283
377
  };
284
378
  }
285
379
  case "workspace": {
@@ -306,7 +400,7 @@ export class AnalyzeSymbolService {
306
400
  : "Workspace compile mapping could not be detected confidently.",
307
401
  subject: createSummarySubject({
308
402
  task: "workspace",
309
- kind: input.subject.kind,
403
+ kind: subjectKind,
310
404
  name: input.subject.name,
311
405
  owner: input.subject.owner,
312
406
  descriptor: input.subject.descriptor,
@@ -320,11 +414,13 @@ export class AnalyzeSymbolService {
320
414
  },
321
415
  blocks: {
322
416
  match: output.resolvedSymbol,
323
- candidates: output.candidates,
417
+ ...projectMappingCandidates(output),
324
418
  workspace: output.workspaceDetection
325
419
  }
326
420
  }),
327
- warnings: [...output.warnings, ...output.workspaceDetection.warnings]
421
+ warnings: inferenceWarning
422
+ ? [inferenceWarning, ...output.warnings, ...output.workspaceDetection.warnings]
423
+ : [...output.warnings, ...output.workspaceDetection.warnings]
328
424
  };
329
425
  }
330
426
  case "api-overview": {
@@ -347,7 +443,7 @@ export class AnalyzeSymbolService {
347
443
  headline: `Built an API overview for ${output.className}.`,
348
444
  subject: createSummarySubject({
349
445
  task: "api-overview",
350
- kind: input.subject.kind,
446
+ kind: subjectKind,
351
447
  name: input.subject.name,
352
448
  version: input.version,
353
449
  classNameMapping
@@ -371,7 +467,7 @@ export class AnalyzeSymbolService {
371
467
  : undefined
372
468
  }
373
469
  }),
374
- warnings: output.warnings
470
+ warnings: inferenceWarning ? [inferenceWarning, ...output.warnings] : output.warnings
375
471
  };
376
472
  }
377
473
  }
@@ -1,3 +1,4 @@
1
+ import { type ResponseDetailLevel } from "../response-utils.js";
1
2
  import type { GetClassMembersInput, GetClassMembersOutput, ResolveArtifactInput, ResolveArtifactOutput } from "../source-service.js";
2
3
  import type { ArtifactScope, MappingSourcePriority, ResolveArtifactTargetInput, SourceMapping } from "../types.js";
3
4
  import { type BatchOutput } from "./batch-runner.js";
@@ -25,7 +26,8 @@ export type BatchClassMembersInput = {
25
26
  strictVersion?: boolean;
26
27
  concurrency?: number;
27
28
  failFast?: boolean;
28
- compact?: boolean;
29
+ detail?: ResponseDetailLevel;
30
+ include?: readonly string[];
29
31
  entries: readonly BatchClassMembersEntry[];
30
32
  };
31
33
  export declare class BatchClassMembersService {
@@ -1,5 +1,5 @@
1
1
  import { buildSuggestedCall } from "../build-suggested-call.js";
2
- import { compactResponse, compactMembersResponse, TOOL_PRESERVE_PAYLOAD_KEYS } from "../response-utils.js";
2
+ import { projectByDetail } from "../response-utils.js";
3
3
  import { runBatch, splitEntryWarnings } from "./batch-runner.js";
4
4
  export class BatchClassMembersService {
5
5
  deps;
@@ -9,7 +9,8 @@ export class BatchClassMembersService {
9
9
  async execute(input) {
10
10
  const concurrency = input.concurrency ?? 4;
11
11
  const failFast = input.failFast ?? false;
12
- const compact = input.compact ?? true;
12
+ const detail = input.detail ?? "summary";
13
+ const include = new Set(input.include ?? []);
13
14
  return runBatch({
14
15
  entries: input.entries,
15
16
  concurrency,
@@ -53,6 +54,7 @@ export class BatchClassMembersService {
53
54
  includeInherited: entry.includeInherited,
54
55
  memberPattern: entry.memberPattern,
55
56
  maxMembers: entry.maxMembers,
57
+ includeDescriptors: include.has("descriptors"),
56
58
  mapping: input.mapping,
57
59
  sourcePriority: input.sourcePriority,
58
60
  allowDecompile: input.allowDecompile,
@@ -63,16 +65,14 @@ export class BatchClassMembersService {
63
65
  strictVersion: input.strictVersion
64
66
  }));
65
67
  const { result, warnings } = splitEntryWarnings(raw);
66
- const projected = compact
67
- ? compactResponse(compactMembersResponse(result), TOOL_PRESERVE_PAYLOAD_KEYS["get-class-members"])
68
- : result;
68
+ const projected = projectByDetail("get-class-members", result, detail, include);
69
69
  return { result: projected, warnings };
70
70
  },
71
71
  buildErrorSuggestedCall: (entry, sharedArtifact) => {
72
72
  if (!sharedArtifact)
73
73
  return undefined;
74
74
  const params = {
75
- target: { type: "artifact", artifactId: sharedArtifact.artifactId },
75
+ target: { kind: "artifact", artifactId: sharedArtifact.artifactId },
76
76
  className: entry.className
77
77
  };
78
78
  if (entry.access !== undefined)
@@ -1,3 +1,4 @@
1
+ import { type ResponseDetailLevel } from "../response-utils.js";
1
2
  import type { GetClassSourceInput, GetClassSourceOutput, ResolveArtifactInput, ResolveArtifactOutput } from "../source-service.js";
2
3
  import type { ArtifactScope, MappingSourcePriority, ResolveArtifactTargetInput, SourceMapping } from "../types.js";
3
4
  import { type BatchOutput } from "./batch-runner.js";
@@ -23,7 +24,8 @@ export type BatchClassSourceInput = {
23
24
  strictVersion?: boolean;
24
25
  concurrency?: number;
25
26
  failFast?: boolean;
26
- compact?: boolean;
27
+ detail?: ResponseDetailLevel;
28
+ include?: readonly string[];
27
29
  entries: readonly BatchClassSourceEntry[];
28
30
  };
29
31
  export type BatchClassSourceDeps = {
@@ -1,5 +1,5 @@
1
1
  import { buildSuggestedCall } from "../build-suggested-call.js";
2
- import { compactResponse, compactSourceResponse, TOOL_PRESERVE_PAYLOAD_KEYS } from "../response-utils.js";
2
+ import { projectByDetail } from "../response-utils.js";
3
3
  import { runBatch, splitEntryWarnings } from "./batch-runner.js";
4
4
  export class BatchClassSourceService {
5
5
  deps;
@@ -9,7 +9,8 @@ export class BatchClassSourceService {
9
9
  async execute(input) {
10
10
  const concurrency = input.concurrency ?? 4;
11
11
  const failFast = input.failFast ?? false;
12
- const compact = input.compact ?? true;
12
+ const detail = input.detail ?? "summary";
13
+ const include = new Set(input.include ?? []);
13
14
  return runBatch({
14
15
  entries: input.entries,
15
16
  concurrency,
@@ -64,16 +65,14 @@ export class BatchClassSourceService {
64
65
  strictVersion: input.strictVersion
65
66
  }));
66
67
  const { result, warnings } = splitEntryWarnings(raw);
67
- const projected = compact
68
- ? compactResponse(compactSourceResponse(result), TOOL_PRESERVE_PAYLOAD_KEYS["get-class-source"])
69
- : result;
68
+ const projected = projectByDetail("get-class-source", result, detail, include);
70
69
  return { result: projected, warnings };
71
70
  },
72
71
  buildErrorSuggestedCall: (entry, sharedArtifact) => {
73
72
  if (!sharedArtifact)
74
73
  return undefined;
75
74
  const params = {
76
- target: { type: "artifact", artifactId: sharedArtifact.artifactId },
75
+ target: { kind: "artifact", artifactId: sharedArtifact.artifactId },
77
76
  className: entry.className
78
77
  };
79
78
  if (entry.mode !== undefined)
@@ -1,3 +1,4 @@
1
+ import { type ResponseDetailLevel } from "../response-utils.js";
1
2
  import type { FindMappingInput, FindMappingOutput } from "../source-service.js";
2
3
  import type { MappingSourcePriority, SourceMapping } from "../types.js";
3
4
  export type BatchMappingsDeps = {
@@ -26,7 +27,8 @@ export type BatchMappingsInput = {
26
27
  gradleUserHome?: string;
27
28
  concurrency?: number;
28
29
  failFast?: boolean;
29
- compact?: boolean;
30
+ detail?: ResponseDetailLevel;
31
+ include?: readonly string[];
30
32
  entries: readonly BatchMappingsEntry[];
31
33
  };
32
34
  export declare class BatchMappingsService {
@@ -1,5 +1,5 @@
1
1
  import { buildSuggestedCall } from "../build-suggested-call.js";
2
- import { compactResponse, compactMappingResponse } from "../response-utils.js";
2
+ import { projectByDetail } from "../response-utils.js";
3
3
  import { runBatch, splitEntryWarnings } from "./batch-runner.js";
4
4
  export class BatchMappingsService {
5
5
  deps;
@@ -9,7 +9,8 @@ export class BatchMappingsService {
9
9
  async execute(input) {
10
10
  const concurrency = input.concurrency ?? 4;
11
11
  const failFast = input.failFast ?? false;
12
- const compact = input.compact ?? true;
12
+ const detail = input.detail ?? "summary";
13
+ const include = new Set(input.include ?? []);
13
14
  return runBatch({
14
15
  entries: input.entries,
15
16
  concurrency,
@@ -32,9 +33,7 @@ export class BatchMappingsService {
32
33
  maxCandidates: entry.maxCandidates
33
34
  }));
34
35
  const { result, warnings } = splitEntryWarnings(raw);
35
- const projected = compact
36
- ? compactResponse(compactMappingResponse(result))
37
- : result;
36
+ const projected = projectByDetail("find-mapping", result, detail, include);
38
37
  return { result: projected, warnings };
39
38
  },
40
39
  buildErrorSuggestedCall: (entry) => {
@@ -1,3 +1,4 @@
1
+ import { type ResponseDetailLevel } from "../response-utils.js";
1
2
  import type { CheckSymbolExistsInput, CheckSymbolExistsOutput, ResolveArtifactInput, ResolveArtifactOutput } from "../source-service.js";
2
3
  import type { ArtifactScope, MappingSourcePriority, SourceMapping, WorkspaceTargetInput, SourceTargetInput } from "../types.js";
3
4
  export type BatchSymbolExistsDeps = {
@@ -36,7 +37,8 @@ export type BatchSymbolExistsInput = {
36
37
  strictVersion?: boolean;
37
38
  concurrency?: number;
38
39
  failFast?: boolean;
39
- compact?: boolean;
40
+ detail?: ResponseDetailLevel;
41
+ include?: readonly string[];
40
42
  entries: readonly BatchSymbolExistsEntry[];
41
43
  };
42
44
  export declare class BatchSymbolExistsService {
@@ -1,6 +1,6 @@
1
1
  import { buildSuggestedCall } from "../build-suggested-call.js";
2
2
  import { createError, ERROR_CODES } from "../errors.js";
3
- import { compactResponse, compactMappingResponse } from "../response-utils.js";
3
+ import { projectByDetail } from "../response-utils.js";
4
4
  import { runBatch, splitEntryWarnings } from "./batch-runner.js";
5
5
  function deriveMinecraftVersion(resolvedVersion, workspaceVersion) {
6
6
  const candidate = resolvedVersion?.trim() || workspaceVersion?.trim();
@@ -23,7 +23,8 @@ export class BatchSymbolExistsService {
23
23
  async execute(input) {
24
24
  const concurrency = input.concurrency ?? 4;
25
25
  const failFast = input.failFast ?? false;
26
- const compact = input.compact ?? true;
26
+ const detail = input.detail ?? "summary";
27
+ const include = new Set(input.include ?? []);
27
28
  return runBatch({
28
29
  entries: input.entries,
29
30
  concurrency,
@@ -79,9 +80,7 @@ export class BatchSymbolExistsService {
79
80
  projectPath: input.projectPath
80
81
  }));
81
82
  const { result, warnings } = splitEntryWarnings(raw);
82
- const projected = compact
83
- ? compactResponse(compactMappingResponse(result))
84
- : result;
83
+ const projected = projectByDetail("check-symbol-exists", result, detail, include);
85
84
  return { result: projected, warnings };
86
85
  },
87
86
  buildErrorSuggestedCall: (entry, sharedArtifact) => {
@@ -33,16 +33,16 @@ export declare const compareMinecraftShape: {
33
33
  fromVersion: string;
34
34
  toVersion: string;
35
35
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
36
- gradleUserHome?: string | undefined;
37
36
  sourcePriority?: "loom-first" | "maven-first" | undefined;
37
+ gradleUserHome?: string | undefined;
38
38
  }, {
39
39
  kind: "class";
40
40
  className: string;
41
41
  fromVersion: string;
42
42
  toVersion: string;
43
43
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
44
- gradleUserHome?: string | undefined;
45
44
  sourcePriority?: "loom-first" | "maven-first" | undefined;
45
+ gradleUserHome?: string | undefined;
46
46
  }>, z.ZodObject<{
47
47
  kind: z.ZodLiteral<"registry">;
48
48
  fromVersion: z.ZodString;
@@ -97,16 +97,16 @@ export declare const compareMinecraftSchema: z.ZodObject<{
97
97
  fromVersion: string;
98
98
  toVersion: string;
99
99
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
100
- gradleUserHome?: string | undefined;
101
100
  sourcePriority?: "loom-first" | "maven-first" | undefined;
101
+ gradleUserHome?: string | undefined;
102
102
  }, {
103
103
  kind: "class";
104
104
  className: string;
105
105
  fromVersion: string;
106
106
  toVersion: string;
107
107
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
108
- gradleUserHome?: string | undefined;
109
108
  sourcePriority?: "loom-first" | "maven-first" | undefined;
109
+ gradleUserHome?: string | undefined;
110
110
  }>, z.ZodObject<{
111
111
  kind: z.ZodLiteral<"registry">;
112
112
  fromVersion: z.ZodString;
@@ -130,7 +130,6 @@ export declare const compareMinecraftSchema: z.ZodObject<{
130
130
  maxEntriesPerRegistry: z.ZodOptional<z.ZodNumber>;
131
131
  includeFullDiff: z.ZodDefault<z.ZodBoolean>;
132
132
  }, "strip", z.ZodTypeAny, {
133
- maxClassResults: number;
134
133
  subject: {
135
134
  kind: "version-pair";
136
135
  fromVersion: string;
@@ -142,18 +141,19 @@ export declare const compareMinecraftSchema: z.ZodObject<{
142
141
  fromVersion: string;
143
142
  toVersion: string;
144
143
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
145
- gradleUserHome?: string | undefined;
146
144
  sourcePriority?: "loom-first" | "maven-first" | undefined;
145
+ gradleUserHome?: string | undefined;
147
146
  } | {
148
147
  kind: "registry";
149
148
  fromVersion: string;
150
149
  toVersion: string;
151
150
  registry?: string | undefined;
152
151
  };
152
+ maxClassResults: number;
153
153
  includeFullDiff: boolean;
154
154
  limit?: number | undefined;
155
155
  task?: "auto" | "versions" | "class-diff" | "registry-diff" | "migration-overview" | undefined;
156
- detail?: "full" | "summary" | "standard" | undefined;
156
+ detail?: "summary" | "standard" | "full" | undefined;
157
157
  include?: string[] | undefined;
158
158
  maxEntriesPerRegistry?: number | undefined;
159
159
  }, {
@@ -168,8 +168,8 @@ export declare const compareMinecraftSchema: z.ZodObject<{
168
168
  fromVersion: string;
169
169
  toVersion: string;
170
170
  mapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
171
- gradleUserHome?: string | undefined;
172
171
  sourcePriority?: "loom-first" | "maven-first" | undefined;
172
+ gradleUserHome?: string | undefined;
173
173
  } | {
174
174
  kind: "registry";
175
175
  fromVersion: string;
@@ -177,10 +177,10 @@ export declare const compareMinecraftSchema: z.ZodObject<{
177
177
  registry?: string | undefined;
178
178
  };
179
179
  limit?: number | undefined;
180
- maxClassResults?: number | undefined;
181
180
  task?: "auto" | "versions" | "class-diff" | "registry-diff" | "migration-overview" | undefined;
182
- detail?: "full" | "summary" | "standard" | undefined;
181
+ detail?: "summary" | "standard" | "full" | undefined;
183
182
  include?: string[] | undefined;
183
+ maxClassResults?: number | undefined;
184
184
  maxEntriesPerRegistry?: number | undefined;
185
185
  includeFullDiff?: boolean | undefined;
186
186
  }>;
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const detailSchema: z.ZodEnum<["summary", "standard", "full"]>;
3
- export declare const includeGroupSchema: z.ZodEnum<["warnings", "provenance", "candidates", "members", "source", "files", "samples", "diff", "issues", "timeline", "matrix", "entries", "workspace", "health", "recovery", "paths", "owners", "preview", "cacheEntries", "timings", "artifact", "classes", "registry"]>;
3
+ export declare const includeGroupSchema: 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"]>;
4
4
  export declare const executionModeSchema: z.ZodEnum<["preview", "apply"]>;
5
5
  export declare const positiveIntSchema: z.ZodNumber;
6
6
  export declare function buildIncludeSchema(allowed: readonly string[]): z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
@@ -8,8 +8,7 @@ export async function handleArtifact(deps, subject, detail, include) {
8
8
  status: "blocked",
9
9
  headline: "Could not resolve an artifact without a Minecraft version.",
10
10
  subject: createSummarySubject({
11
- task: "artifact",
12
- requested: subject
11
+ task: "artifact"
13
12
  }),
14
13
  nextActions: nextActionsOrUndefined([
15
14
  createNextAction("inspect-minecraft", {
@@ -42,7 +41,6 @@ export async function handleArtifact(deps, subject, detail, include) {
42
41
  headline: `Resolved artifact ${resolved.artifactId}.`,
43
42
  subject: createSummarySubject({
44
43
  task: "artifact",
45
- requested: subject,
46
44
  artifactId: resolved.artifactId,
47
45
  version: resolved.version
48
46
  }),
@@ -15,14 +15,14 @@ export async function handleClassMembers(deps, subject, detail, include, limit)
15
15
  gradleUserHome: classSubject.gradleUserHome,
16
16
  preferProjectVersion: classSubject.preferProjectVersion,
17
17
  strictVersion: classSubject.strictVersion,
18
- maxMembers: limit
18
+ maxMembers: limit,
19
+ includeDescriptors: include.includes("descriptors")
19
20
  });
20
21
  const summary = {
21
22
  status: members.truncated ? "partial" : "ok",
22
23
  headline: `Collected ${members.counts.total} members for ${members.className}.`,
23
24
  subject: createSummarySubject({
24
25
  task: "class-members",
25
- requested: subject,
26
26
  className: members.className,
27
27
  artifactId: members.artifactId
28
28
  }),