@adhisang/minecraft-modding-mcp 3.1.1 → 4.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 (61) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +37 -18
  3. package/dist/access-transformer-parser.d.ts +17 -0
  4. package/dist/access-transformer-parser.js +97 -0
  5. package/dist/cache-registry.d.ts +1 -1
  6. package/dist/cache-registry.js +10 -2
  7. package/dist/concurrency.d.ts +1 -0
  8. package/dist/concurrency.js +24 -0
  9. package/dist/config.d.ts +10 -1
  10. package/dist/config.js +52 -1
  11. package/dist/decompiler/vineflower.js +22 -21
  12. package/dist/entry-tools/analyze-mod-service.d.ts +4 -4
  13. package/dist/entry-tools/analyze-symbol-service.d.ts +22 -22
  14. package/dist/entry-tools/analyze-symbol-service.js +13 -2
  15. package/dist/entry-tools/inspect-minecraft-service.d.ts +168 -168
  16. package/dist/entry-tools/inspect-minecraft-service.js +8 -2
  17. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  18. package/dist/entry-tools/validate-project-service.d.ts +153 -16
  19. package/dist/entry-tools/validate-project-service.js +442 -25
  20. package/dist/gradle-paths.d.ts +4 -0
  21. package/dist/gradle-paths.js +57 -0
  22. package/dist/index.js +148 -30
  23. package/dist/lru-list.d.ts +31 -0
  24. package/dist/lru-list.js +102 -0
  25. package/dist/mapping-pipeline-service.d.ts +12 -1
  26. package/dist/mapping-pipeline-service.js +28 -1
  27. package/dist/mapping-service.d.ts +16 -0
  28. package/dist/mapping-service.js +405 -68
  29. package/dist/minecraft-explorer-service.d.ts +13 -0
  30. package/dist/minecraft-explorer-service.js +8 -4
  31. package/dist/mixin-validator.d.ts +33 -2
  32. package/dist/mixin-validator.js +218 -17
  33. package/dist/mod-analyzer.d.ts +1 -0
  34. package/dist/mod-analyzer.js +17 -1
  35. package/dist/mod-decompile-service.js +4 -4
  36. package/dist/mod-remap-service.js +1 -54
  37. package/dist/mod-search-service.d.ts +1 -0
  38. package/dist/mod-search-service.js +84 -51
  39. package/dist/observability.d.ts +18 -1
  40. package/dist/observability.js +44 -1
  41. package/dist/response-utils.d.ts +69 -0
  42. package/dist/response-utils.js +227 -0
  43. package/dist/source-jar-reader.d.ts +16 -0
  44. package/dist/source-jar-reader.js +103 -1
  45. package/dist/source-resolver.d.ts +9 -1
  46. package/dist/source-resolver.js +23 -16
  47. package/dist/source-service.d.ts +119 -3
  48. package/dist/source-service.js +1836 -218
  49. package/dist/storage/artifacts-repo.d.ts +4 -1
  50. package/dist/storage/artifacts-repo.js +33 -5
  51. package/dist/storage/files-repo.d.ts +0 -2
  52. package/dist/storage/files-repo.js +0 -11
  53. package/dist/storage/migrations.d.ts +1 -1
  54. package/dist/storage/migrations.js +10 -2
  55. package/dist/storage/schema.d.ts +2 -0
  56. package/dist/storage/schema.js +25 -0
  57. package/dist/tool-contract-manifest.js +8 -6
  58. package/dist/types.d.ts +20 -0
  59. package/dist/workspace-mapping-service.d.ts +13 -0
  60. package/dist/workspace-mapping-service.js +146 -14
  61. package/package.json +3 -1
@@ -9,7 +9,7 @@ function toErrorMessage(value) {
9
9
  }
10
10
  return String(value);
11
11
  }
