@adhisang/minecraft-modding-mcp 3.2.0 → 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 (38) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +25 -18
  3. package/dist/cache-registry.d.ts +1 -1
  4. package/dist/cache-registry.js +10 -2
  5. package/dist/config.d.ts +10 -1
  6. package/dist/config.js +52 -1
  7. package/dist/entry-tools/analyze-symbol-service.d.ts +2 -2
  8. package/dist/entry-tools/analyze-symbol-service.js +13 -2
  9. package/dist/entry-tools/inspect-minecraft-service.d.ts +20 -20
  10. package/dist/entry-tools/inspect-minecraft-service.js +8 -2
  11. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  12. package/dist/entry-tools/validate-project-service.js +84 -4
  13. package/dist/index.js +99 -33
  14. package/dist/lru-list.d.ts +31 -0
  15. package/dist/lru-list.js +102 -0
  16. package/dist/mapping-pipeline-service.d.ts +10 -1
  17. package/dist/mapping-pipeline-service.js +13 -1
  18. package/dist/mapping-service.d.ts +12 -0
  19. package/dist/mapping-service.js +252 -10
  20. package/dist/mixin-validator.js +22 -7
  21. package/dist/observability.d.ts +18 -1
  22. package/dist/observability.js +44 -1
  23. package/dist/response-utils.d.ts +44 -10
  24. package/dist/response-utils.js +131 -17
  25. package/dist/source-resolver.d.ts +9 -1
  26. package/dist/source-resolver.js +14 -6
  27. package/dist/source-service.d.ts +97 -1
  28. package/dist/source-service.js +922 -113
  29. package/dist/storage/artifacts-repo.d.ts +4 -1
  30. package/dist/storage/artifacts-repo.js +33 -5
  31. package/dist/storage/files-repo.d.ts +0 -2
  32. package/dist/storage/files-repo.js +0 -11
  33. package/dist/storage/migrations.d.ts +1 -1
  34. package/dist/storage/migrations.js +10 -2
  35. package/dist/storage/schema.d.ts +2 -0
  36. package/dist/storage/schema.js +25 -0
  37. package/dist/types.d.ts +3 -0
  38. package/package.json +3 -1
@@ -7,29 +7,63 @@
7
7
  export declare const COMPACT_ENABLED_TOOL_NAMES: Set<string>;
8
8
  /** Mapping-oriented tools that get additional field projection via compactMappingResponse. */
9
9
  export declare const COMPACT_MAPPING_TOOL_NAMES: Set<string>;
10
+ /** Source-oriented tools (get-class-source) that get compactSourceResponse projection. */
11
+ export declare const COMPACT_SOURCE_TOOL_NAMES: Set<string>;
12
+ /** Member-listing tools (get-class-members) that get compactMembersResponse projection. */
13
+ export declare const COMPACT_MEMBERS_TOOL_NAMES: Set<string>;
14
+ /**
15
+ * Tools that only need the light artifactContents projection (search hits,
16
+ * file listing). The primary payload is already small; the projection just
17
+ * drops the artifact-level summary that callers rarely consume.
18
+ */
19
+ export declare const COMPACT_LIGHT_TOOL_NAMES: Set<string>;
10
20
  /**
11
21
  * Double-gated compact check: tool must be in the allowlist AND parsedInput.compact must be true.
12
22
  * Prevents activation on passthrough schemas where Zod doesn't strip unknown keys.
13
23
  */
14
24
  export declare function isCompactEnabled(tool: string, parsedInput: unknown): boolean;
25
+ /**
26
+ * Primary-payload keys that compact mode must preserve per tool, even when
27
+ * the value is an empty array (no hits, no files, no members). Without this
28
+ * the generic {@link compactResponse} path would strip `hits: []` / `items: []`
29
+ * from successful zero-result responses and callers could not distinguish
30
+ * "empty success" from "field missing".
31
+ *
32
+ * Only tools whose primary payload can legitimately be an empty array need
33
+ * an entry here. `get-class-source` returns `sourceText: string` which is
34
+ * never stripped by compactResponse.
35
+ */
36
+ export declare const TOOL_PRESERVE_PAYLOAD_KEYS: Record<string, ReadonlySet<string>>;
15
37
  /**
16
38
  * Shallow-strip empty values from a response object.
17
39
  * Only operates on the top level — nested structures are preserved as-is.
18
40
  * Non-plain objects (Date, Map, class instances) are never treated as empty.
41
+ *
42
+ * `preserveKeys` names keys whose values MUST survive the strip even if
43
+ * empty (used by tools whose primary payload is an array that can legitimately
44
+ * be empty — e.g. zero-hit search, empty file listing). `null` / `undefined`
45
+ * values are still dropped even for preserved keys, so absent optional
46
+ * payload fields do not leak through as explicit nulls.
19
47
  */
