@adhisang/minecraft-modding-mcp 6.1.0 → 6.2.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 (54) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +4 -2
  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 +2 -0
  8. package/dist/entry-tools/analyze-symbol-service.js +37 -2
  9. package/dist/entry-tools/inspect-minecraft/internal.d.ts +4 -0
  10. package/dist/entry-tools/inspect-minecraft/internal.js +28 -0
  11. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  12. package/dist/error-mapping.d.ts +13 -0
  13. package/dist/error-mapping.js +35 -2
  14. package/dist/errors.d.ts +2 -0
  15. package/dist/errors.js +2 -0
  16. package/dist/index.js +37 -17
  17. package/dist/mapping/internal-types.d.ts +7 -0
  18. package/dist/mapping/types.d.ts +18 -0
  19. package/dist/mapping-service.js +16 -3
  20. package/dist/minecraft-explorer-service.d.ts +4 -0
  21. package/dist/minecraft-explorer-service.js +156 -17
  22. package/dist/mod-analyzer.d.ts +7 -0
  23. package/dist/mod-analyzer.js +28 -7
  24. package/dist/nbt/typed-json.js +4 -1
  25. package/dist/source/artifact-resolver.d.ts +2 -0
  26. package/dist/source/artifact-resolver.js +24 -1
  27. package/dist/source/class-source/members-builder.d.ts +4 -0
  28. package/dist/source/class-source/members-builder.js +3 -1
  29. package/dist/source/class-source.d.ts +2 -1
  30. package/dist/source/class-source.js +154 -17
  31. package/dist/source/did-you-mean.d.ts +14 -0
  32. package/dist/source/did-you-mean.js +79 -0
  33. package/dist/source/file-access.js +159 -3
  34. package/dist/source/indexer.js +72 -2
  35. package/dist/source/lifecycle/runtime-check.js +15 -7
  36. package/dist/source/nested-jars.d.ts +59 -0
  37. package/dist/source/nested-jars.js +198 -0
  38. package/dist/source/workspace-target.js +5 -2
  39. package/dist/source-jar-reader.d.ts +16 -0
  40. package/dist/source-jar-reader.js +82 -0
  41. package/dist/source-service.d.ts +36 -0
  42. package/dist/source-service.js +49 -6
  43. package/dist/stage-emitter.js +24 -8
  44. package/dist/stdio-supervisor.d.ts +92 -9
  45. package/dist/stdio-supervisor.js +915 -103
  46. package/dist/tool-contract-manifest.js +1 -1
  47. package/dist/tool-guidance.js +3 -1
  48. package/dist/tool-schemas.d.ts +1337 -149
  49. package/dist/tool-schemas.js +38 -7
  50. package/dist/types.d.ts +23 -0
  51. package/dist/workspace-mapping-service.d.ts +1 -0
  52. package/dist/workspace-mapping-service.js +120 -8
  53. package/docs/tool-reference.md +19 -3
  54. package/package.json +1 -1
@@ -1,4 +1,6 @@
1
1
  import { loadConfig } from "./config.js";
2
+ import { ERROR_CODES, createError } from "./errors.js";
3
+ import { validateAndNormalizeJarPath } from "./path-resolver.js";
2
4
  import { MinecraftExplorerService } from "./minecraft-explorer-service.js";
3
5
  import { MappingService } from "./mapping-service.js";
4
6
  import { openDatabase } from "./storage/db.js";
