@adhisang/minecraft-modding-mcp 3.1.0 → 3.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.
- package/CHANGELOG.md +62 -34
- package/README.md +79 -100
- package/dist/access-transformer-parser.d.ts +17 -0
- package/dist/access-transformer-parser.js +97 -0
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +24 -0
- package/dist/config.js +19 -11
- package/dist/decompiler/vineflower.js +22 -21
- package/dist/entry-tools/analyze-mod-service.d.ts +4 -4
- package/dist/entry-tools/analyze-symbol-service.d.ts +22 -20
- package/dist/entry-tools/analyze-symbol-service.js +6 -3
- package/dist/entry-tools/inspect-minecraft-service.d.ts +166 -149
- package/dist/entry-tools/inspect-minecraft-service.js +318 -55
- package/dist/entry-tools/validate-project-service.d.ts +153 -16
- package/dist/entry-tools/validate-project-service.js +360 -23
- package/dist/gradle-paths.d.ts +4 -0
- package/dist/gradle-paths.js +57 -0
- package/dist/index.js +274 -13
- package/dist/mapping-pipeline-service.d.ts +3 -1
- package/dist/mapping-pipeline-service.js +16 -1
- package/dist/mapping-service.d.ts +5 -0
- package/dist/mapping-service.js +200 -84
- package/dist/minecraft-explorer-service.d.ts +13 -0
- package/dist/minecraft-explorer-service.js +8 -4
- package/dist/mixin-validator.d.ts +33 -2
- package/dist/mixin-validator.js +197 -11
- package/dist/mod-analyzer.d.ts +1 -0
- package/dist/mod-analyzer.js +17 -1
- package/dist/mod-decompile-service.js +4 -4
- package/dist/mod-remap-service.js +1 -54
- package/dist/mod-search-service.d.ts +1 -0
- package/dist/mod-search-service.js +84 -51
- package/dist/response-utils.d.ts +35 -0
- package/dist/response-utils.js +113 -0
- package/dist/source-jar-reader.d.ts +16 -0
- package/dist/source-jar-reader.js +103 -1
- package/dist/source-resolver.js +9 -10
- package/dist/source-service.d.ts +24 -2
- package/dist/source-service.js +1052 -139
- package/dist/tool-contract-manifest.js +74 -74
- package/dist/types.d.ts +17 -0
- package/dist/workspace-mapping-service.d.ts +13 -0
- package/dist/workspace-mapping-service.js +146 -14
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { createError, ERROR_CODES } from "../errors.js";
|
|
2
|
+
import { createError, ERROR_CODES, isAppError } from "../errors.js";
|
|
3
3
|
import { buildIncludeSchema, detailSchema, positiveIntSchema } from "./entry-tool-schema.js";
|
|
4
4
|
import { buildEntryToolResult, buildEntryToolMeta, createNextAction, createSummarySubject, createTruncationMeta } from "./response-contract.js";
|
|
5
5
|
import { capArray, nextActionsOrUndefined, resolveDetail, resolveInclude } from "./request-normalizers.js";
|
|
@@ -124,6 +124,32 @@ export const inspectMinecraftSchema = z.object(inspectMinecraftShape).superRefin
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
|
+
function hasPartialVanillaCoverage(artifact) {
|
|
128
|
+
return artifact?.qualityFlags.includes("partial-source-no-net-minecraft") === true
|
|
129
|
+
|| artifact?.artifactContents.sourceCoverage === "partial";
|
|
130
|
+
}
|
|
131
|
+
function looksLikeClassQuery(query) {
|
|
132
|
+
const trimmed = query.trim();
|
|
133
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$.]*$/.test(trimmed)) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
const simpleName = trimmed.split(".").at(-1) ?? trimmed;
|
|
137
|
+
return /^[A-Z_$]/.test(simpleName) || /^class_\d+(?:\$class_\d+)*$/.test(simpleName);
|
|
138
|
+
}
|
|
139
|
+
function classNameToFilePath(className) {
|
|
140
|
+
const topLevelClassName = className.split("$")[0] ?? className;
|
|
141
|
+
return `${topLevelClassName.replace(/\./g, "/")}.java`;
|
|
142
|
+
}
|
|
143
|
+
function isVanillaNamespacePath(filePath) {
|
|
144
|
+
return filePath.startsWith("net/minecraft/") || filePath.startsWith("com/mojang/");
|
|
145
|
+
}
|
|
146
|
+
function hitTargetsVanillaNamespace(hit) {
|
|
147
|
+
if (isVanillaNamespacePath(hit.filePath)) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
const qualifiedName = hit.symbol?.qualifiedName;
|
|
151
|
+
return qualifiedName?.startsWith("net.minecraft.") === true || qualifiedName?.startsWith("com.mojang.") === true;
|
|
152
|
+
}
|
|
127
153
|
export class InspectMinecraftService {
|
|
128
154
|
deps;
|
|
129
155
|
constructor(deps) {
|
|
@@ -200,11 +226,11 @@ export class InspectMinecraftService {
|
|
|
200
226
|
strictVersion: subject.strictVersion
|
|
201
227
|
};
|
|
202
228
|
}
|
|
203
|
-
async resolveClassArtifactReference(subject, classSubject) {
|
|
229
|
+
async resolveClassArtifactReference(subject, classSubject, task) {
|
|
204
230
|
if (subject.kind === "workspace") {
|
|
205
231
|
return this.resolveWorkspaceArtifactReference(subject, classSubject.artifact);
|
|
206
232
|
}
|
|
207
|
-
return this.resolveArtifactReference(classSubject);
|
|
233
|
+
return this.resolveArtifactReference(classSubject, task);
|
|
208
234
|
}
|
|
209
235
|
async resolveWorkspaceArtifactReference(subject, artifactRef) {
|
|
210
236
|
if (!artifactRef) {
|
|
@@ -280,15 +306,130 @@ export class InspectMinecraftService {
|
|
|
280
306
|
}
|
|
281
307
|
return subject;
|
|
282
308
|
}
|
|
283
|
-
async
|
|
309
|
+
async exampleVersionForSubject(subject) {
|
|
310
|
+
if ("projectPath" in subject && typeof subject.projectPath === "string") {
|
|
311
|
+
const detectedVersion = await this.deps.detectProjectMinecraftVersion(subject.projectPath);
|
|
312
|
+
if (detectedVersion) {
|
|
313
|
+
return detectedVersion;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return "<version>";
|
|
317
|
+
}
|
|
318
|
+
async buildArtifactContextSuggestedCall(task, subject) {
|
|
319
|
+
return {
|
|
320
|
+
tool: "inspect-minecraft",
|
|
321
|
+
params: {
|
|
322
|
+
task,
|
|
323
|
+
subject: {
|
|
324
|
+
...subject,
|
|
325
|
+
artifact: {
|
|
326
|
+
type: "resolve-target",
|
|
327
|
+
target: {
|
|
328
|
+
kind: "version",
|
|
329
|
+
value: await this.exampleVersionForSubject(subject)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
taskForSubject(subject) {
|
|
337
|
+
return this.resolveTask(undefined, subject);
|
|
338
|
+
}
|
|
339
|
+
invalidTaskSubjectError(task, subject) {
|
|
340
|
+
if (task === "class-source" && subject.kind === "version") {
|
|
341
|
+
throw createError({
|
|
342
|
+
code: ERROR_CODES.INVALID_INPUT,
|
|
343
|
+
message: "class-source requires a class subject; version subjects resolve artifacts, not class names.",
|
|
344
|
+
details: {
|
|
345
|
+
nextAction: "Retry class-source with subject.kind=class and attach artifact context, or use task=artifact to inspect the version first.",
|
|
346
|
+
suggestedCall: {
|
|
347
|
+
tool: "inspect-minecraft",
|
|
348
|
+
params: {
|
|
349
|
+
task: "class-source",
|
|
350
|
+
subject: {
|
|
351
|
+
kind: "class",
|
|
352
|
+
className: "net.minecraft.world.item.Item",
|
|
353
|
+
artifact: {
|
|
354
|
+
type: "resolve-target",
|
|
355
|
+
target: {
|
|
356
|
+
kind: "version",
|
|
357
|
+
value: subject.version
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const suggestedTask = this.taskForSubject(subject);
|
|
367
|
+
throw createError({
|
|
368
|
+
code: ERROR_CODES.INVALID_INPUT,
|
|
369
|
+
message: `${task} is not compatible with subject.kind="${subject.kind}".`,
|
|
370
|
+
details: {
|
|
371
|
+
nextAction: suggestedTask === "artifact"
|
|
372
|
+
? `Retry with task=artifact for this ${subject.kind} subject, or reshape the subject so it supplies the input that ${task} needs.`
|
|
373
|
+
: `Retry with task=${suggestedTask} for this subject, or reshape the subject so it supplies the input that ${task} needs.`,
|
|
374
|
+
suggestedCall: {
|
|
375
|
+
tool: "inspect-minecraft",
|
|
376
|
+
params: {
|
|
377
|
+
task: suggestedTask,
|
|
378
|
+
subject
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
async resolveBinaryBackedClass(className, input) {
|
|
385
|
+
if (!this.deps.checkSymbolExists || !input.version) {
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
let lookup;
|
|
389
|
+
try {
|
|
390
|
+
lookup = await this.deps.checkSymbolExists({
|
|
391
|
+
version: input.version,
|
|
392
|
+
kind: "class",
|
|
393
|
+
name: className,
|
|
394
|
+
sourceMapping: input.mapping ?? "obfuscated",
|
|
395
|
+
nameMode: className.includes(".") ? "fqcn" : "auto",
|
|
396
|
+
maxCandidates: 10
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
catch (caughtError) {
|
|
400
|
+
if (isAppError(caughtError)) {
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
throw caughtError;
|
|
404
|
+
}
|
|
405
|
+
const resolvedClassName = lookup.resolvedSymbol?.name;
|
|
406
|
+
if (!resolvedClassName) {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
className: resolvedClassName,
|
|
411
|
+
warnings: lookup.warnings
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
async resolveArtifactReference(subject, task) {
|
|
284
415
|
if (subject.kind === "artifact") {
|
|
285
416
|
return this.resolveArtifactRef(subject.artifact, subject);
|
|
286
417
|
}
|
|
287
418
|
if (subject.kind === "class" || subject.kind === "file" || subject.kind === "search") {
|
|
288
419
|
if (!subject.artifact) {
|
|
420
|
+
const suggestedTask = task
|
|
421
|
+
?? (subject.kind === "class"
|
|
422
|
+
? "class-overview"
|
|
423
|
+
: subject.kind === "search"
|
|
424
|
+
? "search"
|
|
425
|
+
: "file");
|
|
289
426
|
throw createError({
|
|
290
427
|
code: ERROR_CODES.INVALID_INPUT,
|
|
291
|
-
message: `${subject.kind} subject requires artifact context
|
|
428
|
+
message: `${subject.kind} subject requires artifact context.`,
|
|
429
|
+
details: {
|
|
430
|
+
nextAction: "Add subject.artifact or use subject.kind=workspace so inspect-minecraft can resolve the artifact first.",
|
|
431
|
+
suggestedCall: await this.buildArtifactContextSuggestedCall(suggestedTask, subject)
|
|
432
|
+
}
|
|
292
433
|
});
|
|
293
434
|
}
|
|
294
435
|
return this.resolveArtifactRef(subject.artifact, subject);
|
|
@@ -479,14 +620,11 @@ export class InspectMinecraftService {
|
|
|
479
620
|
}
|
|
480
621
|
async handleClassOverview(subject, detail, include) {
|
|
481
622
|
if (subject.kind !== "class" && !(subject.kind === "workspace" && subject.focus?.kind === "class")) {
|
|
482
|
-
|
|
483
|
-
code: ERROR_CODES.INVALID_INPUT,
|
|
484
|
-
message: "class-overview requires a class or workspace focus subject."
|
|
485
|
-
});
|
|
623
|
+
this.invalidTaskSubjectError("class-overview", subject);
|
|
486
624
|
}
|
|
487
625
|
const classSubject = this.buildClassSubject(subject);
|
|
488
626
|
const className = classSubject.className;
|
|
489
|
-
const artifact = await this.resolveClassArtifactReference(subject, classSubject);
|
|
627
|
+
const artifact = await this.resolveClassArtifactReference(subject, classSubject, "class-overview");
|
|
490
628
|
if (!artifact.artifactId) {
|
|
491
629
|
const summary = {
|
|
492
630
|
status: "blocked",
|
|
@@ -519,6 +657,69 @@ export class InspectMinecraftService {
|
|
|
519
657
|
limit: 10
|
|
520
658
|
});
|
|
521
659
|
if (matches.total === 0) {
|
|
660
|
+
const partialSourceFallback = subject.kind === "workspace" && hasPartialVanillaCoverage(artifact.artifact)
|
|
661
|
+
? await this.resolveBinaryBackedClass(className, {
|
|
662
|
+
version: artifact.version,
|
|
663
|
+
mapping: classSubject.mapping
|
|
664
|
+
})
|
|
665
|
+
: undefined;
|
|
666
|
+
if (partialSourceFallback) {
|
|
667
|
+
const metadata = await this.deps.getClassSource({
|
|
668
|
+
className: partialSourceFallback.className,
|
|
669
|
+
artifactId: artifact.artifactId,
|
|
670
|
+
mapping: classSubject.mapping,
|
|
671
|
+
scope: classSubject.scope,
|
|
672
|
+
projectPath: classSubject.projectPath,
|
|
673
|
+
preferProjectVersion: classSubject.preferProjectVersion,
|
|
674
|
+
strictVersion: classSubject.strictVersion,
|
|
675
|
+
mode: "metadata"
|
|
676
|
+
});
|
|
677
|
+
const summary = {
|
|
678
|
+
status: "ok",
|
|
679
|
+
headline: `Resolved class overview for ${partialSourceFallback.className}.`,
|
|
680
|
+
subject: createSummarySubject({
|
|
681
|
+
task: "class-overview",
|
|
682
|
+
requested: subject,
|
|
683
|
+
className: partialSourceFallback.className,
|
|
684
|
+
artifactId: metadata.artifactId
|
|
685
|
+
}),
|
|
686
|
+
counts: {
|
|
687
|
+
totalLines: metadata.totalLines
|
|
688
|
+
},
|
|
689
|
+
notes: [
|
|
690
|
+
"Source coverage was partial, so inspect-minecraft confirmed the vanilla class through binary-backed symbol lookup."
|
|
691
|
+
]
|
|
692
|
+
};
|
|
693
|
+
return {
|
|
694
|
+
...buildEntryToolResult({
|
|
695
|
+
task: "class-overview",
|
|
696
|
+
summary,
|
|
697
|
+
detail,
|
|
698
|
+
include,
|
|
699
|
+
blocks: {
|
|
700
|
+
subject: {
|
|
701
|
+
requested: subject,
|
|
702
|
+
resolved: {
|
|
703
|
+
artifactId: metadata.artifactId,
|
|
704
|
+
className: partialSourceFallback.className
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
class: {
|
|
708
|
+
className: partialSourceFallback.className,
|
|
709
|
+
totalLines: metadata.totalLines,
|
|
710
|
+
returnedNamespace: metadata.returnedNamespace
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
alwaysBlocks: ["subject"]
|
|
714
|
+
}),
|
|
715
|
+
warnings: [
|
|
716
|
+
...artifact.warnings,
|
|
717
|
+
...matches.warnings,
|
|
718
|
+
...partialSourceFallback.warnings,
|
|
719
|
+
...metadata.warnings
|
|
720
|
+
]
|
|
721
|
+
};
|
|
722
|
+
}
|
|
522
723
|
const summary = {
|
|
523
724
|
status: "not_found",
|
|
524
725
|
headline: `No class match was found for ${className}.`,
|
|
@@ -663,14 +864,11 @@ export class InspectMinecraftService {
|
|
|
663
864
|
}
|
|
664
865
|
async handleClassSource(subject, detail, include) {
|
|
665
866
|
if (subject.kind !== "class" && !(subject.kind === "workspace" && subject.focus?.kind === "class")) {
|
|
666
|
-
|
|
667
|
-
code: ERROR_CODES.INVALID_INPUT,
|
|
668
|
-
message: "class-source requires a class or workspace focus subject."
|
|
669
|
-
});
|
|
867
|
+
this.invalidTaskSubjectError("class-source", subject);
|
|
670
868
|
}
|
|
671
869
|
const classSubject = this.buildClassSubject(subject);
|
|
672
870
|
const className = classSubject.className;
|
|
673
|
-
const artifactContext = await this.resolveClassArtifactReference(subject, classSubject);
|
|
871
|
+
const artifactContext = await this.resolveClassArtifactReference(subject, classSubject, "class-source");
|
|
674
872
|
const source = await this.deps.getClassSource({
|
|
675
873
|
className,
|
|
676
874
|
artifactId: artifactContext.artifactId || undefined,
|
|
@@ -723,13 +921,10 @@ export class InspectMinecraftService {
|
|
|
723
921
|
}
|
|
724
922
|
async handleClassMembers(subject, detail, include, limit) {
|
|
725
923
|
if (subject.kind !== "class" && !(subject.kind === "workspace" && subject.focus?.kind === "class")) {
|
|
726
|
-
|
|
727
|
-
code: ERROR_CODES.INVALID_INPUT,
|
|
728
|
-
message: "class-members requires a class or workspace focus subject."
|
|
729
|
-
});
|
|
924
|
+
this.invalidTaskSubjectError("class-members", subject);
|
|
730
925
|
}
|
|
731
926
|
const classSubject = this.buildClassSubject(subject);
|
|
732
|
-
const artifact = await this.resolveClassArtifactReference(subject, classSubject);
|
|
927
|
+
const artifact = await this.resolveClassArtifactReference(subject, classSubject, "class-members");
|
|
733
928
|
const members = await this.deps.getClassMembers({
|
|
734
929
|
className: classSubject.className,
|
|
735
930
|
artifactId: artifact.artifactId || undefined,
|
|
@@ -798,16 +993,13 @@ export class InspectMinecraftService {
|
|
|
798
993
|
}
|
|
799
994
|
async handleSearch(subject, detail, include, limit, cursor) {
|
|
800
995
|
if (subject.kind !== "search" && !(subject.kind === "workspace" && subject.focus?.kind === "search")) {
|
|
801
|
-
|
|
802
|
-
code: ERROR_CODES.INVALID_INPUT,
|
|
803
|
-
message: "search requires a search or workspace focus subject."
|
|
804
|
-
});
|
|
996
|
+
this.invalidTaskSubjectError("search", subject);
|
|
805
997
|
}
|
|
806
998
|
const searchSubject = subject.kind === "search" ? subject : this.requireWorkspaceSearchFocus(subject);
|
|
807
999
|
const requestedSubject = this.summarizeRequestedSubject(subject);
|
|
808
1000
|
const queryMode = searchSubject.queryMode ?? "auto";
|
|
809
1001
|
const artifact = subject.kind === "search"
|
|
810
|
-
? await this.resolveArtifactReference(subject)
|
|
1002
|
+
? await this.resolveArtifactReference(subject, "search")
|
|
811
1003
|
: await this.resolveWorkspaceArtifactReference(subject, searchSubject.artifact);
|
|
812
1004
|
const search = await this.deps.searchClassSource({
|
|
813
1005
|
artifactId: artifact.artifactId,
|
|
@@ -825,8 +1017,38 @@ export class InspectMinecraftService {
|
|
|
825
1017
|
}
|
|
826
1018
|
: undefined
|
|
827
1019
|
});
|
|
828
|
-
const
|
|
829
|
-
|
|
1020
|
+
const needsBinaryBackedClassHit = subject.kind === "workspace" &&
|
|
1021
|
+
hasPartialVanillaCoverage(artifact.artifact) &&
|
|
1022
|
+
looksLikeClassQuery(searchSubject.query) &&
|
|
1023
|
+
!search.hits.some((hit) => hitTargetsVanillaNamespace(hit));
|
|
1024
|
+
const binaryBackedClassHit = needsBinaryBackedClassHit
|
|
1025
|
+
? await this.resolveBinaryBackedClass(searchSubject.query, {
|
|
1026
|
+
version: artifact.version,
|
|
1027
|
+
mapping: subject.mapping
|
|
1028
|
+
})
|
|
1029
|
+
: undefined;
|
|
1030
|
+
const binaryBackedHitRecord = binaryBackedClassHit == null
|
|
1031
|
+
? undefined
|
|
1032
|
+
: {
|
|
1033
|
+
filePath: classNameToFilePath(binaryBackedClassHit.className),
|
|
1034
|
+
score: 100,
|
|
1035
|
+
matchedIn: "symbol",
|
|
1036
|
+
reasonCodes: ["binary-class-lookup"],
|
|
1037
|
+
symbol: {
|
|
1038
|
+
symbolKind: "class",
|
|
1039
|
+
symbolName: binaryBackedClassHit.className.split(".").at(-1) ?? binaryBackedClassHit.className,
|
|
1040
|
+
qualifiedName: binaryBackedClassHit.className,
|
|
1041
|
+
line: 1
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
const effectiveHits = binaryBackedHitRecord == null
|
|
1045
|
+
? search.hits
|
|
1046
|
+
: [
|
|
1047
|
+
binaryBackedHitRecord,
|
|
1048
|
+
...search.hits.filter((hit) => hit.filePath !== binaryBackedHitRecord.filePath)
|
|
1049
|
+
];
|
|
1050
|
+
const sampledHits = capArray(effectiveHits, 5);
|
|
1051
|
+
const isAutoSeparatorMiss = effectiveHits.length === 0 &&
|
|
830
1052
|
queryMode === "auto" &&
|
|
831
1053
|
/[._$]/.test(searchSubject.query);
|
|
832
1054
|
const literalRetrySubject = subject.kind === "search"
|
|
@@ -843,9 +1065,9 @@ export class InspectMinecraftService {
|
|
|
843
1065
|
}
|
|
844
1066
|
};
|
|
845
1067
|
const summary = {
|
|
846
|
-
status:
|
|
847
|
-
headline:
|
|
848
|
-
? `Found ${
|
|
1068
|
+
status: effectiveHits.length > 0 ? "ok" : "not_found",
|
|
1069
|
+
headline: effectiveHits.length > 0
|
|
1070
|
+
? `Found ${effectiveHits.length} source hits for ${searchSubject.query}.`
|
|
849
1071
|
: `No source hits were found for ${searchSubject.query}.`,
|
|
850
1072
|
subject: createSummarySubject({
|
|
851
1073
|
task: "search",
|
|
@@ -854,16 +1076,16 @@ export class InspectMinecraftService {
|
|
|
854
1076
|
artifactId: artifact.artifactId
|
|
855
1077
|
}),
|
|
856
1078
|
counts: {
|
|
857
|
-
hits:
|
|
1079
|
+
hits: effectiveHits.length
|
|
858
1080
|
},
|
|
859
1081
|
nextActions: nextActionsOrUndefined([
|
|
860
|
-
...(
|
|
1082
|
+
...(effectiveHits.length > 0
|
|
861
1083
|
? [
|
|
862
1084
|
createNextAction("inspect-minecraft", {
|
|
863
1085
|
task: "file",
|
|
864
1086
|
subject: {
|
|
865
1087
|
kind: "file",
|
|
866
|
-
filePath:
|
|
1088
|
+
filePath: effectiveHits[0].filePath,
|
|
867
1089
|
artifact: {
|
|
868
1090
|
type: "resolved-id",
|
|
869
1091
|
artifactId: artifact.artifactId
|
|
@@ -888,7 +1110,13 @@ export class InspectMinecraftService {
|
|
|
888
1110
|
"Separator query returned no indexed hits. Retry with queryMode=\"literal\" for an explicit full substring scan."
|
|
889
1111
|
]
|
|
890
1112
|
}
|
|
891
|
-
:
|
|
1113
|
+
: binaryBackedClassHit
|
|
1114
|
+
? {
|
|
1115
|
+
notes: [
|
|
1116
|
+
"Source coverage was partial, so inspect-minecraft returned a binary-backed class match for the vanilla symbol."
|
|
1117
|
+
]
|
|
1118
|
+
}
|
|
1119
|
+
: {})
|
|
892
1120
|
};
|
|
893
1121
|
return {
|
|
894
1122
|
...buildEntryToolResult({
|
|
@@ -905,25 +1133,22 @@ export class InspectMinecraftService {
|
|
|
905
1133
|
},
|
|
906
1134
|
search: {
|
|
907
1135
|
query: searchSubject.query,
|
|
908
|
-
hits: detail === "summary" ? sampledHits.items :
|
|
1136
|
+
hits: detail === "summary" ? sampledHits.items : effectiveHits,
|
|
909
1137
|
nextCursor: search.nextCursor
|
|
910
1138
|
}
|
|
911
1139
|
},
|
|
912
1140
|
alwaysBlocks: ["subject"]
|
|
913
1141
|
}),
|
|
914
|
-
warnings: [...artifact.warnings]
|
|
1142
|
+
warnings: [...artifact.warnings, ...(binaryBackedClassHit?.warnings ?? [])]
|
|
915
1143
|
};
|
|
916
1144
|
}
|
|
917
1145
|
async handleFile(subject, detail, include) {
|
|
918
1146
|
if (subject.kind !== "file" && !(subject.kind === "workspace" && subject.focus?.kind === "file")) {
|
|
919
|
-
|
|
920
|
-
code: ERROR_CODES.INVALID_INPUT,
|
|
921
|
-
message: "file task requires a file or workspace focus subject."
|
|
922
|
-
});
|
|
1147
|
+
this.invalidTaskSubjectError("file", subject);
|
|
923
1148
|
}
|
|
924
1149
|
const fileSubject = subject.kind === "file" ? subject : this.requireWorkspaceFileFocus(subject);
|
|
925
1150
|
const artifact = subject.kind === "file"
|
|
926
|
-
? await this.resolveArtifactReference(subject)
|
|
1151
|
+
? await this.resolveArtifactReference(subject, "file")
|
|
927
1152
|
: await this.resolveWorkspaceArtifactReference(subject, fileSubject.artifact);
|
|
928
1153
|
const file = await this.deps.getArtifactFile({
|
|
929
1154
|
artifactId: artifact.artifactId,
|
|
@@ -969,25 +1194,16 @@ export class InspectMinecraftService {
|
|
|
969
1194
|
};
|
|
970
1195
|
}
|
|
971
1196
|
async handleListFiles(subject, detail, include, limit, cursor) {
|
|
972
|
-
const artifact = await this.resolveArtifactReference(subject);
|
|
1197
|
+
const artifact = await this.resolveArtifactReference(subject, "list-files");
|
|
973
1198
|
const files = await this.deps.listArtifactFiles({
|
|
974
1199
|
artifactId: artifact.artifactId,
|
|
975
1200
|
limit,
|
|
976
1201
|
cursor
|
|
977
1202
|
});
|
|
978
1203
|
const sampled = capArray(files.items, 10);
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
subject: createSummarySubject({
|
|
983
|
-
task: "list-files",
|
|
984
|
-
requested: subject,
|
|
985
|
-
artifactId: artifact.artifactId
|
|
986
|
-
}),
|
|
987
|
-
counts: {
|
|
988
|
-
files: files.items.length
|
|
989
|
-
},
|
|
990
|
-
nextActions: nextActionsOrUndefined(files.items.length > 0
|
|
1204
|
+
const partialCoverage = subject.kind === "workspace" && hasPartialVanillaCoverage(artifact.artifact);
|
|
1205
|
+
const nextActions = [
|
|
1206
|
+
...(files.items.length > 0
|
|
991
1207
|
? [
|
|
992
1208
|
createNextAction("inspect-minecraft", {
|
|
993
1209
|
task: "file",
|
|
@@ -1001,7 +1217,46 @@ export class InspectMinecraftService {
|
|
|
1001
1217
|
}
|
|
1002
1218
|
})
|
|
1003
1219
|
]
|
|
1220
|
+
: []),
|
|
1221
|
+
...(partialCoverage
|
|
1222
|
+
? [
|
|
1223
|
+
createNextAction("inspect-minecraft", {
|
|
1224
|
+
task: "class-source",
|
|
1225
|
+
subject: {
|
|
1226
|
+
kind: "workspace",
|
|
1227
|
+
projectPath: subject.projectPath,
|
|
1228
|
+
mapping: subject.mapping,
|
|
1229
|
+
scope: subject.scope,
|
|
1230
|
+
preferProjectVersion: subject.preferProjectVersion,
|
|
1231
|
+
strictVersion: subject.strictVersion,
|
|
1232
|
+
focus: {
|
|
1233
|
+
kind: "class",
|
|
1234
|
+
className: "net.minecraft.world.item.Item"
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
})
|
|
1238
|
+
]
|
|
1004
1239
|
: [])
|
|
1240
|
+
];
|
|
1241
|
+
const summary = {
|
|
1242
|
+
status: partialCoverage ? "partial" : "ok",
|
|
1243
|
+
headline: `Listed ${files.items.length} files for ${artifact.artifactId}.`,
|
|
1244
|
+
subject: createSummarySubject({
|
|
1245
|
+
task: "list-files",
|
|
1246
|
+
requested: subject,
|
|
1247
|
+
artifactId: artifact.artifactId
|
|
1248
|
+
}),
|
|
1249
|
+
counts: {
|
|
1250
|
+
files: files.items.length
|
|
1251
|
+
},
|
|
1252
|
+
nextActions: nextActionsOrUndefined(nextActions),
|
|
1253
|
+
...(partialCoverage
|
|
1254
|
+
? {
|
|
1255
|
+
notes: [
|
|
1256
|
+
"This listing is partial because the resolved source artifact does not contain net.minecraft entries."
|
|
1257
|
+
]
|
|
1258
|
+
}
|
|
1259
|
+
: {})
|
|
1005
1260
|
};
|
|
1006
1261
|
return {
|
|
1007
1262
|
...buildEntryToolResult({
|
|
@@ -1018,7 +1273,15 @@ export class InspectMinecraftService {
|
|
|
1018
1273
|
},
|
|
1019
1274
|
files: {
|
|
1020
1275
|
items: detail === "summary" ? sampled.items : files.items,
|
|
1021
|
-
nextCursor: files.nextCursor
|
|
1276
|
+
nextCursor: files.nextCursor,
|
|
1277
|
+
...(partialCoverage
|
|
1278
|
+
? {
|
|
1279
|
+
coverage: {
|
|
1280
|
+
sourceCoverage: "partial",
|
|
1281
|
+
missingNamespaces: ["net.minecraft"]
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
: {})
|
|
1022
1285
|
}
|
|
1023
1286
|
},
|
|
1024
1287
|
alwaysBlocks: ["subject"]
|