@adhisang/minecraft-modding-mcp 6.2.0 → 7.0.0-rc.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 (98) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +21 -5
  3. package/dist/cache-policy.d.ts +71 -0
  4. package/dist/cache-policy.js +83 -0
  5. package/dist/cache-registry.js +6 -6
  6. package/dist/cli.js +74 -3
  7. package/dist/compat-stdio-transport.d.ts +1 -1
  8. package/dist/compat-stdio-transport.js +13 -1
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.js +8 -2
  11. package/dist/decompiler/vineflower.d.ts +1 -0
  12. package/dist/decompiler/vineflower.js +8 -5
  13. package/dist/entry-tools/analyze-mod-service.d.ts +70 -136
  14. package/dist/entry-tools/analyze-symbol-service.d.ts +112 -150
  15. package/dist/entry-tools/compare-minecraft-service.d.ts +59 -145
  16. package/dist/entry-tools/entry-tool-schema.d.ts +38 -4
  17. package/dist/entry-tools/entry-tool-schema.js +4 -1
  18. package/dist/entry-tools/inspect-minecraft/internal.d.ts +235 -799
  19. package/dist/entry-tools/inspect-minecraft/internal.js +65 -28
  20. package/dist/entry-tools/inspect-minecraft-service.d.ts +372 -1736
  21. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  22. package/dist/entry-tools/manage-cache-service.d.ts +81 -91
  23. package/dist/entry-tools/validate-project/cases/project-summary.d.ts +7 -7
  24. package/dist/entry-tools/validate-project-service.d.ts +164 -592
  25. package/dist/entry-tools/verify-mixin-target-service.d.ts +3 -19
  26. package/dist/era-classifier.d.ts +161 -0
  27. package/dist/era-classifier.js +292 -0
  28. package/dist/error-mapping.js +9 -2
  29. package/dist/index.d.ts +42 -4
  30. package/dist/index.js +637 -475
  31. package/dist/java-process.d.ts +2 -0
  32. package/dist/java-process.js +22 -2
  33. package/dist/json-rpc-framing.d.ts +77 -1
  34. package/dist/json-rpc-framing.js +249 -13
  35. package/dist/mapping/loaders/tiny-loom-selection.d.ts +88 -0
  36. package/dist/mapping/loaders/tiny-loom-selection.js +223 -0
  37. package/dist/mapping/loaders/tiny-loom.js +45 -33
  38. package/dist/mapping/loaders/tiny-maven.js +6 -11
  39. package/dist/mapping/parsers/tiny.d.ts +57 -0
  40. package/dist/mapping/parsers/tiny.js +99 -22
  41. package/dist/mapping-service.d.ts +19 -0
  42. package/dist/mapping-service.js +93 -9
  43. package/dist/mcp-helpers.d.ts +19 -2
  44. package/dist/mcp-helpers.js +48 -6
  45. package/dist/minecraft-explorer-service.d.ts +1 -1
  46. package/dist/mixin/types.d.ts +8 -0
  47. package/dist/mod-analyzer.js +7 -7
  48. package/dist/mod-decompile-service.js +1 -0
  49. package/dist/nbt/java-nbt-codec.js +12 -2
  50. package/dist/nbt/json-patch.js +14 -3
  51. package/dist/nbt/pipeline.js +40 -3
  52. package/dist/nbt/typed-json.js +26 -1
  53. package/dist/registration-adapter.d.ts +32 -0
  54. package/dist/registration-adapter.js +52 -0
  55. package/dist/request-context.d.ts +7 -0
  56. package/dist/request-context.js +9 -0
  57. package/dist/resources.d.ts +1 -1
  58. package/dist/resources.js +25 -19
  59. package/dist/server-identity.d.ts +27 -0
  60. package/dist/server-identity.js +26 -0
  61. package/dist/source/access-validate.js +53 -0
  62. package/dist/source/artifact-resolver.d.ts +69 -1
  63. package/dist/source/artifact-resolver.js +215 -14
  64. package/dist/source/class-source.d.ts +22 -0
  65. package/dist/source/class-source.js +162 -29
  66. package/dist/source/did-you-mean.d.ts +12 -1
  67. package/dist/source/did-you-mean.js +6 -2
  68. package/dist/source/file-access.js +150 -46
  69. package/dist/source/indexer.js +1 -0
  70. package/dist/source/nested-jars.d.ts +19 -0
  71. package/dist/source/nested-jars.js +90 -21
  72. package/dist/source/shared-utils.d.ts +21 -0
  73. package/dist/source/shared-utils.js +23 -0
  74. package/dist/source-service.d.ts +12 -0
  75. package/dist/source-service.js +3 -0
  76. package/dist/stdio-supervisor.d.ts +357 -2
  77. package/dist/stdio-supervisor.js +1031 -80
  78. package/dist/storage/db.d.ts +2 -1
  79. package/dist/storage/db.js +15 -8
  80. package/dist/synthetic-decorator.d.ts +24 -0
  81. package/dist/synthetic-decorator.js +48 -0
  82. package/dist/tool-contract-manifest.js +1 -1
  83. package/dist/tool-guidance.d.ts +17 -1
  84. package/dist/tool-guidance.js +417 -13
  85. package/dist/tool-schema-registry.d.ts +2 -0
  86. package/dist/tool-schema-registry.js +4 -0
  87. package/dist/tool-schemas.d.ts +2214 -3915
  88. package/dist/tool-schemas.js +34 -7
  89. package/dist/types.d.ts +35 -0
  90. package/dist/v1-parity-schemas.d.ts +7 -0
  91. package/dist/v1-parity-schemas.js +5584 -0
  92. package/dist/version-diff-service.d.ts +33 -0
  93. package/dist/version-diff-service.js +148 -3
  94. package/dist/version-service.js +36 -14
  95. package/dist/warning-details.js +18 -1
  96. package/docs/README-ja.md +9 -3
  97. package/docs/tool-reference.md +267 -22
  98. package/package.json +12 -9