@@ -124,6 +126,47 @@ export class SourceService {
124
126
  async decompileModJar(input) {
125
127
  return this.modDecompileService.decompileModJar(input);
126
128
  }
129
+ /**
130
+ * Member-level view of a third-party mod jar class, read from bytecode
131
+ * only — no decompiler is involved on this path, so it answers in
132
+ * milliseconds where a decompile-backed lookup costs a full Vineflower run.
133
+ */
134
+ async getModClassMembers(input) {
135
+ const jarPath = validateAndNormalizeJarPath(input.jarPath);
136
+ const className = input.className.trim();
137
+ if (!className) {
138
+ throw createError({
139
+ code: ERROR_CODES.INVALID_INPUT,
140
+ message: "className must be non-empty."
141
+ });
142
+ }
143
+ const signature = await this.explorerService.getSignature({
144
+ fqn: className,
145
+ jarPath,
146
+ access: "all"
147
+ });
148
+ const counts = {
149
+ constructors: signature.constructors.length,
150
+ fields: signature.fields.length,
151
+ methods: signature.methods.length,
152
+ total: signature.constructors.length + signature.fields.length + signature.methods.length
153
+ };
154
+ // No context block: contextForJar derives minecraftVersion/namespace from
155
+ // the jar path, which for an arbitrary mod jar greps the MOD's own
156
+ // version (e.g. geckolib-fabric-26.2.jar -> "26.2") — misleading here.
157
+ return {
158
+ className,
159
+ jarPath,
160
+ members: {
161
+ constructors: signature.constructors,
162
+ fields: signature.fields,
163
+ methods: signature.methods
164
+ },
165
+ counts,
166
+ extractionMethod: "bytecode-only",
167
+ warnings: signature.warnings
168
+ };
169
+ }
127
170
  async getModClassSource(input) {
128
171
  return this.modDecompileService.getModClassSource(input);
129
172
  }
@@ -143,12 +186,12 @@ export class SourceService {
143
186
  const result = await this.mappingService.checkSymbolExists(input);
144
187
  // On unobfuscated versions the mapping graph is empty, so the mapping service can
145
188
  // only ever report symbols as missing. We then validate against runtime bytecode.
146
- // Classes/fields surface as `mapping_unavailable` when the graph yields nothing, but
147
- // a method query with a non-empty graph returns `not_found` (empty member lookup)
148
- // which previously skipped the runtime fallback and produced false negatives for
149
- // methods that genuinely exist. Treat `not_found` methods as fallback-eligible.
150
- const fallbackEligible = result.status === "mapping_unavailable" ||
151
- (result.status === "not_found" && input.kind === "method");
189
+ // A non-empty graph that simply lacks the queried record returns `not_found` for
190
+ // ANY kind methods, fields, and classes alike and skipping the runtime check
191
+ // produced false negatives (e.g. a real EntityType.ITEM field reported missing).
192
+ // Every `not_found` is therefore fallback-eligible alongside `mapping_unavailable`;
193
+ // the runtime check itself keeps genuinely-missing symbols `not_found`.
194
+ const fallbackEligible = result.status === "mapping_unavailable" || result.status === "not_found";
152
195
  if (!fallbackEligible ||
153
196
  !isUnobfuscatedVersion(input.version) ||
154
197
  (input.sourceMapping !== "mojang" && input.sourceMapping !== "obfuscated")) {
@@ -15,15 +15,31 @@ export function makeStageEmitter(extra, options = {}) {
15
15
  if (requestId === undefined || typeof sendNotification !== "function") {
16
16
  return NOOP_STAGE_EMITTER;
17
17
  }
18
+ let deliveryPending = false;
18
19
  return async (stage, meta) => {
19
- await sendNotification({
20
- method: "$/stageUpdate",
21
- params: {
22
- stage,
23
- meta: meta ?? null,
24
- t: performance.now(),
25
- requestId
26
- }
20
+ if (deliveryPending) {
21
+ return;
22
+ }
23
+ let delivery;
24
+ try {
25
+ delivery = sendNotification({
26
+ method: "$/stageUpdate",
27
+ params: {
28
+ stage,
29
+ meta: meta ?? null,
30
+ t: performance.now(),
31
+ requestId
32
+ }
33
+ });
34
+ }
35
+ catch {
36
+ return;
37
+ }
38
+ deliveryPending = true;
39
+ void Promise.resolve(delivery)
40
+ .catch(() => undefined)
41
+ .finally(() => {
42
+ deliveryPending = false;
27
43
  });
28
44
  };
29
45
  }
@@ -1,6 +1,36 @@
1
- import type { JSONRPCResponse } from "@modelcontextprotocol/sdk/types.js";
2
- type SupervisorOptions = {
1
+ import { type ChildProcessWithoutNullStreams } from "node:child_process";
2
+ import type { JSONRPCMessage, JSONRPCResponse } from "@modelcontextprotocol/sdk/types.js";
3
+ export declare function loadValidateProjectTimeoutMs(value?: string | undefined): number;
4
+ export declare function computeWorkerStartupWatchdogMs(validateProjectTimeoutMs: number): number;
5
+ export declare function computeRestartBackoffMs(retryIndex: number): number;
6
+ export declare function terminatePosixProcessGroup(pid: number, kill?: (pid: number, signal: NodeJS.Signals) => void): boolean;
7
+ export declare function buildWindowsTreeKillArgs(pid: number): string[];
8
+ export declare function shouldRetainUnavailableNotification(method: string): boolean;
9
+ export type RestartReservation = {
10
+ epoch: number;
11
+ notBefore: number;
12
+ delayMs: number;
13
+ };
14
+ export declare class RestartBackoffState {
15
+ private retryIndex;
16
+ private epoch;
17
+ reserve(now: number): RestartReservation;
18
+ reset(): void;
19
+ }
20
+ export declare function retryPosixTreeToken(pid: number, kill?: (pid: number, signal: NodeJS.Signals) => void): boolean;
21
+ export declare function settleTreeCleanupWithin(operation: Promise<boolean>, timeoutMs: number, onTimeout?: () => void): Promise<boolean>;
22
+ export type SupervisorOptions = {
3
23
  entryFile: string;
24
+ validateProjectTimeoutMs?: number;
25
+ clientWriter?: (message: JSONRPCMessage) => void;
26
+ treeTokenRetrier?: (pid: number) => boolean | Promise<boolean>;
27
+ treeCleanupTimeoutMs?: number;
28
+ eventWriter?: (level: "warn" | "error" | "info", event: string, details?: Record<string, unknown>) => void;
29
+ monotonicNow?: () => number;
30
+ timerScheduler?: (callback: () => void, delayMs: number) => NodeJS.Timeout;
31
+ timerClearer?: (timer: NodeJS.Timeout) => void;
32
+ workerSpawner?: () => ChildProcessWithoutNullStreams;
33
+ treeTerminator?: (pid: number) => boolean | Promise<boolean>;
4
34
  };
5
35
  type RequestId = string | number;
6
36
  export type ExitInfo = {
@@ -39,6 +69,15 @@ export type RedactedToolArgs = {
39
69
  modified: boolean;
40
70
  };
41
71
  export declare function redactToolArgs(args: unknown): RedactedToolArgs;
72
+ export declare function buildSupervisorQueueLimitReply(id: RequestId, method: string): JSONRPCResponse;
73
+ export type BuildValidateProjectTimeoutReplyInput = {
74
+ request: PendingRequestSnapshot;
75
+ phase: "queue" | "running";
76
+ deadlineMs: number;
77
+ now: number;
78
+ workerRestartInitiated: boolean;
79
+ };
80
+ export declare function buildValidateProjectTimeoutReply(input: BuildValidateProjectTimeoutReplyInput): JSONRPCResponse;
42
81
  export declare function decideRetryRecommendation(ctx: Pick<RestartContext, "toolName" | "lastStage" | "lastStageMeta" | "exit">, recentRestartTimestamps: number[]): RetryRecommendation;
43
82
  export declare function buildSyntheticCallToolResult(id: RequestId, ctx: RestartContext): JSONRPCResponse;
44
83
  export declare function pruneRestartTimestamps(timestamps: number[], now: number, windowMs?: number): number[];
@@ -62,15 +101,40 @@ export declare function buildWorkerRestartReply(req: PendingRequestSnapshot, exi
62
101
  };
63
102
  export declare class StdioSupervisor {
64
103
  private readonly entryFile;
104
+ private readonly validateProjectTimeoutMs;
105
+ private readonly workerStartupWatchdogMs;
106
+ private readonly clientWriter;
107
+ private readonly treeTokenRetrier;
108
+ private readonly treeCleanupTimeoutMs;
109
+ private readonly eventWriter;
110
+ private readonly monotonicNow;
111
+ private readonly timerScheduler;
112
+ private readonly timerClearer;
113
+ private readonly workerSpawner;
114
+ private readonly treeTerminator;
65
115
  private readonly clientReader;
66
- private readonly workerReader;
67
- private readonly queuedMessages;
116
+ private readonly workerReaders;
117
+ private readonly queuedRequests;
118
+ private readonly queuedNotifications;
68
119
  private readonly pendingRequests;
69
120
  private readonly recentRestarts;
121
+ private readonly liveChildren;
122
+ private readonly staleChildren;
123
+ private readonly cleanupStates;
124
+ private readonly unresolvedTreeTokens;
125
+ private readonly restartBackoff;
126
+ private readonly terminalChildren;
70
127
  private child;
71
128
  private childReady;
72
129
  private shuttingDown;
73
130
  private restartTimer;
131
+ private startupWatchdog;
132
+ private validateBarrierKey;
133
+ private runningValidateKey;
134
+ private attemptToken;
135
+ private currentRetryEpoch;
136
+ private currentRetryReservation;
137
+ private retryPaused;
74
138
  private workerStderrBuffer;
75
139
  private clientMode;
76
140
  private initializeRequest;
@@ -85,11 +149,17 @@ export declare class StdioSupervisor {
85
149
  private readonly handleClientClosed;
86
150
  private readonly handleTerminateSignal;
87
151
  private handleClientMessage;
88
- private forwardToWorker;
152
+ private createPendingRequest;
153
+ private canDispatchImmediately;
154
+ private forwardRequest;
155
+ private writeToWorker;
156
+ private handleCancellation;
157
+ private handleValidateProjectDeadline;
158
+ private drainQueue;
89
159
  private spawnWorker;
90
- private readonly handleWorkerData;
91
- private readonly handleWorkerStdinError;
92
- private readonly handleWorkerStderr;
160
+ private handleWorkerData;
161
+ private handleWorkerStdinError;
162
+ private handleWorkerStderr;
93
163
  private handleWorkerProcessError;
94
164
  private handleWorkerExit;
95
165
  private handleWorkerMessage;
@@ -99,8 +169,21 @@ export declare class StdioSupervisor {
99
169
  private flushQueue;
100
170
  private failPendingRequestsOnWorkerExit;
101
171
  private writeToClient;
172
+ private clearInitialInitializationState;
173
+ private liveCapOccupancy;
174
+ private clearStartupWatchdog;
175
+ private adoptActiveChild;
176
+ private invalidateCurrentChild;
177
+ private detachCurrentChild;
178
+ private recoverTimedOutWorker;
179
+ private beginTreeTermination;
180
+ private finishTreeTermination;
181
+ private retryUnresolvedTreeToken;
182
+ private handleStartupFailure;
183
+ private failQueuedRequestsOnStartupFailure;
102
184
  private scheduleRestart;
103
- private detachChild;
185
+ private armRestartReservation;
186
+ private resumePausedRestart;
104
187
  private shutdown;
105
188
  }
106
189
  export declare const STDIO_WORKER_MODE_ENV = "MCP_STDIO_WORKER_MODE";