@adhisang/minecraft-modding-mcp 6.1.1 → 6.3.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 (56) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/README.md +12 -4
  3. package/dist/cache-registry.d.ts +1 -1
  4. package/dist/cache-registry.js +3 -0
  5. package/dist/entry-tools/analyze-mod-service.d.ts +12 -6
  6. package/dist/entry-tools/analyze-mod-service.js +37 -3
  7. package/dist/entry-tools/analyze-symbol-service.d.ts +6 -4
  8. package/dist/entry-tools/analyze-symbol-service.js +37 -2
  9. package/dist/entry-tools/inspect-minecraft/internal.d.ts +7 -3
  10. package/dist/entry-tools/inspect-minecraft/internal.js +43 -15
  11. package/dist/entry-tools/inspect-minecraft-service.d.ts +12 -12
  12. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  13. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  14. package/dist/error-mapping.d.ts +13 -0
  15. package/dist/error-mapping.js +35 -2
  16. package/dist/errors.d.ts +2 -0
  17. package/dist/errors.js +2 -0
  18. package/dist/index.js +39 -20
  19. package/dist/mapping/internal-types.d.ts +7 -0
  20. package/dist/mapping/types.d.ts +18 -0
  21. package/dist/mapping-service.js +16 -3
  22. package/dist/minecraft-explorer-service.d.ts +4 -0
  23. package/dist/minecraft-explorer-service.js +156 -17
  24. package/dist/mod-analyzer.d.ts +7 -0
  25. package/dist/mod-analyzer.js +28 -7
  26. package/dist/source/artifact-resolver.d.ts +2 -0
  27. package/dist/source/artifact-resolver.js +24 -1
  28. package/dist/source/class-source/members-builder.d.ts +4 -0
  29. package/dist/source/class-source/members-builder.js +3 -1
  30. package/dist/source/class-source.d.ts +3 -1
  31. package/dist/source/class-source.js +192 -19
  32. package/dist/source/did-you-mean.d.ts +14 -0
  33. package/dist/source/did-you-mean.js +79 -0
  34. package/dist/source/file-access.js +159 -3
  35. package/dist/source/indexer.js +72 -2
  36. package/dist/source/lifecycle/runtime-check.js +9 -5
  37. package/dist/source/nested-jars.d.ts +78 -0
  38. package/dist/source/nested-jars.js +267 -0
  39. package/dist/source/workspace-target.js +5 -2
  40. package/dist/source-jar-reader.d.ts +16 -0
  41. package/dist/source-jar-reader.js +82 -0
  42. package/dist/source-service.d.ts +37 -0
  43. package/dist/source-service.js +52 -6
  44. package/dist/stage-emitter.js +24 -8
  45. package/dist/stdio-supervisor.d.ts +92 -9
  46. package/dist/stdio-supervisor.js +915 -103
  47. package/dist/tool-contract-manifest.js +2 -2
  48. package/dist/tool-guidance.js +115 -7
  49. package/dist/tool-schemas.d.ts +1343 -149
  50. package/dist/tool-schemas.js +39 -7
  51. package/dist/types.d.ts +23 -0
  52. package/dist/workspace-mapping-service.d.ts +1 -0
  53. package/dist/workspace-mapping-service.js +120 -8
  54. package/docs/README-ja.md +4 -0
  55. package/docs/tool-reference.md +92 -6
  56. package/package.json +5 -5
@@ -158,6 +158,7 @@ export declare const inspectMinecraftShape: {
158
158
  scope?: "vanilla" | "merged" | "loader" | undefined;
159
159
  preferProjectVersion?: boolean | undefined;
160
160
  strictVersion?: boolean | undefined;
161
+ gradleUserHome?: string | undefined;
161
162
  artifact?: {
162
163
  artifactId: string;
163
164
  type: "resolved-id";
@@ -168,7 +169,6 @@ export declare const inspectMinecraftShape: {
168
169
  };
169
170
  type: "resolve-target";
170
171
  } | undefined;
171
- gradleUserHome?: string | undefined;
172
172
  }, {
173
173
  kind: "class";
174
174
  className: string;
@@ -177,6 +177,7 @@ export declare const inspectMinecraftShape: {
177
177
  scope?: "vanilla" | "merged" | "loader" | undefined;
178
178
  preferProjectVersion?: boolean | undefined;
179
179
  strictVersion?: boolean | undefined;
180
+ gradleUserHome?: string | undefined;
180
181
  artifact?: {
181
182
  artifactId: string;
182
183
  type: "resolved-id";
@@ -187,7 +188,6 @@ export declare const inspectMinecraftShape: {
187
188
  };
188
189
  type: "resolve-target";
189
190
  } | undefined;
190
- gradleUserHome?: string | undefined;
191
191
  }>, z.ZodObject<{
192
192
  kind: z.ZodLiteral<"file">;
193
193
  filePath: z.ZodString;
@@ -821,6 +821,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
821
821
  scope?: "vanilla" | "merged" | "loader" | undefined;
822
822
  preferProjectVersion?: boolean | undefined;
823
823
  strictVersion?: boolean | undefined;
824
+ gradleUserHome?: string | undefined;
824
825
  artifact?: {
825
826
  artifactId: string;
826
827
  type: "resolved-id";
@@ -831,7 +832,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
831
832
  };
832
833
  type: "resolve-target";
833
834
  } | undefined;
834
- gradleUserHome?: string | undefined;
835
835
  }, {
836
836
  kind: "class";
837
837
  className: string;
@@ -840,6 +840,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
840
840
  scope?: "vanilla" | "merged" | "loader" | undefined;
841
841
  preferProjectVersion?: boolean | undefined;
842
842
  strictVersion?: boolean | undefined;
843
+ gradleUserHome?: string | undefined;
843
844
  artifact?: {
844
845
  artifactId: string;
845
846
  type: "resolved-id";
@@ -850,7 +851,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
850
851
  };
851
852
  type: "resolve-target";
852
853
  } | undefined;