@@ -4,6 +4,7 @@ import { dirname, join } from "node:path";
4
4
  import { buildSuggestedCall } from "../build-suggested-call.js";
5
5
  import { ERROR_CODES, createError } from "../errors.js";
6
6
  import { collectNestedJars } from "../mod-analyzer.js";
7
+ import { isSecureJarEntryPath } from "../path-resolver.js";
7
8
  import { listJarEntries, readJarEntryAsBuffer, readJarEntryAsUtf8 } from "../source-jar-reader.js";
8
9
  /**
9
10
  * A jar with at most this many own `.class` entries can qualify as a
@@ -29,6 +30,84 @@ function rememberClassSet(key, value) {
29
30
  classSetCache.delete(oldest);
30
31
  }
31
32
  }
33
+ async function loadNestedJarClassSet(args) {
34
+ let extractedPath;
35
+ try {
36
+ extractedPath = await extractNestedJar(args.cacheDir, args.outerJarPath, args.outerSignature, args.entryName);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ let classSet = classSetCache.get(extractedPath);
42
+ if (!classSet) {
43
+ try {
44
+ const entries = await listJarEntries(extractedPath);
45
+ classSet = new Set(entries.filter((entry) => entry.endsWith(".class") && isSecureJarEntryPath(entry)));
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ rememberClassSet(extractedPath, classSet);
51
+ }
52
+ return { extractedPath, classSet };
53
+ }
54
+ function nestedClassMatch(entry) {
55
+ const internalName = entry.slice(0, -".class".length);
56
+ if (internalName.startsWith("META-INF/versions/")) {
57
+ return undefined;
58
+ }
59
+ const binarySimpleName = internalName.split("/").at(-1) ?? internalName;
60
+ if (binarySimpleName === "module-info" || binarySimpleName === "package-info") {
61
+ return undefined;
62
+ }
63
+ const innerSegments = binarySimpleName.split("$").slice(1);
64
+ if (innerSegments.some((segment) => segment.length === 0 || /^\d/.test(segment))) {
65
+ return undefined;
66
+ }
67
+ return {
68
+ qualifiedName: internalName.replaceAll("/", ".").replaceAll("$", "."),
69
+ filePath: `${internalName.split("$")[0]}.java`,
70
+ line: 1,
71
+ symbolKind: "class"
72
+ };
73
+ }
74
+ /**
75
+ * Finds exact class-name matches across a shell's nested bytecode inventory.
76
+ * Results use the same binary-backed class representation as entry-tool search:
77
+ * an inferred outer Java path, line 1, and the broad class symbol kind.
78
+ */
79
+ export async function findNestedJarClasses(args) {
80
+ const normalizedQuery = args.className.trim().replaceAll("/", ".").replaceAll("$", ".");
81
+ const isQualified = normalizedQuery.includes(".");
82
+ const matches = new Map();
83
+ inventory: for (const entryName of args.inventory) {
84
+ const loaded = await loadNestedJarClassSet({
85
+ cacheDir: args.cacheDir,
86
+ outerJarPath: args.outerJarPath,
87
+ outerSignature: args.outerSignature,
88
+ entryName
89
+ });
90
+ if (!loaded) {
91
+ continue;
92
+ }
93
+ for (const classEntry of [...loaded.classSet].sort((left, right) => left.localeCompare(right))) {
94
+ const match = nestedClassMatch(classEntry);
95
+ if (!match) {
96
+ continue;
97
+ }
98
+ const simpleName = match.qualifiedName.split(".").at(-1) ?? match.qualifiedName;
99
+ if ((isQualified && match.qualifiedName !== normalizedQuery) ||
100
+ (!isQualified && simpleName !== normalizedQuery)) {
101
+ continue;
102
+ }
103
+ matches.set(match.qualifiedName, match);
104
+ if (isQualified || matches.size >= args.limit) {
105
+ break inventory;
106
+ }
107
+ }
108
+ }
109
+ return [...matches.values()];
110
+ }
32
111
  /**
33
112
  * Shell detection with both required signals: near-zero own classes AND
34
113
  * bundled nested jars (META-INF/jars scan or fabric.mod.json "jars"
@@ -128,29 +207,19 @@ export async function extractNestedJar(cacheDir, outerJarPath, outerSignature, e
128
207
  */