12
- function hasJavaSourceExtension(entryPath) {
12
+ export function hasJavaSourceExtension(entryPath) {
13
13
  const suffix = ".java";
14
14
  if (entryPath.length < suffix.length) {
15
15
  return false;
@@ -144,6 +144,22 @@ export async function listJavaEntries(jarPath) {
144
144
  const entries = await listJarEntries(jarPath);
145
145
  return entries.filter((entry) => hasJavaSourceExtension(entry) && isSecureJarEntryPath(entry));
146
146
  }
147
+ export async function hasAnyJarEntry(jarPath, predicate) {
148
+ return withZipFile(jarPath, async (zipFile) => {
149
+ while (true) {
150
+ const entry = await readNextEntry(zipFile);
151
+ if (!entry) {
152
+ return false;
153
+ }
154
+ if (!isSecureJarEntryPath(entry.fileName)) {
155
+ continue;
156
+ }
157
+ if (predicate(entry.fileName)) {
158
+ return true;
159
+ }
160
+ }
161
+ });
162
+ }
147
163
  export async function readJarEntryAsUtf8(jarPath, entryPath) {
148
164
  const contentBuffer = await readJarEntryAsBuffer(jarPath, entryPath);
149
165
  return decodeUtf8OrThrow(contentBuffer, jarPath, entryPath);
@@ -177,6 +193,39 @@ export async function readJarEntryAsBuffer(jarPath, entryPath) {
177
193
  }
178
194
  });
179
195
  }
196
+ export async function collectMatchedJarEntriesAsUtf8(jarPath, predicate, options = {}) {
197
+ return withZipFile(jarPath, async (zipFile) => {
198
+ const entries = [];
199
+ const maxEntries = options.maxEntries == null ? undefined : Math.max(1, Math.trunc(options.maxEntries));
200
+ while (true) {
201
+ const entry = await readNextEntry(zipFile);
202
+ if (!entry) {
203
+ return entries;
204
+ }
205
+ if (!isSecureJarEntryPath(entry.fileName)) {
206
+ continue;
207
+ }
208
+ if (!predicate(entry.fileName)) {
209
+ continue;
210
+ }
211
+ try {
212
+ const contentBuffer = await readEntryStream(zipFile, entry, jarPath, options.maxBytes);
213
+ entries.push({
214
+ filePath: entry.fileName,
215
+ content: decodeUtf8OrThrow(contentBuffer, jarPath, entry.fileName)
216
+ });
217
+ if (maxEntries != null && entries.length >= maxEntries) {
218
+ return entries;
219
+ }
220
+ }
221
+ catch (error) {
222
+ if (!options.continueOnError) {
223
+ throw error;
224
+ }
225
+ }
226
+ }
227
+ });
228
+ }
180
229
  export async function* iterateJavaEntriesAsUtf8(jarPath, maxBytes) {
181
230
  const zipFile = await openZipFile(jarPath);
182
231
  try {
@@ -227,4 +276,57 @@ export async function readAllJavaEntriesAsUtf8(jarPath, maxBytes) {
227
276
  }
228
277
  return entries;
229
278
  }
279
+ function countMatches(input, pattern) {
280
+ const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
281
+ const globalPattern = new RegExp(pattern.source, flags);
282
+ let count = 0;
283
+ while (globalPattern.exec(input)) {
284
+ count += 1;
285
+ }
286
+ return count;
287
+ }
288
+ export async function detectFabricLikeInputNamespace(inputJar) {
289
+ const warnings = [];
290
+ const classEntries = (await listJarEntries(inputJar))
291
+ .filter((entry) => entry.endsWith(".class"))
292
+ .slice(0, 24);
293
+ if (classEntries.length === 0) {
294
+ warnings.push("Could not inspect class entries to detect input mapping; assuming intermediary.");
295
+ return {
296
+ fromNamespace: "intermediary",
297
+ warnings
298
+ };
299
+ }
300
+ let mojangScore = 0;
301
+ let intermediaryScore = 0;
302
+ for (const entry of classEntries) {
303
+ let text = "";
304
+ try {
305
+ text = (await readJarEntryAsBuffer(inputJar, entry)).toString("latin1");
306
+ }
307
+ catch {
308
+ continue;
309
+ }
310
+ mojangScore += countMatches(text, /net\/minecraft\/(?:advancements|client|commands|core|data|gametest|nbt|network|recipe|resources|server|sounds|stats|tags|util|world)\//g) * 3;
311
+ intermediaryScore += countMatches(text, /net\/minecraft\/class_\d+/g) * 3;
312
+ intermediaryScore += countMatches(text, /\b(?:method|field)_\d+\b/g);
313
+ }
314
+ if (mojangScore > intermediaryScore && mojangScore > 0) {
315
+ return {
316
+ fromNamespace: "mojang",
317
+ warnings
318
+ };
319
+ }
320
+ if (intermediaryScore > mojangScore && intermediaryScore > 0) {
321
+ return {
322
+ fromNamespace: "intermediary",
323
+ warnings
324
+ };
325
+ }
326
+ warnings.push("Could not confidently detect whether the input jar uses intermediary or mojang names; assuming intermediary.");
327
+ return {
328
+ fromNamespace: "intermediary",
329
+ warnings
330
+ };
331
+ }
230
332
  //# sourceMappingURL=source-jar-reader.js.map
@@ -1,8 +1,16 @@
1
- import type { Config, ResolvedSourceArtifact, SourceTargetInput } from "./types.js";
1
+ import type { Config, MappingVariant, ResolvedSourceArtifact, SourceTargetInput } from "./types.js";
2
+ export type { MappingVariant } from "./types.js";
2
3
  export interface ResolveSourceTargetOptions {
3
4
  allowDecompile: boolean;
4
5
  preferBinaryOnly?: boolean;
5
6
  preferredRepos?: string[];
7
+ /**
8
+ * When set to "mojang-remapped", the artifactId hash gets a dedicated
9
+ * suffix so the mojang-remapped variant of an otherwise binary-only artifact
10
+ * occupies its own cache slot. Defaults to "pass" which preserves the
11
+ * legacy hash for obfuscated and source-backed artifacts.
12
+ */
13
+ mappingVariant?: MappingVariant;
6
14
  onRepoFailover?: (event: {
7
15
  stage: "source" | "binary";
8
16
  repoUrl: string;
@@ -1,4 +1,4 @@
1
- import { readdirSync } from "node:fs";
1
+ import { readdir } from "node:fs/promises";
2
2
  import { basename, dirname, join, resolve as resolvePath } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import fastGlob from "fast-glob";
@@ -7,7 +7,7 @@ import { buildRemoteBinaryUrls, buildRemoteSourceUrls, hasExistingJar, parseCoor
7
7
  import { defaultDownloadPath, downloadToCache } from "./repo-downloader.js";
8
8
  import { artifactSignatureFromFile, normalizeJarPath } from "./path-resolver.js";
9
9
  import { stableArtifactId } from "./config.js";
10
- import { listJavaEntries } from "./source-jar-reader.js";
10
+ import { hasAnyJarEntry, hasJavaSourceExtension } from "./source-jar-reader.js";
11
11
  function readStatsSignature(filePath) {
12
12
  const stats = artifactSignatureFromFile(filePath);
13
13
  return stats.signature;
@@ -16,8 +16,7 @@ async function hasJavaSources(jarPath) {
16
16
  if (!hasExistingJar(jarPath)) {
17
17
  return false;
18
18
  }
19
- const entries = await listJavaEntries(jarPath);
20
- return entries.length > 0;
19
+ return hasAnyJarEntry(jarPath, hasJavaSourceExtension);
21
20
  }
22
21
  function resolveExactJarSourceCandidate(inputJarPath) {
23
22
  const directory = dirname(inputJarPath);
@@ -35,12 +34,12 @@ function resolveSiblingBinaryJarCandidate(inputJarPath) {
35
34
  const candidate = join(directory, binaryName);
36
35
  return hasExistingJar(candidate) ? candidate : undefined;
37
36
  }
38
- function listAdjacentJarSourceCandidates(inputJarPath) {
37
+ async function listAdjacentJarSourceCandidates(inputJarPath) {
39
38
  const directory = dirname(inputJarPath);
40
39
  const exact = resolveExactJarSourceCandidate(inputJarPath);
41
40
  const candidates = new Set();
42
41
  try {
43
- for (const file of readdirSync(directory)) {
42
+ for (const file of await readdir(directory)) {
44
43
  if (file.toLowerCase().endsWith("-sources.jar")) {
45
44
  const candidate = join(directory, file);
46
45
  if (candidate !== inputJarPath && candidate !== exact) {
@@ -90,7 +89,7 @@ function resolveGradleUserHome() {
90
89
  }
91
90
  return resolvePath(homedir(), ".gradle");
92
91
  }
93
- function resolveGradleCacheCoordinateCandidate(coordinate) {
92
+ async function resolveGradleCacheCoordinateCandidate(coordinate) {
94
93
  const parsed = parseCoordinate(coordinate);
95
94
  const baseDir = resolvePath(resolveGradleUserHome(), "caches", "modules-2", "files-2.1", parsed.groupId, parsed.artifactId, parsed.version);
96
95
  const base = `${parsed.artifactId}-${parsed.version}`;
@@ -105,7 +104,7 @@ function resolveGradleCacheCoordinateCandidate(coordinate) {
105
104
  ];
106
105
  let discoveredFiles = [];
107
106
  try {
108
- discoveredFiles = fastGlob.sync("*/*", {
107
+ discoveredFiles = await fastGlob.glob("*/*", {
109
108
  cwd: baseDir,
110
109
  absolute: true,
111
110
  onlyFiles: true
@@ -134,11 +133,19 @@ function resolveGradleCacheCoordinateCandidate(coordinate) {
134
133
  function resolveRemoteBinaryCandidate(coordinate, repos) {
135
134
  return buildRemoteBinaryUrls(repos, coordinate);
136
135
  }
137
- function artifactIdForJar(inputKind, artifactPath, signature, suffix) {
138
- return stableArtifactId([inputKind, artifactPath, signature, suffix ?? "source"]);
136
+ function artifactIdForJar(inputKind, artifactPath, signature, suffix, mappingVariant = "pass") {
137
+ const parts = [inputKind, artifactPath, signature, suffix ?? "source"];
138
+ if (mappingVariant === "mojang-remapped") {
139
+ parts.push("mojang-remapped");
140
+ }
141
+ return stableArtifactId(parts);
139
142
  }
140
- function artifactIdForCoordinate(coordinate, source, signature) {
141
- return stableArtifactId(["coord", coordinate, source, signature]);
143
+ function artifactIdForCoordinate(coordinate, source, signature, mappingVariant = "pass") {
144
+ const parts = ["coord", coordinate, source, signature];
145
+ if (mappingVariant === "mojang-remapped") {
146
+ parts.push("mojang-remapped");
147
+ }
148
+ return stableArtifactId(parts);
142
149
  }
143
150
  function resolvedAtNow() {
144
151
  return new Date().toISOString();
@@ -150,7 +157,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
150
157
  const resolvedJarPath = normalizeJarPath(input.value);
151
158
  const binarySignature = readStatsSignature(resolvedJarPath);
152
159
  const exactSourceJarPath = resolveExactJarSourceCandidate(resolvedJarPath);
153
- const adjacentSourceCandidates = listAdjacentJarSourceCandidates(resolvedJarPath);
160
+ const adjacentSourceCandidates = await listAdjacentJarSourceCandidates(resolvedJarPath);
154
161
  const maybeAdjacentSourceCandidates = adjacentSourceCandidates.length > 0 ? adjacentSourceCandidates : undefined;
155
162
  const preferBinaryOnly = options.preferBinaryOnly ?? false;
156
163
  if (await hasJavaSources(resolvedJarPath)) {
@@ -192,7 +199,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
192
199
  });
193
200
  }
194
201
  return {
195
- artifactId: artifactIdForJar("jar", resolvedJarPath, `${binarySignature}:decompile`),
202
+ artifactId: artifactIdForJar("jar", resolvedJarPath, `${binarySignature}:decompile`, undefined, options.mappingVariant ?? "pass"),
196
203
  artifactSignature: `${binarySignature}:decompile`,
197
204
  origin: "decompiled",
198
205
  binaryJarPath: resolvedJarPath,
@@ -225,7 +232,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
225
232
  };
226
233
  }
227
234
  }
228
- const gradleCacheCandidate = resolveGradleCacheCoordinateCandidate(coordinate);
235
+ const gradleCacheCandidate = await resolveGradleCacheCoordinateCandidate(coordinate);
229
236
  if (gradleCacheCandidate?.sourceJarPath && (await hasJavaSources(gradleCacheCandidate.sourceJarPath))) {
230
237
  const signature = readStatsSignature(gradleCacheCandidate.sourceJarPath);
231
238
  return {
@@ -327,7 +334,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
327
334
  }
328
335
  const signature = readStatsSignature(downloaded.path);
329
336
  return {
330
- artifactId: artifactIdForCoordinate(coordinate, "decompiled", signature),
337
+ artifactId: artifactIdForCoordinate(coordinate, "decompiled", signature, options.mappingVariant ?? "pass"),
331
338
  artifactSignature: signature,
332
339
  origin: "decompiled",
333
340
  binaryJarPath: downloaded.path,
@@ -1,9 +1,9 @@
1
1
  import { type ResponseContext as ExplorerResponseContext, type SignatureMember } from "./minecraft-explorer-service.js";
2
- import { type MixinValidationResult, type MixinValidationProvenance, type MappingHealthReport, type AccessWidenerValidationResult } from "./mixin-validator.js";
2
+ import { type MixinValidationResult, type MixinValidationProvenance, type MappingHealthReport, type AccessWidenerValidationResult, type AccessTransformerValidationResult } from "./mixin-validator.js";
3
3
  import { type ClassApiMatrixInput as MappingClassApiMatrixInput, type ClassApiMatrixOutput as MappingClassApiMatrixOutput, type FindMappingInput as MappingFindMappingInput, type FindMappingOutput as MappingFindMappingOutput, type ResolveMethodMappingExactInput as MappingResolveMethodMappingExactInput, type ResolveMethodMappingExactOutput as MappingResolveMethodMappingExactOutput, type SymbolResolutionOutput as MappingSymbolResolutionOutput, type SymbolExistenceInput as MappingSymbolExistenceInput, type SymbolExistenceOutput as MappingSymbolExistenceOutput } from "./mapping-service.js";
4
4
  import { RuntimeMetrics, type RuntimeMetricSnapshot } from "./observability.js";
5
5
  import { type WorkspaceCompileMappingOutput } from "./workspace-mapping-service.js";
6
- import type { ArtifactProvenance, ArtifactRow, ArtifactScope, Config, MappingSourcePriority, ResolvedSourceArtifact, SourceMapping, SourceTargetInput } from "./types.js";
6
+ import type { AccessTransformerNamespace, ArtifactProvenance, ArtifactRow, ArtifactScope, Config, MappingSourcePriority, ResolvedSourceArtifact, SourceMapping, SourceTargetInput } from "./types.js";
7
7
  import { type ListVersionsInput, type ListVersionsOutput } from "./version-service.js";
8
8
  import { type GetRegistryDataInput, type GetRegistryDataOutput } from "./registry-service.js";
9
9
  import { type CompareVersionsInput, type CompareVersionsOutput } from "./version-diff-service.js";
@@ -18,9 +18,11 @@ export type ResolveArtifactInput = {
18
18
  scope?: ArtifactScope;
19
19
  preferProjectVersion?: boolean;
20
20
  strictVersion?: boolean;
21
+ compact?: boolean;
21
22
  };
22
23
  export type ResolveArtifactOutput = {
23
24
  artifactId: string;
25
+ artifactAlias: string;
24
26
  origin: "local-jar" | "local-m2" | "remote-repo" | "decompiled";
25
27
  isDecompiled: boolean;
26
28
  resolvedSourceJarPath?: string;
@@ -74,6 +76,8 @@ export type SearchClassSourceInput = {
74
76
  queryMode?: QueryMode;
75
77
  limit?: number;
76
78
  cursor?: string;
79
+ queryNamespace?: SourceMapping;
80
+ sourcePriority?: MappingSourcePriority;
77
81
  };
78
82
  export type SearchClassSourceOutput = {
79
83
  hits: SearchSourceHit[];
@@ -81,6 +85,13 @@ export type SearchClassSourceOutput = {
81
85
  mappingApplied: SourceMapping;
82
86
  returnedNamespace: SourceMapping;
83
87
  artifactContents: ArtifactContentsSummary;
88
+ translatedQuery?: {
89
+ original: string;
90
+ translated: string;
91
+ fromNamespace: SourceMapping;
92
+ toNamespace: SourceMapping;
93
+ };
94
+ warnings?: string[];
84
95
  };
85
96
  export type GetArtifactFileInput = {
86
97
  artifactId: string;
@@ -207,6 +218,17 @@ export type GetClassMembersInput = {
207
218
  preferProjectVersion?: boolean;
208
219
  strictVersion?: boolean;
209
220
  };
221
+ export type DecompiledMember = {
222
+ name: string;
223
+ line: number;
224
+ kind: "constructor" | "field" | "method";
225
+ };
226
+ export type DecompiledFallback = {
227
+ constructors: DecompiledMember[];
228
+ fields: DecompiledMember[];
229
+ methods: DecompiledMember[];
230
+ origin: "source-extracted";
231
+ };
210
232
  export type GetClassMembersOutput = {
211
233
  className: string;
212
234
  members: {
@@ -230,6 +252,13 @@ export type GetClassMembersOutput = {
230
252
  provenance: ArtifactProvenance;
231
253
  qualityFlags: string[];
232
254
  artifactContents: ArtifactContentsSummary;
255
+ decompiledFallback?: DecompiledFallback;
256
+ decompiledMemberCounts?: {
257
+ constructors: number;
258
+ fields: number;
259
+ methods: number;
260
+ total: number;
261
+ };
233
262
  warnings: string[];
234
263
  };
235
264
  export type TraceSymbolLifecycleInput = {
@@ -424,8 +453,21 @@ export type ValidateAccessWidenerInput = {
424
453
  version: string;
425
454
  mapping?: SourceMapping;
426
455
  sourcePriority?: MappingSourcePriority;
456
+ projectPath?: string;
457
+ scope?: ArtifactScope;
458
+ preferProjectVersion?: boolean;
427
459
  };
428
460
  export type ValidateAccessWidenerOutput = AccessWidenerValidationResult;
461
+ export type ValidateAccessTransformerInput = {
462
+ content: string;
463
+ version: string;
464
+ atNamespace?: AccessTransformerNamespace;
465
+ sourcePriority?: MappingSourcePriority;
466
+ projectPath?: string;
467
+ scope?: ArtifactScope;
468
+ preferProjectVersion?: boolean;
469
+ };
470
+ export type ValidateAccessTransformerOutput = AccessTransformerValidationResult;
429
471
  export declare class SourceService {
430
472
  private readonly config;
431
473
  private readonly db;
@@ -442,10 +484,33 @@ export declare class SourceService {
442
484
  private readonly versionDiffService;
443
485
  private readonly modDecompileService;
444
486
  private readonly modSearchService;
445
- private cacheMetricsState;
487
+ private readonly lru;
488
+ private cacheTotalContentBytes;
489
+ private readonly remappedJarBytes;
490
+ /** In-flight binary-remap jobs keyed by remapped jar path so concurrent
491
+ * resolveArtifact calls for the same artifactId share a single tiny-remapper run. */
492
+ private readonly inflightRemaps;
446
493
  constructor(explicitConfig?: Config, metrics?: RuntimeMetrics);
447
494
  private discoverVersionSourceJar;
495
+ private discoverAccessWidenerRuntimeCandidates;
496
+ private discoverAccessTransformerRuntimeCandidates;
497
+ private resolveAccessWidenerRuntimeArtifact;
498
+ private resolveAccessTransformerNamespace;
499
+ private resolveAccessTransformerRuntimeArtifact;
448
500
  private buildVersionSourceRecoveryCommand;
501
+ /**
502
+ * Decide whether the upcoming resolveArtifact call may transparently remap a
503
+ * binary-only artifact (obfuscated -> mojang) and decompile it. The gate
504
+ * succeeds only when:
505
+ * - the requested mapping is "mojang" on a still-obfuscated runtime
506
+ * - tiny-remapper jar is downloadable / available locally
507
+ * - the version's Mojang tiny mapping file can be produced
508
+ * - checkMappingHealth reports mojang mappings are usable
509
+ * On any failure the variant defaults to "pass" so the legacy
510
+ * MAPPING_NOT_APPLIED fallback (or the existing source-backed flow) keeps
511
+ * its existing artifactId hash.
512
+ */
513
+ private computeBinaryRemapGate;
449
514
  private buildArtifactContentsSummary;
450
515
  private inferVersionFromContext;
451
516
  private resolveVersionContext;
@@ -464,22 +529,28 @@ export declare class SourceService {
464
529
  getClassApiMatrix(input: GetClassApiMatrixInput): Promise<GetClassApiMatrixOutput>;
465
530
  checkSymbolExists(input: CheckSymbolExistsInput): Promise<CheckSymbolExistsOutput>;
466
531
  resolveWorkspaceSymbol(input: ResolveWorkspaceSymbolInput): Promise<ResolveWorkspaceSymbolOutput>;
532
+ private checkSymbolExistsInUnobfuscatedRuntime;
467
533
  traceSymbolLifecycle(input: TraceSymbolLifecycleInput): Promise<TraceSymbolLifecycleOutput>;
468
534
  diffClassSignatures(input: DiffClassSignaturesInput): Promise<DiffClassSignaturesOutput>;
469
535
  findClass(input: FindClassInput): FindClassOutput;
470
536
  getClassSource(input: GetClassSourceInput): Promise<GetClassSourceOutput>;
471
537
  getClassMembers(input: GetClassMembersInput): Promise<GetClassMembersOutput>;
538
+ private buildDecompiledFallback;
472
539
  validateMixin(input: ValidateMixinInput): Promise<ValidateMixinOutput>;
540
+ private runValidateMixinDispatcher;
473
541
  private createProjectValidateMixinConfigInput;
474
542
  private shouldRetryValidateMixinWithMavenFirst;
475
543
  private findValidateMixinClassMapping;
476
544
  private validateMixinSingle;
545
+ private runValidateMixinPipeline;
477
546
  private resolveMixinInputPath;
478
547
  private resolveMixinConfigSources;
479
548
  private validateMixinMany;
480
549
  private applyValidateMixinOutputCompaction;
481
550
  private buildValidateMixinOutput;
482
551
  validateAccessWidener(input: ValidateAccessWidenerInput): Promise<ValidateAccessWidenerOutput>;
552
+ validateAccessTransformer(input: ValidateAccessTransformerInput): Promise<ValidateAccessTransformerOutput>;
553
+ recordToolCall(tool: string, durationMs: number): void;
483
554
  getRuntimeMetrics(): RuntimeMetricSnapshot;
484
555
  indexArtifact(input: IndexArtifactInput): Promise<IndexArtifactOutput>;
485
556
  private searchSymbolIntent;
@@ -491,6 +562,11 @@ export declare class SourceService {
491
562
  private indexedCandidateLimit;
492
563
  private indexedCandidateLimitForMatch;
493
564
  private extractClassMetadata;
565
+ private extractDecompiledMembers;
566
+ private computeLineBraceDepths;
567
+ private computeBraceRange;
568
+ private scanBraceRange;
569
+ private computeNestedTypeRanges;
494
570
  private resolveClassFilePath;
495
571
  private resolveBinaryFallbackArtifact;
496
572
  private buildProvenance;
@@ -509,13 +585,53 @@ export declare class SourceService {
509
585
  private buildRebuiltArtifactData;
510
586
  getArtifact(artifactId: string): ArtifactRow;
511
587
  private ingestIfNeeded;
588
+ /**
589
+ * If the resolved artifact's transformChain promised an "obf -> mojang"
590
+ * binary remap, run tiny-remapper now and return the remapped jar path.
591
+ * Otherwise return the original binaryJarPath unchanged.
592
+ *
593
+ * Cache safety: writes to a per-attempt temp file then atomic-renames into
594
+ * <cacheDir>/remapped/<artifactId>.jar. A per-target inflight Promise map
595
+ * collapses concurrent calls so two simultaneous resolveArtifact calls for
596
+ * the same artifactId share one tiny-remapper run instead of racing on the
597
+ * same output path.
598
+ */
599
+ private maybeRemapBinaryForMojang;
600
+ private recordRemappedJarBytesFromDisk;
601
+ /**
602
+ * Best-effort structural check that `path` is a non-empty file beginning with
603
+ * the ZIP local-file-header magic (`50 4B 03 04`). Used to drop partial /
604
+ * corrupt remap-cache entries before they reach Vineflower. False positives
605
+ * are acceptable (Vineflower will surface a clearer error); false negatives
606
+ * are not (a corrupt cache hit must be evicted).
607
+ */
608
+ private isUsableJarFile;
609
+ private runBinaryRemap;
512
610
  private loadFromSourceJar;
513
611
  private hasAnyFiles;
612
+ /**
613
+ * Best-effort cleanup of `<cacheDir>/remapped/<artifactId>.jar` written by
614
+ * `maybeRemapBinaryForMojang`. Called from cache-eviction paths so the
615
+ * Mojang-remapped binary jar does not outlive the artifact row that owns it.
616
+ * Also releases the jar's bytes from `cacheTotalContentBytes`. Errors are
617
+ * swallowed: orphaned jars remain visible to `manage-cache` under the
618
+ * `binary-remap` cache kind and can be reclaimed there.
619
+ */
620
+ private unlinkRemappedJarForArtifact;
621
+ /**
622
+ * Add the remapped jar's on-disk size to `cacheTotalContentBytes` so the
623
+ * `enforceCacheLimits` byte gate sees the jar before deciding to evict.
624
+ * Without this, a Mojang-remapped client jar (tens of MB) can accumulate
625
+ * silently while the indexed-source byte total stays below `maxCacheBytes`.
626
+ */
627
+ private recordRemappedJarBytes;
628
+ private releaseRemappedJarBytes;
514
629
  private enforceCacheLimits;
515
630
  private refreshCacheMetrics;
516
631
  private touchCacheMetrics;
517
632
  private upsertCacheMetrics;
518
633
  private removeCacheMetrics;
519
634
  private publishCacheMetrics;
635
+ private snapshotLruAccounting;
520
636
  }
521
637
  export {};