853
- gradleUserHome?: string | undefined;
854
854
  }>, z.ZodObject<{
855
855
  kind: z.ZodLiteral<"file">;
856
856
  filePath: z.ZodString;
@@ -1329,7 +1329,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1329
1329
  includeSnapshots: boolean;
1330
1330
  limit?: number | undefined;
1331
1331
  cursor?: string | undefined;
1332
- task?: "search" | "class-source" | "artifact" | "auto" | "file" | "versions" | "class-members" | "class-overview" | "list-files" | undefined;
1332
+ task?: "search" | "class-source" | "file" | "auto" | "class-overview" | "class-members" | "artifact" | "versions" | "list-files" | undefined;
1333
1333
  detail?: "summary" | "standard" | "full" | undefined;
1334
1334
  subject?: {
1335
1335
  kind: "version";
@@ -1366,6 +1366,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1366
1366
  scope?: "vanilla" | "merged" | "loader" | undefined;
1367
1367
  preferProjectVersion?: boolean | undefined;
1368
1368
  strictVersion?: boolean | undefined;
1369
+ gradleUserHome?: string | undefined;
1369
1370
  artifact?: {
1370
1371
  artifactId: string;
1371
1372
  type: "resolved-id";
@@ -1376,7 +1377,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1376
1377
  };
1377
1378
  type: "resolve-target";
1378
1379
  } | undefined;
1379
- gradleUserHome?: string | undefined;
1380
1380
  } | {
1381
1381
  kind: "file";
1382
1382
  filePath: string;
@@ -1468,7 +1468,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1468
1468
  }, {
1469
1469
  limit?: number | undefined;
1470
1470
  cursor?: string | undefined;
1471
- task?: "search" | "class-source" | "artifact" | "auto" | "file" | "versions" | "class-members" | "class-overview" | "list-files" | undefined;
1471
+ task?: "search" | "class-source" | "file" | "auto" | "class-overview" | "class-members" | "artifact" | "versions" | "list-files" | undefined;
1472
1472
  detail?: "summary" | "standard" | "full" | undefined;
1473
1473
  subject?: {
1474
1474
  kind: "version";
@@ -1505,6 +1505,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1505
1505
  scope?: "vanilla" | "merged" | "loader" | undefined;
1506
1506
  preferProjectVersion?: boolean | undefined;
1507
1507
  strictVersion?: boolean | undefined;
1508
+ gradleUserHome?: string | undefined;
1508
1509
  artifact?: {
1509
1510
  artifactId: string;
1510
1511
  type: "resolved-id";
@@ -1515,7 +1516,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1515
1516
  };
1516
1517
  type: "resolve-target";
1517
1518
  } | undefined;
1518
- gradleUserHome?: string | undefined;
1519
1519
  } | {
1520
1520
  kind: "file";
1521
1521
  filePath: string;
@@ -1609,7 +1609,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1609
1609
  includeSnapshots: boolean;
1610
1610
  limit?: number | undefined;
1611
1611
  cursor?: string | undefined;
1612
- task?: "search" | "class-source" | "artifact" | "auto" | "file" | "versions" | "class-members" | "class-overview" | "list-files" | undefined;
1612
+ task?: "search" | "class-source" | "file" | "auto" | "class-overview" | "class-members" | "artifact" | "versions" | "list-files" | undefined;
1613
1613
  detail?: "summary" | "standard" | "full" | undefined;
1614
1614
  subject?: {
1615
1615
  kind: "version";
@@ -1646,6 +1646,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1646
1646
  scope?: "vanilla" | "merged" | "loader" | undefined;
1647
1647
  preferProjectVersion?: boolean | undefined;
1648
1648
  strictVersion?: boolean | undefined;
1649
+ gradleUserHome?: string | undefined;
1649
1650
  artifact?: {
1650
1651
  artifactId: string;
1651
1652
  type: "resolved-id";
@@ -1656,7 +1657,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1656
1657
  };
1657
1658
  type: "resolve-target";
1658
1659
  } | undefined;
1659
- gradleUserHome?: string | undefined;
1660
1660
  } | {
1661
1661
  kind: "file";
1662
1662
  filePath: string;
@@ -1748,7 +1748,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1748
1748
  }, {
1749
1749
  limit?: number | undefined;
1750
1750
  cursor?: string | undefined;
1751
- task?: "search" | "class-source" | "artifact" | "auto" | "file" | "versions" | "class-members" | "class-overview" | "list-files" | undefined;
1751
+ task?: "search" | "class-source" | "file" | "auto" | "class-overview" | "class-members" | "artifact" | "versions" | "list-files" | undefined;
1752
1752
  detail?: "summary" | "standard" | "full" | undefined;
1753
1753
  subject?: {
1754
1754
  kind: "version";
@@ -1785,6 +1785,7 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1785
1785
  scope?: "vanilla" | "merged" | "loader" | undefined;
1786
1786
  preferProjectVersion?: boolean | undefined;
1787
1787
  strictVersion?: boolean | undefined;
1788
+ gradleUserHome?: string | undefined;
1788
1789
  artifact?: {
1789
1790
  artifactId: string;
1790
1791
  type: "resolved-id";
@@ -1795,7 +1796,6 @@ export declare const inspectMinecraftSchema: z.ZodEffects<z.ZodObject<{
1795
1796
  };
1796
1797
  type: "resolve-target";
1797
1798
  } | undefined;
1798
- gradleUserHome?: string | undefined;
1799
1799
  } | {
1800
1800
  kind: "file";
1801
1801
  filePath: string;
@@ -14,7 +14,7 @@ import { handleListFiles } from "./inspect-minecraft/handlers/list-files.js";
14
14
  const INCLUDE_GROUPS = ["warnings", "provenance", "candidates", "members", "descriptors", "source", "files", "samples", "artifact", "timings"];
15
15
  const nonEmptyString = z.string().trim().min(1);
16
16
  export const inspectMinecraftShape = {
17
- task: z.enum(TASKS).optional(),
17
+ task: z.enum(TASKS).optional().describe("Workflow task. auto dispatches only from subject.kind and workspace focus.kind; it is not a natural-language planner."),
18
18
  subject: subjectSchema.optional(),
19
19
  includeSnapshots: z.boolean().default(false),
20
20
  detail: detailSchema.optional(),
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import { type CacheRegistry } from "../cache-registry.js";
3
3
  export declare const manageCacheShape: {
4
4
  action: z.ZodEnum<["summary", "list", "inspect", "delete", "prune", "rebuild", "verify"]>;
5
- cacheKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap", "workspace"]>, "many">>;
5
+ cacheKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap", "nested-jar", "workspace"]>, "many">>;
6
6
  selector: z.ZodOptional<z.ZodObject<{
7
7
  artifactId: z.ZodOptional<z.ZodString>;
8
8
  version: z.ZodOptional<z.ZodString>;
@@ -42,7 +42,7 @@ export declare const manageCacheShape: {
42
42
  };
43
43
  export declare const manageCacheSchema: z.ZodObject<{
44
44
  action: z.ZodEnum<["summary", "list", "inspect", "delete", "prune", "rebuild", "verify"]>;
45
- cacheKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap", "workspace"]>, "many">>;
45
+ cacheKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap", "nested-jar", "workspace"]>, "many">>;
46
46
  selector: z.ZodOptional<z.ZodObject<{
47
47
  artifactId: z.ZodOptional<z.ZodString>;
48
48
  version: z.ZodOptional<z.ZodString>;
@@ -86,7 +86,7 @@ export declare const manageCacheSchema: z.ZodObject<{
86
86
  cursor?: string | undefined;
87
87
  detail?: "summary" | "standard" | "full" | undefined;
88
88
  include?: string[] | undefined;
89
- cacheKinds?: ("workspace" | "artifact-index" | "downloads" | "mapping" | "registry" | "decompiled-source" | "mod-remap" | "binary-remap")[] | undefined;
89
+ cacheKinds?: ("workspace" | "artifact-index" | "downloads" | "mapping" | "registry" | "decompiled-source" | "mod-remap" | "binary-remap" | "nested-jar")[] | undefined;
90
90
  selector?: {
91
91
  version?: string | undefined;
92
92
  projectPath?: string | undefined;
@@ -105,7 +105,7 @@ export declare const manageCacheSchema: z.ZodObject<{
105
105
  detail?: "summary" | "standard" | "full" | undefined;
106
106
  include?: string[] | undefined;
107
107
  executionMode?: "preview" | "apply" | undefined;
108
- cacheKinds?: ("workspace" | "artifact-index" | "downloads" | "mapping" | "registry" | "decompiled-source" | "mod-remap" | "binary-remap")[] | undefined;
108
+ cacheKinds?: ("workspace" | "artifact-index" | "downloads" | "mapping" | "registry" | "decompiled-source" | "mod-remap" | "binary-remap" | "nested-jar")[] | undefined;
109
109
  selector?: {
110
110
  version?: string | undefined;
111
111
  projectPath?: string | undefined;
@@ -38,6 +38,10 @@ export type RetryClass = "transient" | "permanent" | "server" | "environment" |
38
38
  * - `environment`: a server capability is missing (Java, decompiler, remapper).
39
39
  */
40
40
  export type IssueOrigin = "code_issue" | "tool_issue" | "environment";
41
+ export type DidYouMeanCandidate = {
42
+ className: string;
43
+ matchReason: string;
44
+ };
41
45
  export type ProblemDetails = {
42
46
  type: string;
43
47
  title: string;
@@ -51,9 +55,18 @@ export type ProblemDetails = {
51
55
  hints?: string[];
52
56
  suggestedCall?: SuggestedCall;
53
57
  exampleCalls?: ExampleCall[];
58
+ /** Ranked near-miss candidates for a class/symbol that was not found. */
59
+ didYouMean?: DidYouMeanCandidate[];
54
60
  failedStage?: string;
55
61
  context?: Record<string, string | number | boolean>;
56
62
  };
63
+ /**
64
+ * Validates and extracts a `didYouMean` array from error details. Like
65
+ * `suggestedCall`, it travels as a dedicated typed field — the primitive-only
66
+ * context allowlist is not loosened for it. Malformed payloads are dropped
67
+ * whole rather than partially published.
68
+ */
69
+ export declare function extractDidYouMean(details: unknown): DidYouMeanCandidate[] | undefined;
57
70
  export declare function statusForErrorCode(code: string): number;
58
71
  /**
59
72
  * Single source of truth mapping an error code to its {@link RetryClass}. Used
@@ -1,5 +1,30 @@
1
1
  import { ERROR_CODES, isAppError } from "./errors.js";
2
2
  import { log } from "./logger.js";
3
+ const MAX_DID_YOU_MEAN_ENTRIES = 16;
4
+ /**
5
+ * Validates and extracts a `didYouMean` array from error details. Like
6
+ * `suggestedCall`, it travels as a dedicated typed field — the primitive-only
7
+ * context allowlist is not loosened for it. Malformed payloads are dropped
8
+ * whole rather than partially published.
9
+ */
10
+ export function extractDidYouMean(details) {
11
+ const raw = details?.didYouMean;
12
+ if (!Array.isArray(raw)) {
13
+ return undefined;
14
+ }
15
+ const cleaned = [];
16
+ for (const entry of raw) {
17
+ if (!entry || typeof entry !== "object") {
18
+ return undefined;
19
+ }
20
+ const { className, matchReason } = entry;
21
+ if (typeof className !== "string" || typeof matchReason !== "string") {
22
+ return undefined;
23
+ }
24
+ cleaned.push({ className, matchReason });
25
+ }
26
+ return cleaned.slice(0, MAX_DID_YOU_MEAN_ENTRIES);
27
+ }
3
28
  export function statusForErrorCode(code) {
4
29
  if (code === ERROR_CODES.BATCH_ABORTED) {
5
30
  return 412;
@@ -9,6 +34,9 @@ export function statusForErrorCode(code) {
9
34
  // not an internal server failure.
10
35
  return 408;
11
36
  }
37
+ if (code === ERROR_CODES.TOOL_TIMEOUT) {
38
+ return 408;
39
+ }
12
40
  if (code === ERROR_CODES.INVALID_INPUT ||
13
41
  code === ERROR_CODES.COORDINATE_PARSE_FAILED ||
14
42
  code === ERROR_CODES.INVALID_LINE_RANGE ||
@@ -35,7 +63,8 @@ export function statusForErrorCode(code) {
35
63
  code === ERROR_CODES.DECOMPILE_DISABLED ||
36
64
  code === ERROR_CODES.REMAP_FAILED ||
37
65
  code === ERROR_CODES.WORKSPACE_VERSION_UNRESOLVED ||
38
- code === ERROR_CODES.DEPENDENCY_VERSION_UNRESOLVED) {
66
+ code === ERROR_CODES.DEPENDENCY_VERSION_UNRESOLVED ||
67
+ code === ERROR_CODES.NESTED_JAR_AMBIGUOUS) {
39
68
  return 422;
40
69
  }
41
70
  if (code === ERROR_CODES.REMAPPER_UNAVAILABLE ||
@@ -82,6 +111,7 @@ const RETRY_CLASS_PERMANENT = new Set([
82
111
  ERROR_CODES.REMAP_FAILED,
83
112
  ERROR_CODES.WORKSPACE_VERSION_UNRESOLVED,
84
113
  ERROR_CODES.DEPENDENCY_VERSION_UNRESOLVED,
114
+ ERROR_CODES.NESTED_JAR_AMBIGUOUS,
85
115
  ERROR_CODES.PROVENANCE_INCOMPLETE,
86
116
  ERROR_CODES.BATCH_ABORTED
87
117
  ]);
@@ -145,7 +175,8 @@ const ISSUE_ORIGIN_CODE = new Set([
145
175
  ERROR_CODES.JAR_NOT_FOUND,
146
176
  ERROR_CODES.VERSION_NOT_FOUND,
147
177
  ERROR_CODES.WORKSPACE_VERSION_UNRESOLVED,
148
- ERROR_CODES.DEPENDENCY_VERSION_UNRESOLVED
178
+ ERROR_CODES.DEPENDENCY_VERSION_UNRESOLVED,
179
+ ERROR_CODES.NESTED_JAR_AMBIGUOUS
149
180
  ]);
150
181
  /**
151
182
  * Single source of truth mapping an error code to its {@link IssueOrigin}.
@@ -243,6 +274,7 @@ export function errorToBatchEntryProblem(caughtError, instance, options) {
243
274
  const baseHints = extractHints(caughtError.details);
244
275
  const fieldErrors = extractFieldErrors(caughtError.details);
245
276
  const context = extractAllowlistedContext(caughtError.details);
277
+ const didYouMean = extractDidYouMean(caughtError.details);
246
278
  return {
247
279
  type: `https://minecraft-modding-mcp.dev/problems/${caughtError.code.toLowerCase()}`,
248
280
  title: "Tool execution error",
@@ -255,6 +287,7 @@ export function errorToBatchEntryProblem(caughtError, instance, options) {
255
287
  ...(fieldErrors ? { fieldErrors } : {}),
256
288
  ...(baseHints ? { hints: baseHints } : {}),
257
289
  ...(options?.suggestedCall ? { suggestedCall: options.suggestedCall } : {}),
290
+ ...(didYouMean ? { didYouMean } : {}),
258
291
  ...(context ? { context } : {})
259
292
  };
260
293
  }
package/dist/errors.d.ts CHANGED
@@ -31,10 +31,12 @@ export declare const ERROR_CODES: {
31
31
  readonly REMAP_FAILED: "ERR_REMAP_FAILED";
32
32
  readonly REMAPPER_UNAVAILABLE: "ERR_REMAPPER_UNAVAILABLE";
33
33
  readonly WORKER_RESTART: "ERR_WORKER_RESTART";
34
+ readonly TOOL_TIMEOUT: "ERR_TOOL_TIMEOUT";
34
35
  readonly MIXIN_PARSE_FAILED: "ERR_MIXIN_PARSE_FAILED";
35
36
  readonly STAGE_BUDGET_PRE_PARSE: "ERR_STAGE_BUDGET_PRE_PARSE";
36
37
  readonly WORKSPACE_VERSION_UNRESOLVED: "ERR_WORKSPACE_VERSION_UNRESOLVED";
37
38
  readonly DEPENDENCY_VERSION_UNRESOLVED: "ERR_DEPENDENCY_VERSION_UNRESOLVED";
39
+ readonly NESTED_JAR_AMBIGUOUS: "ERR_NESTED_JAR_AMBIGUOUS";
38
40
  readonly BATCH_ABORTED: "ERR_BATCH_ABORTED";
39
41
  readonly INTERNAL: "ERR_INTERNAL";
40
42
  };
package/dist/errors.js CHANGED
@@ -31,10 +31,12 @@ export const ERROR_CODES = {
31
31
  REMAP_FAILED: "ERR_REMAP_FAILED",
32
32
  REMAPPER_UNAVAILABLE: "ERR_REMAPPER_UNAVAILABLE",
33
33
  WORKER_RESTART: "ERR_WORKER_RESTART",
34
+ TOOL_TIMEOUT: "ERR_TOOL_TIMEOUT",
34
35
  MIXIN_PARSE_FAILED: "ERR_MIXIN_PARSE_FAILED",
35
36
  STAGE_BUDGET_PRE_PARSE: "ERR_STAGE_BUDGET_PRE_PARSE",
36
37
  WORKSPACE_VERSION_UNRESOLVED: "ERR_WORKSPACE_VERSION_UNRESOLVED",
37
38
  DEPENDENCY_VERSION_UNRESOLVED: "ERR_DEPENDENCY_VERSION_UNRESOLVED",
39
+ NESTED_JAR_AMBIGUOUS: "ERR_NESTED_JAR_AMBIGUOUS",
38
40
  BATCH_ABORTED: "ERR_BATCH_ABORTED",
39
41
  INTERNAL: "ERR_INTERNAL"
40
42
  };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { makeStageEmitter } from "./stage-emitter.js";
4
- import { ZodError, z } from "zod";
4
+ import { ZodError } from "zod";
5
5
  import { CompatStdioServerTransport } from "./compat-stdio-transport.js";
6
6
  import { objectResult } from "./mcp-helpers.js";
7
7
  import { prepareToolInput } from "./tool-input.js";
@@ -34,7 +34,7 @@ import { buildEntryToolMeta } from "./entry-tools/response-contract.js";
34
34
  import { registerToolSchema } from "./tool-schema-registry.js";
35
35
  import { buildSuggestedCall } from "./build-suggested-call.js";
36
36
  import { applyErrorMetaExtensions, mapErrorToProblem } from "./tool-guidance.js";
37
- import { nonEmptyString, optionalPositiveInt, analyzeModJarSchema, analyzeModJarShape, batchClassMembersSchema, batchClassMembersShape, batchClassSourceSchema, batchClassSourceShape, batchMappingsSchema, batchMappingsShape, batchSymbolExistsSchema, batchSymbolExistsShape, checkSymbolExistsSchema, checkSymbolExistsShape, compareVersionsSchema, compareVersionsShape, decompileModJarSchema, decompileModJarShape, diffClassSignaturesSchema, diffClassSignaturesShape, emptySchema, findMappingSchema, findMappingShape, getArtifactFileSchema, getArtifactFileShape, getClassApiMatrixSchema, getClassApiMatrixShape, getClassMembersSchema, getClassMembersShape, getClassSourceSchema, getClassSourceShape, getModClassSourceSchema, getModClassSourceShape, getRegistryDataSchema, getRegistryDataShape, indexArtifactSchema, indexArtifactShape, jsonToNbtSchema, jsonToNbtShape, listArtifactFilesSchema, listArtifactFilesShape, listVersionsSchema, listVersionsShape, nbtApplyJsonPatchSchema, nbtApplyJsonPatchShape, nbtToJsonSchema, nbtToJsonShape, remapModJarSchema, remapModJarShape, resolveArtifactSchema, resolveArtifactShape, resolveMethodMappingExactSchema, resolveMethodMappingExactShape, resolveWorkspaceSymbolSchema, resolveWorkspaceSymbolShape, searchClassSourceSchema, searchClassSourceShape, searchModSourceSchema, searchModSourceShape, traceSymbolLifecycleSchema, traceSymbolLifecycleShape, validateAccessTransformerSchema, validateAccessTransformerShape, validateAccessWidenerSchema, validateAccessWidenerShape, validateMixinSchema, validateMixinShape, verifyMixinTargetSchema, verifyMixinTargetShape } from "./tool-schemas.js";
37
+ import { analyzeModJarSchema, analyzeModJarShape, batchClassMembersSchema, batchClassMembersShape, batchClassSourceSchema, batchClassSourceShape, batchMappingsSchema, batchMappingsShape, batchSymbolExistsSchema, batchSymbolExistsShape, checkSymbolExistsSchema, checkSymbolExistsShape, compareVersionsSchema, compareVersionsShape, decompileModJarSchema, decompileModJarShape, diffClassSignaturesSchema, diffClassSignaturesShape, emptySchema, findMappingSchema, findMappingShape, getArtifactFileSchema, getArtifactFileShape, getClassApiMatrixSchema, getClassApiMatrixShape, getClassMembersSchema, getClassMembersShape, getClassSourceSchema, getClassSourceShape, getModClassSourceSchema, getModClassSourceShape, getRegistryDataSchema, getRegistryDataShape, indexArtifactSchema, indexArtifactShape, jsonToNbtSchema, jsonToNbtShape, listArtifactFilesSchema, listArtifactFilesShape, listVersionsSchema, listVersionsShape, nbtApplyJsonPatchSchema, nbtApplyJsonPatchShape, nbtToJsonSchema, nbtToJsonShape, remapModJarSchema, remapModJarShape, resolveArtifactSchema, resolveArtifactShape, resolveMethodMappingExactSchema, resolveMethodMappingExactShape, resolveWorkspaceSymbolSchema, resolveWorkspaceSymbolShape, searchClassSourceSchema, searchClassSourceShape, searchModSourceSchema, searchModSourceShape, traceSymbolLifecycleSchema, traceSymbolLifecycleShape, validateAccessTransformerSchema, validateAccessTransformerShape, validateAccessWidenerSchema, validateAccessWidenerShape, validateMixinSchema, validateMixinShape, verifyMixinTargetSchema, verifyMixinTargetShape, findClassShape, findClassSchema } from "./tool-schemas.js";
38
38
  export { mapErrorToProblem, applyErrorMetaExtensions };
39
39
  if (!process.env.NODE_ENV) {
40
40
  process.env.NODE_ENV = "production";
@@ -114,16 +114,18 @@ const workspaceMappingService = new WorkspaceMappingService();
114
114
  const inspectMinecraftService = new InspectMinecraftService({
115
115
  listVersions: (input) => sourceService.listVersions(input),
116
116
  resolveArtifact: (input) => sourceService.resolveArtifact(input),
117
- findClass: (input) => Promise.resolve(sourceService.findClass(input)),
117
+ findClass: (input) => sourceService.findClassIncludingNested(input),
118
118
  checkSymbolExists: (input) => sourceService.checkSymbolExists(input),
119
119
  getClassSource: (input) => sourceService.getClassSource(input),
120
120
  getClassMembers: (input) => sourceService.getClassMembers(input),
121
121
  searchClassSource: (input) => sourceService.searchClassSource(input),
122
122
  getArtifactFile: (input) => sourceService.getArtifactFile(input),
123
123
  listArtifactFiles: (input) => sourceService.listArtifactFiles(input),
124
- detectProjectMinecraftVersion: (projectPath) => workspaceMappingService.detectProjectMinecraftVersion(projectPath)
124
+ detectProjectMinecraftVersion: (projectPath) => workspaceMappingService.detectProjectMinecraftVersion(projectPath),
125
+ listWorkspaceContexts: () => sourceService.workspaceContextCache.list()
125
126
  });
126
127
  const analyzeSymbolService = new AnalyzeSymbolService({
128
+ detectProjectMinecraftVersion: (projectPath) => workspaceMappingService.detectProjectMinecraftVersion(projectPath),
127
129
  checkSymbolExists: (input) => sourceService.checkSymbolExists(input),
128
130
  findMapping: (input) => sourceService.findMapping(input),
129
131
  resolveMethodMappingExact: (input) => sourceService.resolveMethodMappingExact(input),
@@ -141,7 +143,8 @@ const analyzeModService = new AnalyzeModService({
141
143
  decompileModJar: (input) => sourceService.decompileModJar(input),
142
144
  getModClassSource: (input) => sourceService.getModClassSource(input),
143
145
  searchModSource: (input) => sourceService.searchModSource(input),
144
- remapModJar: (input) => remapModJar(input, config)
146
+ remapModJar: (input) => remapModJar(input, config),
147
+ getModClassMembers: (input) => sourceService.getModClassMembers(input)
145
148
  });
146
149
  const validateProjectService = new ValidateProjectService({
147
150
  validateMixin: (input, options) => sourceService.validateMixin(input, options),
@@ -469,13 +472,13 @@ expertTool("list-versions", "List available Minecraft versions from Mojang manif
469
472
  limit: input.limit
470
473
  })));
471
474
  registerToolSchema("list-versions", listVersionsSchema);
472
- server.tool("inspect-minecraft", "Top-level workflow tool for version discovery, artifact resolution, class inspection, source search, file reads, and file listings.", inspectMinecraftShape, { readOnlyHint: true }, async (args) => runTool("inspect-minecraft", args, inspectMinecraftSchema, async (input) => inspectMinecraftService.execute(input)));
475
+ server.tool("inspect-minecraft", "Top-level workflow tool for version discovery, artifact resolution, class inspection, source search, file reads, and file listings. Workspace subject.focus is a structured class/file/search object, never a string; task=auto dispatches from subject.kind and focus.kind.", inspectMinecraftShape, { readOnlyHint: true }, async (args) => runTool("inspect-minecraft", args, inspectMinecraftSchema, async (input) => inspectMinecraftService.execute(input)));
473
476
  registerToolSchema("inspect-minecraft", inspectMinecraftSchema);
474
477
  server.tool("analyze-symbol", "Top-level workflow tool for symbol existence, mapping, lifecycle, workspace analysis, and API overview. subject.kind='symbol' auto-detects class/field/method from the selector.", analyzeSymbolShape, { readOnlyHint: true }, async (args) => runTool("analyze-symbol", args, analyzeSymbolSchema, async (input) => analyzeSymbolService.execute(input)));
475
478
  registerToolSchema("analyze-symbol", analyzeSymbolSchema);
476
479
  server.tool("compare-minecraft", "Top-level workflow tool for version comparisons, class diffs, registry diffs, and migration overviews.", compareMinecraftShape, { readOnlyHint: true }, async (args) => runTool("compare-minecraft", args, compareMinecraftSchema, async (input) => compareMinecraftService.execute(input)));
477
480
  registerToolSchema("compare-minecraft", compareMinecraftSchema);
478
- server.tool("analyze-mod", "Top-level workflow tool for mod metadata inspection, decompile/search flows, class source, and safe remap previews/applies.", analyzeModShape, { readOnlyHint: false }, async (args) => runTool("analyze-mod", args, analyzeModSchema, async (input) => analyzeModService.execute(input)));
481
+ server.tool("analyze-mod", "Top-level workflow tool for mod metadata inspection, decompile/search flows, class source, bytecode-only class member reads, and safe remap previews/applies.", analyzeModShape, { readOnlyHint: false }, async (args) => runTool("analyze-mod", args, analyzeModSchema, async (input) => analyzeModService.execute(input)));
479
482
  registerToolSchema("analyze-mod", analyzeModSchema);
480
483
  server.tool("validate-project", "Top-level workflow tool for project summary, direct mixin validation, and access widener/access transformer validation.", validateProjectShape, { readOnlyHint: true }, async (args, extra) => runTool("validate-project", args, validateProjectSchema, async (input) => validateProjectService.execute(input, {
481
484
  stageEmitter: makeStageEmitter(extra)
@@ -524,15 +527,31 @@ expertTool("resolve-artifact", "Resolve a source artifact and return artifact me
524
527
  (Array.isArray(input.include) && input.include.includes("samples"))
525
528
  })));
526
529
  registerToolSchema("resolve-artifact", resolveArtifactSchema);
527
- const findClassShape = {
528
- className: nonEmptyString.describe("Simple name (e.g. Blocks) or fully-qualified name (e.g. net.minecraft.world.level.block.Blocks)"),
529
- artifactId: nonEmptyString,
530
- limit: optionalPositiveInt.describe("default 20, max 200")
531
- };
532
- const findClassSchema = z.object(findClassShape);
533
- expertTool("find-class", "Resolve a simple or qualified class name to fully-qualified class names within an artifact. Use this before get-class-source when you only have a simple name.", findClassShape, { readOnlyHint: true }, async (args) => runTool("find-class", args, findClassSchema, async (input) => sourceService.findClass({
530
+ // Flat tools accept `target` as an additive alternative to `artifactId`
531
+ // (mutually exclusive, enforced by each schema). A target is resolved to its
532
+ // artifactId here before the underlying artifactId-based service call.
533
+ async function resolveFlatArtifactId(input) {
534
+ if (input.artifactId) {
535
+ return input.artifactId;
536
+ }
537
+ const target = input.target;
538
+ // {kind:"artifact"} reuses an already-resolved artifact without a resolve
539
+ // round-trip. Workspace-context kinds carry their own projectPath when the
540
+ // target shape provides one; kinds that require workspace context beyond
541
+ // that fail with the resolver's own projectPath guidance.
542
+ if (target?.kind === "artifact" && target.artifactId) {
543
+ return target.artifactId;
544
+ }
545
+ const projectPath = input.projectPath ?? target?.projectPath;
546
+ const resolved = await sourceService.resolveArtifact({
547
+ target: target,
548
+ ...(projectPath ? { projectPath } : {})
549
+ });
550
+ return resolved.artifactId;
551
+ }
552
+ expertTool("find-class", "Resolve a simple or qualified class name to fully-qualified class names within an artifact. Use this before get-class-source when you only have a simple name.", findClassShape, { readOnlyHint: true }, async (args) => runTool("find-class", args, findClassSchema, async (input) => sourceService.findClassIncludingNested({
534
553
  className: input.className,
535
- artifactId: input.artifactId,
554
+ artifactId: await resolveFlatArtifactId(input),
536
555
  limit: input.limit
537
556
  })));
538
557
  registerToolSchema("find-class", findClassSchema);
@@ -596,7 +615,7 @@ expertTool("search-class-source", "Search indexed class source files for one art
596
615
  }
597
616
  : undefined;
598
617
  return sourceService.searchClassSource({
599
- artifactId: input.artifactId,
618
+ artifactId: await resolveFlatArtifactId(input),
600
619
  query: input.query,
601
620
  intent: input.intent,
602
621
  match: input.match,
@@ -611,13 +630,13 @@ expertTool("search-class-source", "Search indexed class source files for one art
611
630
  }));
612
631
  registerToolSchema("search-class-source", searchClassSourceSchema);
613
632
  expertTool("get-artifact-file", "Get full source file content by artifactId and file path.", getArtifactFileShape, { readOnlyHint: true }, async (args) => runTool("get-artifact-file", args, getArtifactFileSchema, async (input) => sourceService.getArtifactFile({
614
- artifactId: input.artifactId,
633
+ artifactId: await resolveFlatArtifactId(input),
615
634
  filePath: input.filePath,
616
635
  maxBytes: input.maxBytes
617
636
  })));
618
637
  registerToolSchema("get-artifact-file", getArtifactFileSchema);
619
638
  expertTool("list-artifact-files", "List source file paths in an artifact with optional prefix filter and cursor-based pagination.", listArtifactFilesShape, { readOnlyHint: true }, async (args) => runTool("list-artifact-files", args, listArtifactFilesSchema, async (input) => sourceService.listArtifactFiles({
620
- artifactId: input.artifactId,
639
+ artifactId: await resolveFlatArtifactId(input),
621
640
  prefix: input.prefix,
622
641
  limit: input.limit,
623
642
  cursor: input.cursor
@@ -727,8 +746,8 @@ server.tool("json-to-nbt", "Encode typed NBT JSON to Java Edition NBT binary pay
727
746
  compression: input.compression
728
747
  }, nbtLimits))));
729
748
  registerToolSchema("json-to-nbt", jsonToNbtSchema);
730
- expertTool("index-artifact", "Rebuild indexed files/symbols metadata for an existing artifactId. Does not resolve new artifacts.", indexArtifactShape, { readOnlyHint: false, idempotentHint: true }, async (args) => runTool("index-artifact", args, indexArtifactSchema, async (input) => sourceService.indexArtifact({
731
- artifactId: input.artifactId,
749
+ expertTool("index-artifact", "Rebuild indexed files/symbols metadata for an artifact addressed by artifactId or target. A new target is resolved and ingested first; force rebuilds an existing index.", indexArtifactShape, { readOnlyHint: false, idempotentHint: true }, async (args) => runTool("index-artifact", args, indexArtifactSchema, async (input) => sourceService.indexArtifact({
750
+ artifactId: await resolveFlatArtifactId(input),
732
751
  force: input.force
733
752
  })));
734
753
  registerToolSchema("index-artifact", indexArtifactSchema);
@@ -56,6 +56,13 @@ export type CandidateAccumulator = {
56
56
  };
57
57
  export type LoadedGraph = {
58
58
  version: string;
59
+ /**
60
+ * True when the runtime already uses deobfuscated names, so the graph is
61
+ * deliberately empty. Surfaces on outputs as
62
+ * mappingContext.unobfuscatedRuntime instead of a per-response warning
63
+ * sentence.
64
+ */
65
+ unobfuscatedRuntime?: boolean;
59
66
  priority: import("../types.js").MappingSourcePriority;
60
67
  mode: GraphLoadMode;
61
68
  pairs: Map<PairKey, PairRecord>;
@@ -38,6 +38,19 @@ export type SymbolResolutionOutput = {
38
38
  sourceMapping: SourceMapping;
39
39
  targetMapping?: SourceMapping;
40
40
  sourcePriorityApplied: MappingSourcePriority;
41
+ /**
42
+ * The runtime already uses deobfuscated names, so the mapping graph is
43
+ * deliberately empty. Replaces the former per-response warning
44
+ * "Version X is unobfuscated; mapping graph is empty because the runtime
45
+ * already uses deobfuscated names."
46
+ */
47
+ unobfuscatedRuntime?: boolean;
48
+ /**
49
+ * Symbol existence was validated against runtime bytecode. Replaces the
50
+ * former per-response warning "Version X is unobfuscated; validated
51
+ * symbol existence against runtime bytecode."
52
+ */
53
+ runtimeValidated?: boolean;
41
54
  };
42
55
  resolved: boolean;
43
56
  status: SymbolResolutionStatus;
@@ -122,6 +135,11 @@ export type ClassApiMatrixRow = {
122
135
  completeness: boolean;
123
136
  };
124
137
  export type ClassApiMatrixOutput = {
138
+ /**
139
+ * The runtime already uses deobfuscated names, so non-mojang matrix
140
+ * columns are empty by design (the mapping graph is deliberately empty).
141
+ */
142
+ unobfuscatedRuntime?: boolean;
125
143
  version: string;
126
144
  className: string;
127
145
  classNameMapping: SourceMapping;
@@ -126,6 +126,9 @@ export class MappingService {
126
126
  };
127
127
  }
128
128
  const graph = await this.loadGraph(version, priority, requiresOnlyObfuscatedMojangGraph(sourceMapping, targetMapping) ? "obfuscated-mojang-only" : "full", input.projectPath, input.gradleUserHome);
129
+ if (graph.unobfuscatedRuntime) {
130
+ mappingContext.unobfuscatedRuntime = true;
131
+ }
129
132
  const path = namespacePath(graph, sourceMapping, targetMapping);
130
133
  if (!path) {
131
134
  return {
@@ -352,6 +355,9 @@ export class MappingService {
352
355
  };
353
356
  }
354
357
  const graph = await this.loadGraph(version, priority, requiresOnlyObfuscatedMojangGraph(sourceMapping, targetMapping) ? "obfuscated-mojang-only" : "full", input.projectPath, input.gradleUserHome);
358
+ if (graph.unobfuscatedRuntime) {
359
+ mappingContext.unobfuscatedRuntime = true;
360
+ }
355
361
  const path = namespacePath(graph, sourceMapping, targetMapping);
356
362
  if (!path) {
357
363
  return {
@@ -469,6 +475,7 @@ export class MappingService {
469
475
  const priority = mappingPriorityFromInput(this.config.mappingSourcePriority, input.sourcePriority);
470
476
  const graph = await this.loadGraph(version, priority, "full", undefined, input.gradleUserHome);
471
477
  const warnings = [...graph.warnings];
478
+ const unobfuscatedRuntime = graph.unobfuscatedRuntime === true;
472
479
  const includeKinds = normalizeIncludedKinds(input.includeKinds);
473
480
  const pathCache = new Map();
474
481
  const resolvePath = (sourceMapping, targetMapping) => {
@@ -514,6 +521,7 @@ export class MappingService {
514
521
  },
515
522
  rows: [],
516
523
  rowCount: 0,
524
+ ...(unobfuscatedRuntime ? { unobfuscatedRuntime: true } : {}),
517
525
  warnings
518
526
  };
519
527
  }
@@ -638,6 +646,7 @@ export class MappingService {
638
646
  version,
639
647
  className,
640
648
  classNameMapping,
649
+ ...(unobfuscatedRuntime ? { unobfuscatedRuntime: true } : {}),
641
650
  classIdentity: {
642
651
  obfuscated: classByMapping.obfuscated?.symbol,
643
652
  mojang: classByMapping.mojang?.symbol,
@@ -727,6 +736,9 @@ export class MappingService {
727
736
  };
728
737
  })();
729
738
  const graph = await this.loadGraph(version, priority, sourceMapping === "mojang" ? "obfuscated-mojang-only" : "full", undefined, input.gradleUserHome);
739
+ if (graph.unobfuscatedRuntime) {
740
+ mappingContext.unobfuscatedRuntime = true;
741
+ }
730
742
  const warnings = [...graph.warnings];
731
743
  const records = collectTargetRecords(graph, sourceMapping);
732
744
  if (records.length === 0) {
@@ -1115,9 +1127,10 @@ export class MappingService {
1115
1127
  recordsByTarget: new Map(),
1116
1128
  exactRecordIndex: new Map(),
1117
1129
  classProjectionCache: new Map(),
1118
- warnings: [
1119
- `Version ${version} is unobfuscated; mapping graph is empty because the runtime already uses deobfuscated names.`
1120
- ]
1130
+ // No warning sentence: consumers surface this as the structured
1131
+ // mappingContext.unobfuscatedRuntime flag instead.
1132
+ unobfuscatedRuntime: true,
1133
+ warnings: []
1121
1134
  };
1122
1135
  }
1123
1136
  const graph = {
@@ -15,6 +15,10 @@ export interface SignatureMember {
15
15
  jvmDescriptor: string;
16
16
  accessFlags: number;
17
17
  isSynthetic: boolean;
18
+ /** Rendered default value of an annotation-type member (AnnotationDefault). */
19
+ annotationDefault?: string;
20
+ /** Rendered runtime-visible annotations on the member, e.g. "@java.lang.Deprecated". */
21
+ annotations?: string[];
18
22
  }
19
23
  export interface GetSignatureInput {
20
24
  fqn: string;