129
208
  export async function findNestedJarsContainingClass(args) {
130
209
  const classEntry = `${args.internalName}.class`;
210
+ const qualifiedName = args.internalName.replaceAll("/", ".").replaceAll("$", ".");
131
211
  const matches = [];
132
212
  for (const entryName of args.inventory) {
133
- let extractedPath;
134
- try {
135
- extractedPath = await extractNestedJar(args.cacheDir, args.outerJarPath, args.outerSignature, entryName);
136
- }
137
- catch {
138
- // Unsafe or unreadable nested entries never become candidates.
139
- continue;
140
- }
141
- let classSet = classSetCache.get(extractedPath);
142
- if (!classSet) {
143
- try {
144
- const entries = await listJarEntries(extractedPath);
145
- classSet = new Set(entries.filter((entry) => entry.endsWith(".class")));
146
- }
147
- catch {
148
- continue;
149
- }
150
- rememberClassSet(extractedPath, classSet);
151
- }
152
- if (classSet.has(classEntry)) {
153
- matches.push({ entryName, extractedPath });
213
+ const loaded = await loadNestedJarClassSet({
214
+ cacheDir: args.cacheDir,
215
+ outerJarPath: args.outerJarPath,
216
+ outerSignature: args.outerSignature,
217
+ entryName
218
+ });
219
+ const containsClass = loaded?.classSet.has(classEntry) || [...(loaded?.classSet ?? [])].some((entry) => entry.endsWith(".class") &&
220
+ entry.slice(0, -".class".length).replaceAll("/", ".").replaceAll("$", ".") === qualifiedName);
221
+ if (loaded && containsClass) {
222
+ matches.push({ entryName, extractedPath: loaded.extractedPath });
154
223
  }
155
224
  }
156
225
  return matches;
@@ -2,5 +2,26 @@ import type { SourceMapping } from "../types.js";
2
2
  export declare function normalizePathStyle(path: string): string;
3
3
  export declare function normalizeOptionalString(value: string | undefined): string | undefined;
4
4
  export declare function normalizeMapping(mapping: SourceMapping | undefined): SourceMapping;
5
+ /**
6
+ * The mapping an artifact-targeted call runs in when the caller left `mapping`
7
+ * out.
8
+ *
9
+ * A stored artifact already carries the namespace it was resolved into, so a
10
+ * follow-up call that names it by `artifactId` must inherit that namespace
11
+ * instead of falling back to the version-target default ("obfuscated").
12
+ * Without this, `find-class` -> `get-class-source` -> `get-class-members`
13
+ * split across two namespaces: source came back in mojang names while members
14
+ * came back obfuscated (`ownerFqn: "dlp"`), for the same artifact and the same
15
+ * absent `mapping` argument.
16
+ *
17
+ * `requestedMapping` wins over `mappingApplied` so the echoed request keeps
18
+ * meaning "what was asked for" even on artifacts where the mapping could not
19
+ * be applied; `mappingApplied` is the fallback for rows stored before the
20
+ * requested namespace was persisted.
21
+ */
22
+ export declare function inheritArtifactMapping(inputMapping: SourceMapping | undefined, artifact: {
23
+ requestedMapping?: SourceMapping;
24
+ mappingApplied?: SourceMapping;
25
+ }): SourceMapping;
5
26
  export declare function pathExists(filePath: string): Promise<boolean>;
6
27
  export declare function dedupeQualityFlags(qualityFlags: readonly string[]): string[];
@@ -31,6 +31,29 @@ export function normalizeMapping(mapping) {
31
31
  }
32
32
  });