20
- export declare function compactResponse(obj: Record<string, unknown>): Record<string, unknown>;
48
+ export declare function compactResponse(obj: Record<string, unknown>, preserveKeys?: ReadonlySet<string>): Record<string, unknown>;
21
49
  /** resolve-artifact compact: omit debug/diagnostic fields. */
22
50
  export declare function compactArtifactResponse(obj: Record<string, unknown>): Record<string, unknown>;
51
+ /** get-class-source compact: drop provenance, artifactContents, qualityFlags. */
52
+ export declare function compactSourceResponse(obj: Record<string, unknown>): Record<string, unknown>;
53
+ /** get-class-members compact: drop provenance, artifactContents, qualityFlags, context. */
54
+ export declare function compactMembersResponse(obj: Record<string, unknown>): Record<string, unknown>;
55
+ /** Light compact projection: drop the artifactContents summary only. */
56
+ export declare function compactLightResponse(obj: Record<string, unknown>): Record<string, unknown>;
23
57
  /**
24
- * Mapping tool compact: omit candidates only when provably redundant.
58
+ * Mapping tool compact: project candidates for size reduction.
59
+ *
60
+ * Resolved-exact path: omit candidates entirely when provably redundant.
61
+ * All of: resolved===true, resolvedSymbol exists, single exact candidate, not truncated,
62
+ * confidence missing or 1.
25
63
  *
26
- * Candidates are omitted when ALL of:
27
- * 1. resolved === true
28
- * 2. resolvedSymbol exists
29
- * 3. candidates is an array of length 1
30
- * 4. candidateCount === 1
31
- * 5. candidatesTruncated is falsy
32
- * 6. candidates[0].matchKind === "exact"
33
- * 7. candidates[0].confidence is undefined or 1
64
+ * Unresolved/ambiguous path: keep top {@link UNRESOLVED_FULL_DETAIL_LIMIT} candidates with full
65
+ * metadata, slim the tail to {kind,symbol,owner,name,descriptor,confidence,matchKind}, and
66
+ * surface `candidatesTruncated:true` + `totalCandidateCount` so the caller knows what it's
67
+ * seeing.
34
68
  */
35
69
  export declare function compactMappingResponse(obj: Record<string, unknown>): Record<string, unknown>;
@@ -9,7 +9,11 @@ export const COMPACT_ENABLED_TOOL_NAMES = new Set([
9
9
  "find-mapping",
10
10
  "resolve-method-mapping-exact",
11
11
  "resolve-workspace-symbol",
12
- "check-symbol-exists"
12
+ "check-symbol-exists",
13
+ "get-class-source",
14
+ "get-class-members",
15
+ "search-class-source",
16
+ "list-artifact-files"
13
17
  ]);
14
18
  /** Mapping-oriented tools that get additional field projection via compactMappingResponse. */
