@adhisang/minecraft-modding-mcp 2.1.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +224 -802
  3. package/dist/cache-registry.d.ts +95 -0
  4. package/dist/cache-registry.js +541 -0
  5. package/dist/entry-tools/analyze-mod-service.d.ts +207 -0
  6. package/dist/entry-tools/analyze-mod-service.js +309 -0
  7. package/dist/entry-tools/analyze-symbol-service.d.ts +209 -0
  8. package/dist/entry-tools/analyze-symbol-service.js +359 -0
  9. package/dist/entry-tools/compare-minecraft-service.d.ts +210 -0
  10. package/dist/entry-tools/compare-minecraft-service.js +429 -0
  11. package/dist/entry-tools/entry-tool-schema.d.ts +6 -0
  12. package/dist/entry-tools/entry-tool-schema.js +10 -0
  13. package/dist/entry-tools/inspect-minecraft-service.d.ts +1954 -0
  14. package/dist/entry-tools/inspect-minecraft-service.js +1030 -0
  15. package/dist/entry-tools/manage-cache-service.d.ts +130 -0
  16. package/dist/entry-tools/manage-cache-service.js +264 -0
  17. package/dist/entry-tools/request-normalizers.d.ts +10 -0
  18. package/dist/entry-tools/request-normalizers.js +36 -0
  19. package/dist/entry-tools/response-contract.d.ts +45 -0
  20. package/dist/entry-tools/response-contract.js +99 -0
  21. package/dist/entry-tools/validate-project-service.d.ts +543 -0
  22. package/dist/entry-tools/validate-project-service.js +414 -0
  23. package/dist/index.js +183 -59
  24. package/dist/observability.d.ts +18 -2
  25. package/dist/observability.js +47 -10
  26. package/dist/source-service.d.ts +0 -1
  27. package/dist/source-service.js +44 -54
  28. package/dist/storage/files-repo.d.ts +1 -0
  29. package/dist/storage/files-repo.js +29 -5
  30. package/dist/tool-contract-manifest.d.ts +4 -0
  31. package/dist/tool-contract-manifest.js +139 -0
  32. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ import type { AnalyzeModOptions, ModAnalysisResult } from "../mod-analyzer.js";