33
33
  }
34
+ /**
35
+ * The mapping an artifact-targeted call runs in when the caller left `mapping`
36
+ * out.
37
+ *
38
+ * A stored artifact already carries the namespace it was resolved into, so a
39
+ * follow-up call that names it by `artifactId` must inherit that namespace
40
+ * instead of falling back to the version-target default ("obfuscated").
41
+ * Without this, `find-class` -> `get-class-source` -> `get-class-members`
42
+ * split across two namespaces: source came back in mojang names while members
43
+ * came back obfuscated (`ownerFqn: "dlp"`), for the same artifact and the same
44
+ * absent `mapping` argument.
45
+ *
46
+ * `requestedMapping` wins over `mappingApplied` so the echoed request keeps
47
+ * meaning "what was asked for" even on artifacts where the mapping could not
48
+ * be applied; `mappingApplied` is the fallback for rows stored before the
49
+ * requested namespace was persisted.
50
+ */
51
+ export function inheritArtifactMapping(inputMapping, artifact) {
52
+ if (inputMapping != null) {
53
+ return normalizeMapping(inputMapping);
54
+ }
55
+ return artifact.requestedMapping ?? artifact.mappingApplied ?? normalizeMapping(undefined);
56
+ }
34
57
  export async function pathExists(filePath) {
35
58
  try {
36
59
  await access(filePath);
@@ -268,11 +268,20 @@ export type FindClassMatch = {
268
268
  filePath: string;
269
269
  line: number;
270
270
  symbolKind: string;
271
+ /** Set when the match is a type declared INSIDE another type. */
272
+ nested?: boolean;
273
+ /** The enclosing top-level type, present only on a nested match. */
274
+ enclosingClass?: string;
271
275
  };
272
276
  export type FindClassOutput = {
273
277
  matches: FindClassMatch[];
274
278
  total: number;
275
279
  warnings: string[];
280
+ /** Recovery route when the index legitimately cannot answer (partial coverage). */
281
+ suggestedCall?: {
282
+ tool: string;
283
+ params: Record<string, unknown>;
284
+ };
276
285
  };
277
286
  type MemberAccess = "public" | "all";
278
287
  export type GetClassMembersInput = {
@@ -638,6 +647,7 @@ export declare class SourceService {
638
647
  requestedScope: ArtifactScope;
639
648
  atNamespace: AccessTransformerNamespace;
640
649
  loader: import("./workspace-mapping-service.js").WorkspaceProjectLoader | "unknown";
650
+ projectMinecraftVersion?: string;
641
651
  }): ReturnType<typeof artifactResolver.discoverAccessTransformerRuntimeCandidates>;
642
652
  buildMappingFallbackSuggestedCall(args: {
643
653
  input: ResolveArtifactInput;
@@ -670,6 +680,7 @@ export declare class SourceService {
670
680
  traceSymbolLifecycle(input: TraceSymbolLifecycleInput): Promise<TraceSymbolLifecycleOutput>;
671
681
  diffClassSignatures(input: DiffClassSignaturesInput): Promise<DiffClassSignaturesOutput>;
672
682
  findClass(input: FindClassInput): FindClassOutput;
683
+ findClassIncludingNested(input: FindClassInput): Promise<FindClassOutput>;
673
684
  getClassSource(input: GetClassSourceInput): Promise<GetClassSourceOutput>;
674
685
  getClassMembers(input: GetClassMembersInput): Promise<GetClassMembersOutput>;
675
686
  validateMixin(input: ValidateMixinInput, options?: ValidateMixinOptions): Promise<ValidateMixinOutput>;
@@ -701,6 +712,7 @@ export declare class SourceService {
701
712
  mappingApplied: SourceMapping;
702
713
  provenance?: ArtifactProvenance;
703
714
  qualityFlags: string[];
715
+ allowDecompile?: boolean;
704
716
  }): Promise<ResolvedSourceArtifact | undefined>;
705
717
  getArtifact(artifactId: string): ArtifactRow;
706
718
  ingestIfNeeded(resolved: ResolvedSourceArtifact): Promise<void>;
@@ -215,6 +215,9 @@ export class SourceService {
215
215
  findClass(input) {
216
216
  return classSource.findClass(this, input);
217
217
  }
218
+ async findClassIncludingNested(input) {
219
+ return classSource.findClassIncludingNested(this, input);
220
+ }
218
221
  async getClassSource(input) {
219
222
  return classSource.getClassSource(this, input);
220
223
  }