15
19
  export const COMPACT_MAPPING_TOOL_NAMES = new Set([
@@ -18,6 +22,23 @@ export const COMPACT_MAPPING_TOOL_NAMES = new Set([
18
22
  "resolve-workspace-symbol",
19
23
  "check-symbol-exists"
20
24
  ]);
25
+ /** Source-oriented tools (get-class-source) that get compactSourceResponse projection. */
26
+ export const COMPACT_SOURCE_TOOL_NAMES = new Set([
27
+ "get-class-source"
28
+ ]);
29
+ /** Member-listing tools (get-class-members) that get compactMembersResponse projection. */
30
+ export const COMPACT_MEMBERS_TOOL_NAMES = new Set([
31
+ "get-class-members"
32
+ ]);
33
+ /**
34
+ * Tools that only need the light artifactContents projection (search hits,
35
+ * file listing). The primary payload is already small; the projection just
36
+ * drops the artifact-level summary that callers rarely consume.
37
+ */
38
+ export const COMPACT_LIGHT_TOOL_NAMES = new Set([
39
+ "search-class-source",
40
+ "list-artifact-files"
41
+ ]);
21
42
  /**
22
43
  * Double-gated compact check: tool must be in the allowlist AND parsedInput.compact must be true.
23
44
  * Prevents activation on passthrough schemas where Zod doesn't strip unknown keys.
@@ -39,18 +60,44 @@ function isPlainObject(v) {
39
60
  const proto = Object.getPrototypeOf(v);
40
61
  return proto === Object.prototype || proto === null;
41
62
  }
63
+ /**
64
+ * Primary-payload keys that compact mode must preserve per tool, even when
65
+ * the value is an empty array (no hits, no files, no members). Without this
66
+ * the generic {@link compactResponse} path would strip `hits: []` / `items: []`
67
+ * from successful zero-result responses and callers could not distinguish
68
+ * "empty success" from "field missing".
69
+ *
70
+ * Only tools whose primary payload can legitimately be an empty array need
71
+ * an entry here. `get-class-source` returns `sourceText: string` which is
72
+ * never stripped by compactResponse.
73
+ */
74
+ export const TOOL_PRESERVE_PAYLOAD_KEYS = {
75
+ "search-class-source": new Set(["hits"]),
76
+ "list-artifact-files": new Set(["items"]),
77
+ "get-class-members": new Set(["members", "counts", "decompiledFallback", "decompiledMemberCounts"])
78
+ };
42
79
  /**
43
80
  * Shallow-strip empty values from a response object.
44
81
  * Only operates on the top level — nested structures are preserved as-is.
45
82
  * Non-plain objects (Date, Map, class instances) are never treated as empty.
83
+ *
84
+ * `preserveKeys` names keys whose values MUST survive the strip even if
85
+ * empty (used by tools whose primary payload is an array that can legitimately
86
+ * be empty — e.g. zero-hit search, empty file listing). `null` / `undefined`
87
+ * values are still dropped even for preserved keys, so absent optional
88
+ * payload fields do not leak through as explicit nulls.
46
89
  */
47
- export function compactResponse(obj) {
90
+ export function compactResponse(obj, preserveKeys) {
48
91
  if (!isPlainObject(obj))
49
92
  return {};
50
93
  const result = {};
51
94
  for (const [key, value] of Object.entries(obj)) {
52
95
  if (value === null || value === undefined)
53
96
  continue;
97
+ if (preserveKeys?.has(key)) {
98
+ result[key] = value;
99
+ continue;
100
+ }
54
101
  if (Array.isArray(value) && value.length === 0)
55
102
  continue;
56
103
  if (isPlainObject(value) && Object.keys(value).length === 0)
@@ -59,6 +106,15 @@ export function compactResponse(obj) {
59
106
  }
60
107
  return result;
61
108
  }
109
+ function projectOmitKeys(obj, omit) {
110
+ const projected = {};
111
+ for (const [key, value] of Object.entries(obj)) {
112
+ if (omit.has(key))
113
+ continue;
114
+ projected[key] = value;
115
+ }
116
+ return projected;
117
+ }
62
118
  /** Fields to omit from resolve-artifact in compact mode. */
63
119
  const ARTIFACT_COMPACT_OMIT_KEYS = new Set([
64
120
  "provenance",
@@ -72,25 +128,69 @@ const ARTIFACT_COMPACT_OMIT_KEYS = new Set([
72
128
  ]);
73
129
  /** resolve-artifact compact: omit debug/diagnostic fields. */
74
130
  export function compactArtifactResponse(obj) {
75
- const projected = {};
76
- for (const [key, value] of Object.entries(obj)) {
77
- if (ARTIFACT_COMPACT_OMIT_KEYS.has(key))
78
- continue;
79
- projected[key] = value;
131
+ return projectOmitKeys(obj, ARTIFACT_COMPACT_OMIT_KEYS);
132
+ }
133
+ /** Fields to omit from get-class-source in compact mode. */
134
+ const SOURCE_COMPACT_OMIT_KEYS = new Set([
135
+ "provenance",
136
+ "artifactContents",
137
+ "qualityFlags"
138
+ ]);
139
+ /** get-class-source compact: drop provenance, artifactContents, qualityFlags. */
140
+ export function compactSourceResponse(obj) {
141
+ return projectOmitKeys(obj, SOURCE_COMPACT_OMIT_KEYS);
142
+ }
143
+ /** Fields to omit from get-class-members in compact mode. */
144
+ const MEMBERS_COMPACT_OMIT_KEYS = new Set([
145
+ "provenance",
146
+ "artifactContents",
147
+ "qualityFlags",
148
+ "context"
149
+ ]);
150
+ /** get-class-members compact: drop provenance, artifactContents, qualityFlags, context. */
151
+ export function compactMembersResponse(obj) {
152
+ return projectOmitKeys(obj, MEMBERS_COMPACT_OMIT_KEYS);
153
+ }
154
+ /** Fields to omit from search-class-source / list-artifact-files in compact mode. */
155
+ const LIGHT_COMPACT_OMIT_KEYS = new Set([
156
+ "artifactContents"
157
+ ]);
158
+ /** Light compact projection: drop the artifactContents summary only. */
159
+ export function compactLightResponse(obj) {
160
+ return projectOmitKeys(obj, LIGHT_COMPACT_OMIT_KEYS);
161
+ }
162
+ /** Max number of unresolved candidates that get full metadata in compact mode. */
163
+ const UNRESOLVED_FULL_DETAIL_LIMIT = 3;
164
+ /**
165
+ * Slim projection of a candidate: retains only identification + confidence fields.
166
+ *
167
+ * `kind` and `symbol` are part of the public `SymbolReference` / candidate contract that
168
+ * clients branch on and use as rendering keys, so they MUST survive the slim. The heavy
169
+ * fields removed here are the cycle-local diagnostic metadata (provenance, context,
170
+ * ambiguityReasons, warnings on the candidate, etc.) — not the identity fields.
171
+ */
172
+ function slimCandidate(candidate) {
173
+ if (!isPlainObject(candidate))
174
+ return candidate;
175
+ const picked = {};
176
+ for (const key of ["kind", "symbol", "owner", "name", "descriptor", "confidence", "matchKind"]) {
177
+ if (candidate[key] !== undefined) {
178
+ picked[key] = candidate[key];
179
+ }
80
180
  }
81
- return projected;
181
+ return picked;
82
182
  }
83
183
  /**
84
- * Mapping tool compact: omit candidates only when provably redundant.
184
+ * Mapping tool compact: project candidates for size reduction.
185
+ *
186
+ * Resolved-exact path: omit candidates entirely when provably redundant.
187
+ * All of: resolved===true, resolvedSymbol exists, single exact candidate, not truncated,
188
+ * confidence missing or 1.
85
189
  *
86
- * Candidates are omitted when ALL of:
87
- * 1. resolved === true
88
- * 2. resolvedSymbol exists
89
- * 3. candidates is an array of length 1
90
- * 4. candidateCount === 1
91
- * 5. candidatesTruncated is falsy
92
- * 6. candidates[0].matchKind === "exact"
93
- * 7. candidates[0].confidence is undefined or 1
190
+ * Unresolved/ambiguous path: keep top {@link UNRESOLVED_FULL_DETAIL_LIMIT} candidates with full
191
+ * metadata, slim the tail to {kind,symbol,owner,name,descriptor,confidence,matchKind}, and
192
+ * surface `candidatesTruncated:true` + `totalCandidateCount` so the caller knows what it's
193
+ * seeing.
94
194
  */
95
195
  export function compactMappingResponse(obj) {
96
196
  const projected = { ...obj };
@@ -106,8 +206,22 @@ export function compactMappingResponse(obj) {
106
206
  candidate.matchKind === "exact" &&
107
207
  (candidate.confidence === undefined || candidate.confidence === 1)) {
108
208
  delete projected.candidates;
209
+ return projected;
109
210
  }
110
211
  }
212
+ if (projected.resolved === false &&
213
+ Array.isArray(candidates) &&
214
+ candidates.length > UNRESOLVED_FULL_DETAIL_LIMIT) {
215
+ const head = candidates.slice(0, UNRESOLVED_FULL_DETAIL_LIMIT);
216
+ const tail = candidates.slice(UNRESOLVED_FULL_DETAIL_LIMIT).map(slimCandidate);
217
+ projected.candidates = [...head, ...tail];
218
+ // Tail slimming keeps the full candidate array; only metadata was dropped. Use a
219
+ // dedicated `candidateDetailsTruncated` signal so clients do not confuse it with the
220
+ // existing `candidatesTruncated` semantics ("more candidates exist than this response
221
+ // contains"). If the upstream already reported list-level truncation via
222
+ // `candidatesTruncated`, that value is preserved unchanged.
223
+ projected.candidateDetailsTruncated = true;
224
+ }
111
225
  return projected;
112
226
  }
113
227
  //# sourceMappingURL=response-utils.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;
@@ -133,11 +133,19 @@ async function resolveGradleCacheCoordinateCandidate(coordinate) {
133
133
  function resolveRemoteBinaryCandidate(coordinate, repos) {
134
134
  return buildRemoteBinaryUrls(repos, coordinate);
135
135
  }
136
- function artifactIdForJar(inputKind, artifactPath, signature, suffix) {
137
- 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);
138
142
  }
139
- function artifactIdForCoordinate(coordinate, source, signature) {
140
- 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);
141
149
  }
142
150
  function resolvedAtNow() {
143
151
  return new Date().toISOString();
@@ -191,7 +199,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
191
199
  });
192
200
  }
193
201
  return {
194
- artifactId: artifactIdForJar("jar", resolvedJarPath, `${binarySignature}:decompile`),
202
+ artifactId: artifactIdForJar("jar", resolvedJarPath, `${binarySignature}:decompile`, undefined, options.mappingVariant ?? "pass"),
195
203
  artifactSignature: `${binarySignature}:decompile`,
196
204
  origin: "decompiled",
197
205
  binaryJarPath: resolvedJarPath,
@@ -326,7 +334,7 @@ export async function resolveSourceTarget(input, options, explicitConfig) {
326
334
  }
327
335
  const signature = readStatsSignature(downloaded.path);
328
336
  return {
329
- artifactId: artifactIdForCoordinate(coordinate, "decompiled", signature),
337
+ artifactId: artifactIdForCoordinate(coordinate, "decompiled", signature, options.mappingVariant ?? "pass"),
330
338
  artifactSignature: signature,
331
339
  origin: "decompiled",
332
340
  binaryJarPath: downloaded.path,
@@ -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 = {
@@ -455,7 +484,12 @@ export declare class SourceService {
455
484
  private readonly versionDiffService;
456
485
  private readonly modDecompileService;
457
486
  private readonly modSearchService;
458
- 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;
459
493
  constructor(explicitConfig?: Config, metrics?: RuntimeMetrics);
460
494
  private discoverVersionSourceJar;
461
495
  private discoverAccessWidenerRuntimeCandidates;
@@ -464,6 +498,19 @@ export declare class SourceService {
464
498
  private resolveAccessTransformerNamespace;
465
499
  private resolveAccessTransformerRuntimeArtifact;
466
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;
467
514
  private buildArtifactContentsSummary;
468
515
  private inferVersionFromContext;
469
516
  private resolveVersionContext;
@@ -488,11 +535,14 @@ export declare class SourceService {
488
535
  findClass(input: FindClassInput): FindClassOutput;
489
536
  getClassSource(input: GetClassSourceInput): Promise<GetClassSourceOutput>;
490
537
  getClassMembers(input: GetClassMembersInput): Promise<GetClassMembersOutput>;
538
+ private buildDecompiledFallback;
491
539
  validateMixin(input: ValidateMixinInput): Promise<ValidateMixinOutput>;
540
+ private runValidateMixinDispatcher;
492
541
  private createProjectValidateMixinConfigInput;
493
542
  private shouldRetryValidateMixinWithMavenFirst;
494
543
  private findValidateMixinClassMapping;
495
544
  private validateMixinSingle;
545
+ private runValidateMixinPipeline;
496
546
  private resolveMixinInputPath;
497
547
  private resolveMixinConfigSources;
498
548
  private validateMixinMany;
@@ -500,6 +550,7 @@ export declare class SourceService {
500
550
  private buildValidateMixinOutput;
501
551
  validateAccessWidener(input: ValidateAccessWidenerInput): Promise<ValidateAccessWidenerOutput>;
502
552
  validateAccessTransformer(input: ValidateAccessTransformerInput): Promise<ValidateAccessTransformerOutput>;
553
+ recordToolCall(tool: string, durationMs: number): void;
503
554
  getRuntimeMetrics(): RuntimeMetricSnapshot;
504
555
  indexArtifact(input: IndexArtifactInput): Promise<IndexArtifactOutput>;
505
556
  private searchSymbolIntent;
@@ -511,6 +562,11 @@ export declare class SourceService {
511
562
  private indexedCandidateLimit;
512
563
  private indexedCandidateLimitForMatch;
513
564
  private extractClassMetadata;
565
+ private extractDecompiledMembers;
566
+ private computeLineBraceDepths;
567
+ private computeBraceRange;
568
+ private scanBraceRange;
569
+ private computeNestedTypeRanges;
514
570
  private resolveClassFilePath;
515
571
  private resolveBinaryFallbackArtifact;
516
572
  private buildProvenance;
@@ -529,13 +585,53 @@ export declare class SourceService {
529
585
  private buildRebuiltArtifactData;
530
586
  getArtifact(artifactId: string): ArtifactRow;
531
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;
532
610
  private loadFromSourceJar;
533
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;
534
629
  private enforceCacheLimits;
535
630
  private refreshCacheMetrics;
536
631
  private touchCacheMetrics;
537
632
  private upsertCacheMetrics;
538
633
  private removeCacheMetrics;
539
634
  private publishCacheMetrics;
635
+ private snapshotLruAccounting;
540
636
  }
541
637
  export {};