2
+ import { z } from "zod";
3
+ export declare const analyzeModShape: {
4
+ task: z.ZodEnum<["summary", "decompile", "search", "class-source", "remap"]>;
5
+ subject: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
6
+ kind: z.ZodLiteral<"jar">;
7
+ jarPath: z.ZodString;
8
+ }, "strip", z.ZodTypeAny, {
9
+ kind: "jar";
10
+ jarPath: string;
11
+ }, {
12
+ kind: "jar";
13
+ jarPath: string;
14
+ }>, z.ZodObject<{
15
+ kind: z.ZodLiteral<"class">;
16
+ jarPath: z.ZodString;
17
+ className: z.ZodString;
18
+ }, "strip", z.ZodTypeAny, {
19
+ kind: "class";
20
+ jarPath: string;
21
+ className: string;
22
+ }, {
23
+ kind: "class";
24
+ jarPath: string;
25
+ className: string;
26
+ }>]>;
27
+ query: z.ZodOptional<z.ZodString>;
28
+ searchType: z.ZodDefault<z.ZodEnum<["class", "method", "field", "content", "all"]>>;
29
+ limit: z.ZodDefault<z.ZodNumber>;
30
+ includeFiles: z.ZodDefault<z.ZodBoolean>;
31
+ maxFiles: z.ZodOptional<z.ZodNumber>;
32
+ maxLines: z.ZodOptional<z.ZodNumber>;
33
+ maxChars: z.ZodOptional<z.ZodNumber>;
34
+ targetMapping: z.ZodOptional<z.ZodEnum<["yarn", "mojang"]>>;
35
+ outputJar: z.ZodOptional<z.ZodString>;
36
+ executionMode: z.ZodDefault<z.ZodEnum<["preview", "apply"]>>;
37
+ detail: z.ZodOptional<z.ZodEnum<["summary", "standard", "full"]>>;
38
+ include: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
39
+ };
40
+ export declare const analyzeModSchema: z.ZodEffects<z.ZodObject<{
41
+ task: z.ZodEnum<["summary", "decompile", "search", "class-source", "remap"]>;
42
+ subject: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
43
+ kind: z.ZodLiteral<"jar">;
44
+ jarPath: z.ZodString;
45
+ }, "strip", z.ZodTypeAny, {
46
+ kind: "jar";
47
+ jarPath: string;
48
+ }, {
49
+ kind: "jar";
50
+ jarPath: string;
51
+ }>, z.ZodObject<{
52
+ kind: z.ZodLiteral<"class">;
53
+ jarPath: z.ZodString;
54
+ className: z.ZodString;
55
+ }, "strip", z.ZodTypeAny, {
56
+ kind: "class";
57
+ jarPath: string;
58
+ className: string;
59
+ }, {
60
+ kind: "class";
61
+ jarPath: string;
62
+ className: string;
63
+ }>]>;
64
+ query: z.ZodOptional<z.ZodString>;
65
+ searchType: z.ZodDefault<z.ZodEnum<["class", "method", "field", "content", "all"]>>;
66
+ limit: z.ZodDefault<z.ZodNumber>;
67
+ includeFiles: z.ZodDefault<z.ZodBoolean>;
68
+ maxFiles: z.ZodOptional<z.ZodNumber>;
69
+ maxLines: z.ZodOptional<z.ZodNumber>;
70
+ maxChars: z.ZodOptional<z.ZodNumber>;
71
+ targetMapping: z.ZodOptional<z.ZodEnum<["yarn", "mojang"]>>;
72
+ outputJar: z.ZodOptional<z.ZodString>;
73
+ executionMode: z.ZodDefault<z.ZodEnum<["preview", "apply"]>>;
74
+ detail: z.ZodOptional<z.ZodEnum<["summary", "standard", "full"]>>;
75
+ include: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
76
+ }, "strip", z.ZodTypeAny, {
77
+ limit: number;
78
+ searchType: "class" | "method" | "field" | "all" | "content";
79
+ task: "search" | "remap" | "summary" | "class-source" | "decompile";
80
+ subject: {
81
+ kind: "jar";
82
+ jarPath: string;
83
+ } | {
84
+ kind: "class";
85
+ jarPath: string;
86
+ className: string;
87
+ };
88
+ includeFiles: boolean;
89
+ executionMode: "preview" | "apply";
90
+ maxLines?: number | undefined;
91
+ maxChars?: number | undefined;
92
+ targetMapping?: "mojang" | "yarn" | undefined;
93
+ outputJar?: string | undefined;
94
+ query?: string | undefined;
95
+ detail?: "full" | "summary" | "standard" | undefined;
96
+ include?: string[] | undefined;
97
+ maxFiles?: number | undefined;
98
+ }, {
99
+ task: "search" | "remap" | "summary" | "class-source" | "decompile";
100
+ subject: {
101
+ kind: "jar";
102
+ jarPath: string;
103
+ } | {
104
+ kind: "class";
105
+ jarPath: string;
106
+ className: string;
107
+ };
108
+ limit?: number | undefined;
109
+ maxLines?: number | undefined;
110
+ maxChars?: number | undefined;
111
+ targetMapping?: "mojang" | "yarn" | undefined;
112
+ outputJar?: string | undefined;
113
+ query?: string | undefined;
114
+ searchType?: "class" | "method" | "field" | "all" | "content" | undefined;
115
+ detail?: "full" | "summary" | "standard" | undefined;
116
+ include?: string[] | undefined;
117
+ includeFiles?: boolean | undefined;
118
+ maxFiles?: number | undefined;
119
+ executionMode?: "preview" | "apply" | undefined;
120
+ }>, {
121
+ limit: number;
122
+ searchType: "class" | "method" | "field" | "all" | "content";
123
+ task: "search" | "remap" | "summary" | "class-source" | "decompile";
124
+ subject: {
125
+ kind: "jar";
126
+ jarPath: string;
127
+ } | {
128
+ kind: "class";
129
+ jarPath: string;
130
+ className: string;
131
+ };
132
+ includeFiles: boolean;
133
+ executionMode: "preview" | "apply";
134
+ maxLines?: number | undefined;
135
+ maxChars?: number | undefined;
136
+ targetMapping?: "mojang" | "yarn" | undefined;
137
+ outputJar?: string | undefined;
138
+ query?: string | undefined;
139
+ detail?: "full" | "summary" | "standard" | undefined;
140
+ include?: string[] | undefined;
141
+ maxFiles?: number | undefined;
142
+ }, {
143
+ task: "search" | "remap" | "summary" | "class-source" | "decompile";
144
+ subject: {
145
+ kind: "jar";
146
+ jarPath: string;
147
+ } | {
148
+ kind: "class";
149
+ jarPath: string;
150
+ className: string;
151
+ };
152
+ limit?: number | undefined;
153
+ maxLines?: number | undefined;
154
+ maxChars?: number | undefined;
155
+ targetMapping?: "mojang" | "yarn" | undefined;
156
+ outputJar?: string | undefined;
157
+ query?: string | undefined;
158
+ searchType?: "class" | "method" | "field" | "all" | "content" | undefined;
159
+ detail?: "full" | "summary" | "standard" | undefined;
160
+ include?: string[] | undefined;
161
+ includeFiles?: boolean | undefined;
162
+ maxFiles?: number | undefined;
163
+ executionMode?: "preview" | "apply" | undefined;
164
+ }>;
165
+ export type AnalyzeModInput = z.infer<typeof analyzeModSchema>;
166
+ type AnalyzeModDeps = {
167
+ analyzeModJar: (jarPath: string, options?: AnalyzeModOptions) => Promise<ModAnalysisResult>;
168
+ decompileModJar: (input: {
169
+ jarPath: string;
170
+ includeFiles?: boolean;
171
+ maxFiles?: number;
172
+ }) => Promise<Record<string, unknown> & {
173
+ warnings?: string[];
174
+ }>;
175
+ getModClassSource: (input: {
176
+ jarPath: string;
177
+ className: string;
178
+ maxLines?: number;
179
+ maxChars?: number;
180
+ }) => Promise<Record<string, unknown> & {
181
+ warnings?: string[];
182
+ }>;
183
+ searchModSource: (input: {
184
+ jarPath: string;
185
+ query: string;
186
+ searchType?: "class" | "method" | "field" | "content" | "all";
187
+ limit?: number;
188
+ }) => Promise<Record<string, unknown> & {
189
+ warnings?: string[];
190
+ }>;
191
+ remapModJar: (input: {
192
+ inputJar: string;
193
+ outputJar?: string;
194
+ mcVersion?: string;
195
+ targetMapping: "yarn" | "mojang";
196
+ }) => Promise<Record<string, unknown> & {
197
+ warnings?: string[];
198
+ }>;
199
+ };
200
+ export declare class AnalyzeModService {
201
+ private readonly deps;
202
+ constructor(deps: AnalyzeModDeps);
203
+ execute(input: AnalyzeModInput): Promise<Record<string, unknown> & {
204
+ warnings?: string[];
205
+ }>;
206
+ }
207
+ export {};
@@ -0,0 +1,309 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { normalizePathForHost } from "../path-converter.js";
4
+ import { createError, ERROR_CODES } from "../errors.js";
5
+ import { z } from "zod";
6
+ import { buildIncludeSchema, detailSchema, executionModeSchema, positiveIntSchema } from "./entry-tool-schema.js";
7
+ import { buildEntryToolResult, createNextAction, createSummarySubject } from "./response-contract.js";
8
+ import { resolveDetail, resolveInclude } from "./request-normalizers.js";
9
+ const nonEmptyString = z.string().trim().min(1);
10
+ const INCLUDE_GROUPS = ["warnings", "files", "source", "samples", "timings"];
11
+ const subjectSchema = z.discriminatedUnion("kind", [
12
+ z.object({
13
+ kind: z.literal("jar"),
14
+ jarPath: nonEmptyString
15
+ }),
16
+ z.object({
17
+ kind: z.literal("class"),
18
+ jarPath: nonEmptyString,
19
+ className: nonEmptyString
20
+ })
21
+ ]);
22
+ export const analyzeModShape = {
23
+ task: z.enum(["summary", "decompile", "search", "class-source", "remap"]),
24
+ subject: subjectSchema,
25
+ query: nonEmptyString.optional(),
26
+ searchType: z.enum(["class", "method", "field", "content", "all"]).default("all"),
27
+ limit: positiveIntSchema.default(50),
28
+ includeFiles: z.boolean().default(true),
29
+ maxFiles: positiveIntSchema.optional(),
30
+ maxLines: positiveIntSchema.optional(),
31
+ maxChars: positiveIntSchema.optional(),
32
+ targetMapping: z.enum(["yarn", "mojang"]).optional(),
33
+ outputJar: nonEmptyString.optional(),
34
+ executionMode: executionModeSchema.default("preview"),
35
+ detail: detailSchema.optional(),
36
+ include: buildIncludeSchema(INCLUDE_GROUPS)
37
+ };
38
+ export const analyzeModSchema = z.object(analyzeModShape).superRefine((value, ctx) => {
39
+ if ((value.task === "summary" || value.task === "decompile" || value.task === "search" || value.task === "remap") && value.subject.kind !== "jar") {
40
+ ctx.addIssue({
41
+ code: z.ZodIssueCode.custom,
42
+ path: ["subject", "kind"],
43
+ message: `${value.task} requires subject.kind=jar.`
44
+ });
45
+ }
46
+ if (value.task === "class-source" && value.subject.kind !== "class") {
47
+ ctx.addIssue({
48
+ code: z.ZodIssueCode.custom,
49
+ path: ["subject", "kind"],
50
+ message: "class-source requires subject.kind=class."
51
+ });
52
+ }
53
+ if (value.task === "search" && !value.query) {
54
+ ctx.addIssue({
55
+ code: z.ZodIssueCode.custom,
56
+ path: ["query"],
57
+ message: "search requires query."
58
+ });
59
+ }
60
+ if (value.task === "remap" && !value.targetMapping) {
61
+ ctx.addIssue({
62
+ code: z.ZodIssueCode.custom,
63
+ path: ["targetMapping"],
64
+ message: "remap requires targetMapping."
65
+ });
66
+ }
67
+ });
68
+ function deriveOutputJar(inputJar, analysis, targetMapping) {
69
+ return join(dirname(inputJar), `${analysis.modId ?? "mod"}-${analysis.modVersion ?? "0"}-${targetMapping}.jar`);
70
+ }
71
+ export class AnalyzeModService {
72
+ deps;
73
+ constructor(deps) {
74
+ this.deps = deps;
75
+ }
76
+ async execute(input) {
77
+ const detail = resolveDetail(input.detail);
78
+ const include = resolveInclude(input.include);
79
+ switch (input.task) {
80
+ case "summary": {
81
+ const analysis = await this.deps.analyzeModJar(input.subject.jarPath, {
82
+ includeClasses: detail !== "summary" || include.includes("files")
83
+ });
84
+ return {
85
+ ...buildEntryToolResult({
86
+ task: "summary",
87
+ detail,
88
+ include,
89
+ summary: {
90
+ status: "ok",
91
+ headline: `Summarized ${analysis.loader} mod metadata.`,
92
+ subject: createSummarySubject({
93
+ task: "summary",
94
+ kind: input.subject.kind,
95
+ jarPath: input.subject.jarPath
96
+ }),
97
+ counts: {
98
+ classes: analysis.classCount,
99
+ dependencies: analysis.dependencies?.length ?? 0
100
+ }
101
+ },
102
+ blocks: {
103
+ metadata: analysis
104
+ }
105
+ }),
106
+ warnings: []
107
+ };
108
+ }
109
+ case "decompile": {
110
+ const includeFiles = input.includeFiles ?? true;
111
+ const output = await this.deps.decompileModJar({
112
+ jarPath: input.subject.jarPath,
113
+ includeFiles,
114
+ maxFiles: input.maxFiles
115
+ });
116
+ return {
117
+ ...buildEntryToolResult({
118
+ task: "decompile",
119
+ detail,
120
+ include,
121
+ summary: {
122
+ status: "ok",
123
+ headline: `Decompiled ${input.subject.jarPath}.`,
124
+ subject: createSummarySubject({
125
+ task: "decompile",
126
+ kind: input.subject.kind,
127
+ jarPath: input.subject.jarPath,
128
+ includeFiles: includeFiles === true ? undefined : includeFiles,
129
+ maxFiles: input.maxFiles
130
+ })
131
+ },
132
+ blocks: {
133
+ decompile: output
134
+ }
135
+ }),
136
+ warnings: Array.isArray(output.warnings) ? output.warnings : []
137
+ };
138
+ }
139
+ case "search": {
140
+ const searchType = input.searchType ?? "all";
141
+ const limit = input.limit ?? 50;
142
+ const output = await this.deps.searchModSource({
143
+ jarPath: input.subject.jarPath,
144
+ query: input.query,
145
+ searchType,
146
+ limit
147
+ });
148
+ return {
149
+ ...buildEntryToolResult({
150
+ task: "search",
151
+ detail,
152
+ include,
153
+ summary: {
154
+ status: "ok",
155
+ headline: `Searched ${input.subject.jarPath} for ${input.query}.`,
156
+ subject: createSummarySubject({
157
+ task: "search",
158
+ kind: input.subject.kind,
159
+ jarPath: input.subject.jarPath,
160
+ query: input.query,
161
+ searchType: searchType === "all" ? undefined : searchType,
162
+ limit: limit === 50 ? undefined : limit
163
+ })
164
+ },
165
+ blocks: {
166
+ hits: output
167
+ }
168
+ }),
169
+ warnings: Array.isArray(output.warnings) ? output.warnings : []
170
+ };
171
+ }
172
+ case "class-source": {
173
+ if (input.subject.kind !== "class") {
174
+ throw createError({
175
+ code: ERROR_CODES.INVALID_INPUT,
176
+ message: "class-source requires subject.kind=class."
177
+ });
178
+ }
179
+ const output = await this.deps.getModClassSource({
180
+ jarPath: input.subject.jarPath,
181
+ className: input.subject.className,
182
+ maxLines: input.maxLines,
183
+ maxChars: input.maxChars
184
+ });
185
+ return {
186
+ ...buildEntryToolResult({
187
+ task: "class-source",
188
+ detail,
189
+ include,
190
+ summary: {
191
+ status: "ok",
192
+ headline: `Loaded class source for ${input.subject.className}.`,
193
+ subject: createSummarySubject({
194
+ task: "class-source",
195
+ kind: input.subject.kind,
196
+ jarPath: input.subject.jarPath,
197
+ className: input.subject.className,
198
+ maxLines: input.maxLines,
199
+ maxChars: input.maxChars
200
+ })
201
+ },
202
+ blocks: {
203
+ source: output
204
+ }
205
+ }),
206
+ warnings: Array.isArray(output.warnings) ? output.warnings : []
207
+ };
208
+ }
209
+ case "remap": {
210
+ const normalizedInputJar = normalizePathForHost(input.subject.jarPath, undefined, "jarPath");
211
+ const analysis = await this.deps.analyzeModJar(normalizedInputJar);
212
+ const outputJar = input.outputJar
213
+ ? normalizePathForHost(input.outputJar, undefined, "outputJar")
214
+ : deriveOutputJar(normalizedInputJar, analysis, input.targetMapping);
215
+ if (outputJar === normalizedInputJar) {
216
+ throw createError({
217
+ code: ERROR_CODES.INVALID_INPUT,
218
+ message: "outputJar must differ from the input jar."
219
+ });
220
+ }
221
+ if ((input.executionMode ?? "preview") === "apply" && existsSync(outputJar)) {
222
+ throw createError({
223
+ code: ERROR_CODES.INVALID_INPUT,
224
+ message: "outputJar already exists. Choose a new destination."
225
+ });
226
+ }
227
+ if ((input.executionMode ?? "preview") === "preview") {
228
+ return {
229
+ ...buildEntryToolResult({
230
+ task: "remap",
231
+ detail,
232
+ include,
233
+ summary: {
234
+ status: "unchanged",
235
+ headline: `Previewed remap output for ${normalizedInputJar}.`,
236
+ subject: createSummarySubject({
237
+ task: "remap",
238
+ kind: input.subject.kind,
239
+ jarPath: normalizedInputJar,
240
+ executionMode: "preview",
241
+ targetMapping: input.targetMapping
242
+ }),
243
+ nextActions: [
244
+ createNextAction("analyze-mod", {
245
+ task: "remap",
246
+ subject: {
247
+ kind: input.subject.kind,
248
+ jarPath: input.subject.jarPath
249
+ },
250
+ executionMode: "apply",
251
+ targetMapping: input.targetMapping
252
+ })
253
+ ]
254
+ },
255
+ blocks: {
256
+ metadata: {
257
+ loader: analysis.loader,
258
+ modId: analysis.modId,
259
+ modVersion: analysis.modVersion
260
+ },
261
+ operation: {
262
+ executionMode: "preview",
263
+ outputJar,
264
+ targetMapping: input.targetMapping
265
+ }
266
+ },
267
+ alwaysBlocks: ["operation"]
268
+ }),
269
+ warnings: []
270
+ };
271
+ }
272
+ const output = await this.deps.remapModJar({
273
+ inputJar: normalizedInputJar,
274
+ outputJar,
275
+ targetMapping: input.targetMapping
276
+ });
277
+ return {
278
+ ...buildEntryToolResult({
279
+ task: "remap",
280
+ detail,
281
+ include,
282
+ summary: {
283
+ status: "changed",
284
+ headline: `Remapped ${normalizedInputJar} to ${input.targetMapping}.`,
285
+ subject: createSummarySubject({
286
+ task: "remap",
287
+ kind: input.subject.kind,
288
+ jarPath: normalizedInputJar,
289
+ executionMode: "apply",
290
+ targetMapping: input.targetMapping
291
+ })
292
+ },
293
+ blocks: {
294
+ operation: {
295
+ executionMode: "apply",
296
+ outputJar,
297
+ targetMapping: input.targetMapping
298
+ },
299
+ metadata: output
300
+ },
301
+ alwaysBlocks: ["operation"]
302
+ }),
303
+ warnings: Array.isArray(output.warnings) ? output.warnings : []
304
+ };
305
+ }
306
+ }
307
+ }
308
+ }
309
+ //# sourceMappingURL=analyze-mod-service.js.map