@adhisang/minecraft-modding-mcp 4.0.0 → 4.1.1
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 +61 -0
- package/README.md +40 -23
- package/dist/build-suggested-call.d.ts +29 -0
- package/dist/build-suggested-call.js +58 -0
- package/dist/cache-registry.d.ts +3 -1
- package/dist/cache-registry.js +50 -6
- package/dist/entry-tools/analyze-symbol-service.d.ts +16 -16
- package/dist/entry-tools/batch-class-members-service.d.ts +34 -0
- package/dist/entry-tools/batch-class-members-service.js +97 -0
- package/dist/entry-tools/batch-class-source-service.d.ts +37 -0
- package/dist/entry-tools/batch-class-source-service.js +100 -0
- package/dist/entry-tools/batch-mappings-service.d.ts +36 -0
- package/dist/entry-tools/batch-mappings-service.js +66 -0
- package/dist/entry-tools/batch-runner.d.ts +72 -0
- package/dist/entry-tools/batch-runner.js +90 -0
- package/dist/entry-tools/batch-symbol-exists-service.d.ts +46 -0
- package/dist/entry-tools/batch-symbol-exists-service.js +113 -0
- package/dist/entry-tools/compare-minecraft-service.d.ts +6 -6
- package/dist/entry-tools/inspect-minecraft/handlers/artifact.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +83 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-members.d.ts +6 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +80 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-overview.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +248 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-source.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +60 -0
- package/dist/entry-tools/inspect-minecraft/handlers/file.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/file.js +54 -0
- package/dist/entry-tools/inspect-minecraft/handlers/list-files.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +100 -0
- package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +5 -0
- package/dist/entry-tools/inspect-minecraft/handlers/search.js +155 -0
- package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +6 -0
- package/dist/entry-tools/inspect-minecraft/handlers/versions.js +49 -0
- package/dist/entry-tools/inspect-minecraft/internal.d.ts +1042 -0
- package/dist/entry-tools/inspect-minecraft/internal.js +448 -0
- package/dist/entry-tools/inspect-minecraft-service.d.ts +193 -308
- package/dist/entry-tools/inspect-minecraft-service.js +20 -1244
- package/dist/entry-tools/manage-cache-service.d.ts +16 -16
- package/dist/entry-tools/validate-project/cases/access-transformer.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/access-transformer.js +106 -0
- package/dist/entry-tools/validate-project/cases/access-widener.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/access-widener.js +86 -0
- package/dist/entry-tools/validate-project/cases/mixin.d.ts +6 -0
- package/dist/entry-tools/validate-project/cases/mixin.js +90 -0
- package/dist/entry-tools/validate-project/cases/project-summary.d.ts +102 -0
- package/dist/entry-tools/validate-project/cases/project-summary.js +415 -0
- package/dist/entry-tools/validate-project/internal.d.ts +142 -0
- package/dist/entry-tools/validate-project/internal.js +303 -0
- package/dist/entry-tools/validate-project-service.d.ts +67 -47
- package/dist/entry-tools/validate-project-service.js +13 -563
- package/dist/entry-tools/verify-mixin-target-service.d.ts +133 -0
- package/dist/entry-tools/verify-mixin-target-service.js +323 -0
- package/dist/error-mapping.d.ts +40 -0
- package/dist/error-mapping.js +139 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +147 -1354
- package/dist/mapping/internal-types.d.ts +54 -0
- package/dist/mapping/internal-types.js +14 -0
- package/dist/mapping/loaders/mojang.d.ts +2 -0
- package/dist/mapping/loaders/mojang.js +64 -0
- package/dist/mapping/loaders/tiny-loom.d.ts +2 -0
- package/dist/mapping/loaders/tiny-loom.js +73 -0
- package/dist/mapping/loaders/tiny-maven.d.ts +2 -0
- package/dist/mapping/loaders/tiny-maven.js +104 -0
- package/dist/mapping/loaders/types.d.ts +14 -0
- package/dist/mapping/loaders/types.js +2 -0
- package/dist/mapping/lookup.d.ts +52 -0
- package/dist/mapping/lookup.js +496 -0
- package/dist/mapping/parsers/normalize.d.ts +10 -0
- package/dist/mapping/parsers/normalize.js +52 -0
- package/dist/mapping/parsers/proguard.d.ts +20 -0
- package/dist/mapping/parsers/proguard.js +138 -0
- package/dist/mapping/parsers/symbol-records.d.ts +27 -0
- package/dist/mapping/parsers/symbol-records.js +216 -0
- package/dist/mapping/parsers/tiny.d.ts +9 -0
- package/dist/mapping/parsers/tiny.js +96 -0
- package/dist/mapping/types.d.ts +147 -0
- package/dist/mapping/types.js +2 -0
- package/dist/mapping-pipeline-service.js +3 -2
- package/dist/mapping-service.d.ts +8 -145
- package/dist/mapping-service.js +30 -1207
- package/dist/mixin/access-validators.d.ts +9 -0
- package/dist/mixin/access-validators.js +257 -0
- package/dist/mixin/annotation-validators.d.ts +5 -0
- package/dist/mixin/annotation-validators.js +162 -0
- package/dist/mixin/helpers.d.ts +28 -0
- package/dist/mixin/helpers.js +315 -0
- package/dist/mixin/parsed-validator.d.ts +8 -0
- package/dist/mixin/parsed-validator.js +337 -0
- package/dist/mixin/types.d.ts +208 -0
- package/dist/mixin/types.js +28 -0
- package/dist/mixin-validator.d.ts +9 -201
- package/dist/mixin-validator.js +8 -1020
- package/dist/source/access-validate.d.ts +4 -0
- package/dist/source/access-validate.js +254 -0
- package/dist/source/artifact-resolver.d.ts +111 -0
- package/dist/source/artifact-resolver.js +1271 -0
- package/dist/source/cache-metrics.d.ts +26 -0
- package/dist/source/cache-metrics.js +172 -0
- package/dist/source/class-source/members-builder.d.ts +34 -0
- package/dist/source/class-source/members-builder.js +46 -0
- package/dist/source/class-source/snippet-builder.d.ts +19 -0
- package/dist/source/class-source/snippet-builder.js +46 -0
- package/dist/source/class-source-helpers.d.ts +34 -0
- package/dist/source/class-source-helpers.js +140 -0
- package/dist/source/class-source.d.ts +42 -0
- package/dist/source/class-source.js +883 -0
- package/dist/source/descriptor-utils.d.ts +6 -0
- package/dist/source/descriptor-utils.js +37 -0
- package/dist/source/file-access.d.ts +4 -0
- package/dist/source/file-access.js +102 -0
- package/dist/source/indexer.d.ts +82 -0
- package/dist/source/indexer.js +522 -0
- package/dist/source/lifecycle/diff-utils.d.ts +9 -0
- package/dist/source/lifecycle/diff-utils.js +107 -0
- package/dist/source/lifecycle/diff.d.ts +2 -0
- package/dist/source/lifecycle/diff.js +265 -0
- package/dist/source/lifecycle/mapping-helpers.d.ts +22 -0
- package/dist/source/lifecycle/mapping-helpers.js +327 -0
- package/dist/source/lifecycle/runtime-check.d.ts +2 -0
- package/dist/source/lifecycle/runtime-check.js +142 -0
- package/dist/source/lifecycle/trace.d.ts +2 -0
- package/dist/source/lifecycle/trace.js +231 -0
- package/dist/source/lifecycle.d.ts +4 -0
- package/dist/source/lifecycle.js +5 -0
- package/dist/source/search.d.ts +51 -0
- package/dist/source/search.js +676 -0
- package/dist/source/shared-utils.d.ts +6 -0
- package/dist/source/shared-utils.js +55 -0
- package/dist/source/state.d.ts +26 -0
- package/dist/source/state.js +24 -0
- package/dist/source/symbol-resolver.d.ts +3 -0
- package/dist/source/symbol-resolver.js +212 -0
- package/dist/source/validate-mixin/pipeline/mapping-health.d.ts +3 -0
- package/dist/source/validate-mixin/pipeline/mapping-health.js +41 -0
- package/dist/source/validate-mixin/pipeline/parse.d.ts +2 -0
- package/dist/source/validate-mixin/pipeline/parse.js +10 -0
- package/dist/source/validate-mixin/pipeline/resolve.d.ts +3 -0
- package/dist/source/validate-mixin/pipeline/resolve.js +78 -0
- package/dist/source/validate-mixin/pipeline/target-lookup.d.ts +6 -0
- package/dist/source/validate-mixin/pipeline/target-lookup.js +260 -0
- package/dist/source/validate-mixin/pipeline-context.d.ts +72 -0
- package/dist/source/validate-mixin/pipeline-context.js +93 -0
- package/dist/source/validate-mixin.d.ts +22 -0
- package/dist/source/validate-mixin.js +799 -0
- package/dist/source/workspace-target.d.ts +18 -0
- package/dist/source/workspace-target.js +305 -0
- package/dist/source-resolver.d.ts +1 -0
- package/dist/source-resolver.js +1 -1
- package/dist/source-service.d.ts +164 -170
- package/dist/source-service.js +70 -6116
- package/dist/stage-emitter.d.ts +13 -0
- package/dist/stage-emitter.js +30 -0
- package/dist/stdio-supervisor.d.ts +61 -0
- package/dist/stdio-supervisor.js +326 -9
- package/dist/tool-contract-manifest.d.ts +1 -1
- package/dist/tool-contract-manifest.js +23 -6
- package/dist/tool-guidance.d.ts +82 -0
- package/dist/tool-guidance.js +734 -0
- package/dist/tool-schema-registry.d.ts +16 -0
- package/dist/tool-schema-registry.js +37 -0
- package/dist/tool-schemas.d.ts +3518 -0
- package/dist/tool-schemas.js +813 -0
- package/dist/types.d.ts +36 -0
- package/dist/version-service.js +7 -6
- package/dist/workspace-context-cache.d.ts +32 -0
- package/dist/workspace-context-cache.js +66 -0
- package/dist/workspace-mapping-service.d.ts +16 -0
- package/dist/workspace-mapping-service.js +173 -1
- package/docs/README-ja.md +416 -0
- package/docs/examples.md +483 -0
- package/docs/tool-reference.md +462 -0
- package/package.json +17 -4
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
import { buildSuggestedCall } from "./build-suggested-call.js";
|
|
3
|
+
import { ERROR_CODES, isAppError } from "./errors.js";
|
|
4
|
+
import { statusForErrorCode } from "./error-mapping.js";
|
|
5
|
+
export const SUGGESTED_CALL_DEFAULTS = {
|
|
6
|
+
allowDecompile: true,
|
|
7
|
+
preferProjectVersion: false,
|
|
8
|
+
strictVersion: false,
|
|
9
|
+
mode: "metadata",
|
|
10
|
+
access: "public",
|
|
11
|
+
includeSynthetic: false,
|
|
12
|
+
includeInherited: false,
|
|
13
|
+
hideUncertain: false,
|
|
14
|
+
explain: false,
|
|
15
|
+
preferProjectMapping: false,
|
|
16
|
+
minSeverity: "all",
|
|
17
|
+
reportMode: "full",
|
|
18
|
+
treatInfoAsWarning: true,
|
|
19
|
+
includeIssues: true
|
|
20
|
+
};
|
|
21
|
+
export function isSuggestedCallDefault(field, value) {
|
|
22
|
+
return value === SUGGESTED_CALL_DEFAULTS[field];
|
|
23
|
+
}
|
|
24
|
+
export const ANALYZE_MOD_INCLUDE_GROUPS = ["warnings", "files", "source", "samples", "timings"];
|
|
25
|
+
export const ANALYZE_MOD_LEGACY_METADATA_INCLUDES = ["metadata", "entrypoints", "mixins", "dependencies"];
|
|
26
|
+
export const VALIDATE_PROJECT_INCLUDE_GROUPS = ["warnings", "issues", "workspace", "recovery"];
|
|
27
|
+
export const VALIDATE_PROJECT_LEGACY_WORKSPACE_INCLUDES = ["detectedConfig", "mixins", "accessWideners"];
|
|
28
|
+
export const VALIDATION_FALLBACK_HINT = "suggested call payload failed schema validation; using fallback examples";
|
|
29
|
+
export function toFieldErrorsFromZod(error) {
|
|
30
|
+
return error.issues.map((issue) => ({
|
|
31
|
+
path: issue.path.join(".") || "$",
|
|
32
|
+
message: issue.message,
|
|
33
|
+
code: issue.code
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
export function toHints(details) {
|
|
37
|
+
if (typeof details !== "object" || details == null) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const hints = [];
|
|
41
|
+
const maybeNextAction = details.nextAction;
|
|
42
|
+
if (typeof maybeNextAction === "string" && maybeNextAction.trim()) {
|
|
43
|
+
hints.push(maybeNextAction.trim());
|
|
44
|
+
}
|
|
45
|
+
if (hints.length === 0) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return hints;
|
|
49
|
+
}
|
|
50
|
+
export function extractValidatedSuggestionAndExamples(details) {
|
|
51
|
+
if (typeof details !== "object" || details == null) {
|
|
52
|
+
return { primaryDropped: false };
|
|
53
|
+
}
|
|
54
|
+
const record = details;
|
|
55
|
+
let primaryDropped = record._suggestedCallPrimaryDropped === true;
|
|
56
|
+
let suggestedCall;
|
|
57
|
+
const rawSuggested = record.suggestedCall;
|
|
58
|
+
if (rawSuggested !== undefined) {
|
|
59
|
+
if (typeof rawSuggested === "object" &&
|
|
60
|
+
rawSuggested !== null &&
|
|
61
|
+
!Array.isArray(rawSuggested)) {
|
|
62
|
+
const call = rawSuggested;
|
|
63
|
+
if (typeof call.tool === "string" &&
|
|
64
|
+
typeof call.params === "object" &&
|
|
65
|
+
call.params !== null &&
|
|
66
|
+
!Array.isArray(call.params)) {
|
|
67
|
+
const validated = buildSuggestedCall({
|
|
68
|
+
tool: call.tool,
|
|
69
|
+
params: call.params
|
|
70
|
+
});
|
|
71
|
+
if (validated.suggestedCall) {
|
|
72
|
+
suggestedCall = validated.suggestedCall;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
primaryDropped = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
primaryDropped = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
primaryDropped = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let exampleCalls;
|
|
87
|
+
const rawExamples = record.exampleCalls;
|
|
88
|
+
if (Array.isArray(rawExamples)) {
|
|
89
|
+
const validated = [];
|
|
90
|
+
for (const entry of rawExamples) {
|
|
91
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
92
|
+
continue;
|
|
93
|
+
const ex = entry;
|
|
94
|
+
if (typeof ex.tool !== "string" ||
|
|
95
|
+
typeof ex.params !== "object" ||
|
|
96
|
+
ex.params === null ||
|
|
97
|
+
Array.isArray(ex.params) ||
|
|
98
|
+
typeof ex.reason !== "string") {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const result = buildSuggestedCall({
|
|
102
|
+
tool: ex.tool,
|
|
103
|
+
params: ex.params
|
|
104
|
+
});
|
|
105
|
+
if (result.suggestedCall) {
|
|
106
|
+
validated.push({
|
|
107
|
+
tool: ex.tool,
|
|
108
|
+
params: result.suggestedCall.params,
|
|
109
|
+
reason: ex.reason
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (validated.length > 0) {
|
|
114
|
+
exampleCalls = validated;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { suggestedCall, exampleCalls, primaryDropped };
|
|
118
|
+
}
|
|
119
|
+
export function extractFailedStageFromDetails(details) {
|
|
120
|
+
if (typeof details !== "object" || details == null) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const maybeStage = details.failedStage;
|
|
124
|
+
if (typeof maybeStage === "string" && maybeStage.trim().length > 0) {
|
|
125
|
+
return maybeStage;
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
export function extractFieldErrorsFromDetails(details) {
|
|
130
|
+
if (typeof details !== "object" || details == null) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const maybeFieldErrors = details.fieldErrors;
|
|
134
|
+
if (!Array.isArray(maybeFieldErrors)) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const normalized = maybeFieldErrors
|
|
138
|
+
.map((entry) => {
|
|
139
|
+
if (typeof entry !== "object" || entry == null) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const asRecord = entry;
|
|
143
|
+
const path = asRecord.path;
|
|
144
|
+
const message = asRecord.message;
|
|
145
|
+
const code = asRecord.code;
|
|
146
|
+
if (typeof path !== "string" || typeof message !== "string") {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
path,
|
|
151
|
+
message,
|
|
152
|
+
code: typeof code === "string" ? code : undefined
|
|
153
|
+
};
|
|
154
|
+
})
|
|
155
|
+
.filter((entry) => entry != null);
|
|
156
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
157
|
+
}
|
|
158
|
+
export function asObjectRecord(value) {
|
|
159
|
+
return typeof value === "object" && value != null && !Array.isArray(value)
|
|
160
|
+
? value
|
|
161
|
+
: undefined;
|
|
162
|
+
}
|
|
163
|
+
export function asNonEmptyString(value) {
|
|
164
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
165
|
+
}
|
|
166
|
+
export function asStringArray(value) {
|
|
167
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.trim())
|
|
168
|
+
? value
|
|
169
|
+
: undefined;
|
|
170
|
+
}
|
|
171
|
+
export function truncateSuggestionText(value, maxLength = 500) {
|
|
172
|
+
return value.length > maxLength
|
|
173
|
+
? `${value.slice(0, maxLength)}...`
|
|
174
|
+
: value;
|
|
175
|
+
}
|
|
176
|
+
export function parseJsonObjectString(value) {
|
|
177
|
+
if (!value.trim().startsWith("{")) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const parsed = JSON.parse(value);
|
|
182
|
+
return asObjectRecord(parsed);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function inferTargetKindFromString(value) {
|
|
189
|
+
if (/[\\/]/.test(value) || /\.jar$/i.test(value)) {
|
|
190
|
+
return "jar";
|
|
191
|
+
}
|
|
192
|
+
if (value.split(":").length >= 3) {
|
|
193
|
+
return "coordinate";
|
|
194
|
+
}
|
|
195
|
+
return "version";
|
|
196
|
+
}
|
|
197
|
+
export function copySourceLookupSuggestionFields(tool, source) {
|
|
198
|
+
const result = {};
|
|
199
|
+
const stringFields = tool === "get-class-source"
|
|
200
|
+
? ["className", "mode", "mapping", "sourcePriority", "projectPath", "scope", "outputFile"]
|
|
201
|
+
: ["className", "mapping", "sourcePriority", "projectPath", "scope", "access", "memberPattern"];
|
|
202
|
+
for (const field of stringFields) {
|
|
203
|
+
const value = source[field];
|
|
204
|
+
if (typeof value === "string" &&
|
|
205
|
+
value.trim() &&
|
|
206
|
+
(!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
|
|
207
|
+
!isSuggestedCallDefault(field, value))) {
|
|
208
|
+
result[field] = value;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const numericFields = tool === "get-class-source"
|
|
212
|
+
? ["startLine", "endLine", "maxLines", "maxChars"]
|
|
213
|
+
: ["maxMembers"];
|
|
214
|
+
for (const field of numericFields) {
|
|
215
|
+
const value = source[field];
|
|
216
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
217
|
+
result[field] = value;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const booleanFields = tool === "get-class-source"
|
|
221
|
+
? ["allowDecompile", "preferProjectVersion", "strictVersion"]
|
|
222
|
+
: ["allowDecompile", "preferProjectVersion", "strictVersion", "includeSynthetic", "includeInherited"];
|
|
223
|
+
for (const field of booleanFields) {
|
|
224
|
+
const value = source[field];
|
|
225
|
+
if (typeof value === "boolean" &&
|
|
226
|
+
(!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
|
|
227
|
+
!isSuggestedCallDefault(field, value))) {
|
|
228
|
+
result[field] = value;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
export function copyValidateMixinSharedParams(source) {
|
|
234
|
+
const result = {};
|
|
235
|
+
const stringFields = [
|
|
236
|
+
"version",
|
|
237
|
+
"mapping",
|
|
238
|
+
"sourcePriority",
|
|
239
|
+
"scope",
|
|
240
|
+
"projectPath",
|
|
241
|
+
"minSeverity",
|
|
242
|
+
"warningMode",
|
|
243
|
+
"reportMode"
|
|
244
|
+
];
|
|
245
|
+
for (const field of stringFields) {
|
|
246
|
+
const value = source[field];
|
|
247
|
+
if (typeof value === "string" &&
|
|
248
|
+
value.trim() &&
|
|
249
|
+
(!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
|
|
250
|
+
!isSuggestedCallDefault(field, value))) {
|
|
251
|
+
result[field] = value;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const booleanFields = [
|
|
255
|
+
"preferProjectVersion",
|
|
256
|
+
"hideUncertain",
|
|
257
|
+
"explain",
|
|
258
|
+
"preferProjectMapping",
|
|
259
|
+
"treatInfoAsWarning",
|
|
260
|
+
"includeIssues"
|
|
261
|
+
];
|
|
262
|
+
for (const field of booleanFields) {
|
|
263
|
+
const value = source[field];
|
|
264
|
+
if (typeof value === "boolean" &&
|
|
265
|
+
(!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
|
|
266
|
+
!isSuggestedCallDefault(field, value))) {
|
|
267
|
+
result[field] = value;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const sourceRoots = asStringArray(source.sourceRoots);
|
|
271
|
+
if (sourceRoots) {
|
|
272
|
+
result.sourceRoots = sourceRoots;
|
|
273
|
+
}
|
|
274
|
+
const warningCategoryFilter = asStringArray(source.warningCategoryFilter);
|
|
275
|
+
if (warningCategoryFilter) {
|
|
276
|
+
result.warningCategoryFilter = warningCategoryFilter;
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
export function buildValidateMixinSuggestedParams(normalizedInput) {
|
|
281
|
+
const record = asObjectRecord(normalizedInput);
|
|
282
|
+
if (!record) {
|
|
283
|
+
return {
|
|
284
|
+
input: {
|
|
285
|
+
mode: "inline",
|
|
286
|
+
source: "<Mixin Java source>"
|
|
287
|
+
},
|
|
288
|
+
version: "<minecraft-version>"
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const inputRecord = asObjectRecord(record.input);
|
|
292
|
+
const shared = copyValidateMixinSharedParams(record);
|
|
293
|
+
const version = asNonEmptyString(record.version) ?? "<minecraft-version>";
|
|
294
|
+
const inlineSource = asNonEmptyString(record.input) ??
|
|
295
|
+
asNonEmptyString(inputRecord?.source) ??
|
|
296
|
+
asNonEmptyString(record.source);
|
|
297
|
+
if (inlineSource) {
|
|
298
|
+
const parsedInlineObject = parseJsonObjectString(inlineSource);
|
|
299
|
+
if (parsedInlineObject && typeof parsedInlineObject.mode === "string") {
|
|
300
|
+
return {
|
|
301
|
+
...shared,
|
|
302
|
+
input: parsedInlineObject,
|
|
303
|
+
version
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
...shared,
|
|
308
|
+
input: {
|
|
309
|
+
mode: "inline",
|
|
310
|
+
source: truncateSuggestionText(inlineSource)
|
|
311
|
+
},
|
|
312
|
+
version
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const path = asNonEmptyString(inputRecord?.path) ??
|
|
316
|
+
asNonEmptyString(record.sourcePath);
|
|
317
|
+
if (path) {
|
|
318
|
+
return {
|
|
319
|
+
...shared,
|
|
320
|
+
input: {
|
|
321
|
+
mode: "path",
|
|
322
|
+
path
|
|
323
|
+
},
|
|
324
|
+
version
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const paths = asStringArray(inputRecord?.paths) ??
|
|
328
|
+
asStringArray(record.sourcePaths);
|
|
329
|
+
if (paths) {
|
|
330
|
+
return {
|
|
331
|
+
...shared,
|
|
332
|
+
input: {
|
|
333
|
+
mode: "paths",
|
|
334
|
+
paths
|
|
335
|
+
},
|
|
336
|
+
version
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const configPaths = asStringArray(inputRecord?.configPaths) ??
|
|
340
|
+
(asNonEmptyString(record.mixinConfigPath) ? [record.mixinConfigPath] : undefined);
|
|
341
|
+
if (configPaths) {
|
|
342
|
+
return {
|
|
343
|
+
...shared,
|
|
344
|
+
input: {
|
|
345
|
+
mode: "config",
|
|
346
|
+
configPaths
|
|
347
|
+
},
|
|
348
|
+
version
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const projectPath = asNonEmptyString(record.projectPath) ??
|
|
352
|
+
(inputRecord?.mode === "project" ? asNonEmptyString(inputRecord.path) : undefined);
|
|
353
|
+
if (projectPath) {
|
|
354
|
+
return {
|
|
355
|
+
...shared,
|
|
356
|
+
input: {
|
|
357
|
+
mode: "project",
|
|
358
|
+
path: projectPath
|
|
359
|
+
},
|
|
360
|
+
version
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
...shared,
|
|
365
|
+
input: {
|
|
366
|
+
mode: "inline",
|
|
367
|
+
source: "<Mixin Java source>"
|
|
368
|
+
},
|
|
369
|
+
version
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
export function buildResolveArtifactSuggestedParams(normalizedInput) {
|
|
373
|
+
const record = asObjectRecord(normalizedInput);
|
|
374
|
+
if (!record) {
|
|
375
|
+
return {
|
|
376
|
+
target: {
|
|
377
|
+
kind: "version",
|
|
378
|
+
value: "<minecraft-version>"
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const targetValue = asNonEmptyString(record.target);
|
|
383
|
+
const result = {
|
|
384
|
+
target: targetValue
|
|
385
|
+
? {
|
|
386
|
+
kind: inferTargetKindFromString(targetValue),
|
|
387
|
+
value: targetValue
|
|
388
|
+
}
|
|
389
|
+
: {
|
|
390
|
+
kind: "version",
|
|
391
|
+
value: "<minecraft-version>"
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
const stringFields = ["mapping", "sourcePriority", "projectPath", "scope"];
|
|
395
|
+
for (const field of stringFields) {
|
|
396
|
+
const value = record[field];
|
|
397
|
+
if (typeof value === "string" && value.trim()) {
|
|
398
|
+
result[field] = value;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
const booleanFields = ["allowDecompile", "preferProjectVersion", "strictVersion"];
|
|
402
|
+
for (const field of booleanFields) {
|
|
403
|
+
const value = record[field];
|
|
404
|
+
if (typeof value === "boolean" &&
|
|
405
|
+
!isSuggestedCallDefault(field, value)) {
|
|
406
|
+
result[field] = value;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
}
|
|
411
|
+
export function buildSourceLookupSuggestedParams(tool, normalizedInput) {
|
|
412
|
+
const record = asObjectRecord(normalizedInput);
|
|
413
|
+
const result = record ? copySourceLookupSuggestionFields(tool, record) : {};
|
|
414
|
+
const targetValue = asNonEmptyString(record?.target);
|
|
415
|
+
result.target = targetValue
|
|
416
|
+
? {
|
|
417
|
+
type: "resolve",
|
|
418
|
+
kind: inferTargetKindFromString(targetValue),
|
|
419
|
+
value: targetValue
|
|
420
|
+
}
|
|
421
|
+
: {
|
|
422
|
+
type: "resolve",
|
|
423
|
+
kind: "version",
|
|
424
|
+
value: "<minecraft-version>"
|
|
425
|
+
};
|
|
426
|
+
if (!asNonEmptyString(result.className)) {
|
|
427
|
+
result.className = "<fully-qualified-class-name>";
|
|
428
|
+
}
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
export function filterAllowedIncludeValues(values, allowed) {
|
|
432
|
+
if (!values?.length) {
|
|
433
|
+
return [];
|
|
434
|
+
}
|
|
435
|
+
const allowedSet = new Set(allowed);
|
|
436
|
+
const filtered = values.filter((value) => allowedSet.has(value));
|
|
437
|
+
return [...new Set(filtered)];
|
|
438
|
+
}
|
|
439
|
+
export function buildAnalyzeModSuggestedParams(normalizedInput) {
|
|
440
|
+
const record = asObjectRecord(normalizedInput);
|
|
441
|
+
if (!record) {
|
|
442
|
+
return {
|
|
443
|
+
task: "summary",
|
|
444
|
+
detail: "standard",
|
|
445
|
+
subject: {
|
|
446
|
+
kind: "jar",
|
|
447
|
+
jarPath: "<mod-jar-path>"
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const task = asNonEmptyString(record.task) ?? "summary";
|
|
452
|
+
const result = { task };
|
|
453
|
+
const subjectRecord = asObjectRecord(record.subject);
|
|
454
|
+
const include = asStringArray(record.include);
|
|
455
|
+
const canonicalInclude = filterAllowedIncludeValues(include, ANALYZE_MOD_INCLUDE_GROUPS);
|
|
456
|
+
const wantsLegacyMetadata = include?.some((value) => ANALYZE_MOD_LEGACY_METADATA_INCLUDES.includes(value)) ?? false;
|
|
457
|
+
const detail = asNonEmptyString(record.detail);
|
|
458
|
+
if (task === "summary" && wantsLegacyMetadata) {
|
|
459
|
+
result.detail = detail && detail !== "summary" ? detail : "standard";
|
|
460
|
+
}
|
|
461
|
+
else if (detail && detail !== "summary") {
|
|
462
|
+
result.detail = detail;
|
|
463
|
+
}
|
|
464
|
+
if (canonicalInclude.length > 0) {
|
|
465
|
+
result.include = canonicalInclude;
|
|
466
|
+
}
|
|
467
|
+
if (task === "class-source") {
|
|
468
|
+
result.subject = {
|
|
469
|
+
kind: "class",
|
|
470
|
+
jarPath: asNonEmptyString(subjectRecord?.jarPath) ?? asNonEmptyString(record.subject) ?? "<mod-jar-path>",
|
|
471
|
+
className: asNonEmptyString(subjectRecord?.className) ?? asNonEmptyString(record.className) ?? "<fully-qualified-class-name>"
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
result.subject = {
|
|
476
|
+
kind: "jar",
|
|
477
|
+
jarPath: asNonEmptyString(subjectRecord?.jarPath) ?? asNonEmptyString(record.subject) ?? asNonEmptyString(record.jarPath) ?? "<mod-jar-path>"
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
const stringFields = ["query", "searchType", "targetMapping", "outputJar", "executionMode"];
|
|
481
|
+
for (const field of stringFields) {
|
|
482
|
+
const value = record[field];
|
|
483
|
+
if (typeof value === "string" && value.trim()) {
|
|
484
|
+
result[field] = value;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const booleanFields = ["includeFiles"];
|
|
488
|
+
for (const field of booleanFields) {
|
|
489
|
+
const value = record[field];
|
|
490
|
+
if (typeof value === "boolean") {
|
|
491
|
+
result[field] = value;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const numericFields = ["limit", "maxFiles", "maxLines", "maxChars"];
|
|
495
|
+
for (const field of numericFields) {
|
|
496
|
+
const value = record[field];
|
|
497
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
498
|
+
result[field] = value;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
export function buildValidateProjectSuggestedParams(normalizedInput) {
|
|
504
|
+
const record = asObjectRecord(normalizedInput);
|
|
505
|
+
if (!record) {
|
|
506
|
+
return {
|
|
507
|
+
task: "project-summary",
|
|
508
|
+
subject: {
|
|
509
|
+
kind: "workspace",
|
|
510
|
+
projectPath: "<workspace-path>"
|
|
511
|
+
},
|
|
512
|
+
preferProjectVersion: true
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
const task = asNonEmptyString(record.task) ?? "project-summary";
|
|
516
|
+
const result = { task };
|
|
517
|
+
const subjectRecord = asObjectRecord(record.subject);
|
|
518
|
+
const include = asStringArray(record.include);
|
|
519
|
+
const canonicalInclude = filterAllowedIncludeValues(include, VALIDATE_PROJECT_INCLUDE_GROUPS);
|
|
520
|
+
const wantsWorkspaceInclude = include?.some((value) => VALIDATE_PROJECT_LEGACY_WORKSPACE_INCLUDES.includes(value)) ?? false;
|
|
521
|
+
const detail = asNonEmptyString(record.detail);
|
|
522
|
+
if (detail && detail !== "summary") {
|
|
523
|
+
result.detail = detail;
|
|
524
|
+
}
|
|
525
|
+
const includeSuggestion = wantsWorkspaceInclude
|
|
526
|
+
? [...new Set([...canonicalInclude, "workspace"])]
|
|
527
|
+
: canonicalInclude;
|
|
528
|
+
if (includeSuggestion.length > 0) {
|
|
529
|
+
result.include = includeSuggestion;
|
|
530
|
+
}
|
|
531
|
+
const stringFields = [
|
|
532
|
+
"version",
|
|
533
|
+
"mapping",
|
|
534
|
+
"sourcePriority",
|
|
535
|
+
"scope",
|
|
536
|
+
"minSeverity",
|
|
537
|
+
"warningMode"
|
|
538
|
+
];
|
|
539
|
+
for (const field of stringFields) {
|
|
540
|
+
const value = record[field];
|
|
541
|
+
if (typeof value === "string" && value.trim()) {
|
|
542
|
+
result[field] = value;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
const booleanFields = [
|
|
546
|
+
"preferProjectVersion",
|
|
547
|
+
"preferProjectMapping",
|
|
548
|
+
"hideUncertain",
|
|
549
|
+
"explain",
|
|
550
|
+
"treatInfoAsWarning",
|
|
551
|
+
"includeIssues"
|
|
552
|
+
];
|
|
553
|
+
for (const field of booleanFields) {
|
|
554
|
+
const value = record[field];
|
|
555
|
+
if (typeof value === "boolean" &&
|
|
556
|
+
(!Object.prototype.hasOwnProperty.call(SUGGESTED_CALL_DEFAULTS, field) ||
|
|
557
|
+
!isSuggestedCallDefault(field, value))) {
|
|
558
|
+
result[field] = value;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const sourceRoots = asStringArray(record.sourceRoots);
|
|
562
|
+
if (sourceRoots?.length) {
|
|
563
|
+
result.sourceRoots = sourceRoots;
|
|
564
|
+
}
|
|
565
|
+
const configPaths = asStringArray(record.configPaths);
|
|
566
|
+
if (configPaths?.length) {
|
|
567
|
+
result.configPaths = configPaths;
|
|
568
|
+
}
|
|
569
|
+
const warningCategoryFilter = asStringArray(record.warningCategoryFilter);
|
|
570
|
+
if (warningCategoryFilter?.length) {
|
|
571
|
+
result.warningCategoryFilter = warningCategoryFilter;
|
|
572
|
+
}
|
|
573
|
+
if (task === "project-summary") {
|
|
574
|
+
const subject = {
|
|
575
|
+
kind: "workspace",
|
|
576
|
+
projectPath: asNonEmptyString(subjectRecord?.projectPath) ??
|
|
577
|
+
asNonEmptyString(record.subject) ??
|
|
578
|
+
asNonEmptyString(record.projectPath) ??
|
|
579
|
+
"<workspace-path>"
|
|
580
|
+
};
|
|
581
|
+
const discover = asStringArray(subjectRecord?.discover);
|
|
582
|
+
if (discover?.length) {
|
|
583
|
+
subject.discover = discover;
|
|
584
|
+
}
|
|
585
|
+
result.subject = subject;
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
if (task === "mixin") {
|
|
589
|
+
const inputRecord = asObjectRecord(subjectRecord?.input) ?? asObjectRecord(record.input);
|
|
590
|
+
result.subject = {
|
|
591
|
+
kind: "mixin",
|
|
592
|
+
input: inputRecord ?? {
|
|
593
|
+
mode: "inline",
|
|
594
|
+
source: "<Mixin Java source>"
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
return result;
|
|
598
|
+
}
|
|
599
|
+
const inputRecord = asObjectRecord(subjectRecord?.input) ?? asObjectRecord(record.input);
|
|
600
|
+
result.subject = {
|
|
601
|
+
kind: "access-widener",
|
|
602
|
+
input: inputRecord ?? {
|
|
603
|
+
mode: "inline",
|
|
604
|
+
content: "<access widener contents>"
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
function gatedGuidance(tool, hints, params) {
|
|
610
|
+
const validated = buildSuggestedCall({ tool, params });
|
|
611
|
+
return {
|
|
612
|
+
hints,
|
|
613
|
+
...validated,
|
|
614
|
+
primaryDropped: !validated.suggestedCall
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
export function buildInvalidInputGuidance(tool, normalizedInput) {
|
|
618
|
+
if (tool === "validate-mixin") {
|
|
619
|
+
return gatedGuidance(tool, [
|
|
620
|
+
"validate-mixin.input must be an object with input.mode = \"inline\" | \"path\" | \"paths\" | \"config\" | \"project\".",
|
|
621
|
+
"Whole-project example: {\"input\":{\"mode\":\"project\",\"path\":\"/workspace\"},\"version\":\"1.21.10\",\"preferProjectVersion\":true,\"preferProjectMapping\":true}.",
|
|
622
|
+
"Legacy top-level source/sourcePath/sourcePaths/mixinConfigPath fields are no longer accepted; wrap them under input.mode instead."
|
|
623
|
+
], buildValidateMixinSuggestedParams(normalizedInput));
|
|
624
|
+
}
|
|
625
|
+
if (tool === "resolve-artifact") {
|
|
626
|
+
return gatedGuidance(tool, [
|
|
627
|
+
"resolve-artifact.target must be an object: {\"kind\":\"version|jar|coordinate\",\"value\":\"...\"}.",
|
|
628
|
+
"Bare string targets are not accepted; wrap the value under target.kind and target.value."
|
|
629
|
+
], buildResolveArtifactSuggestedParams(normalizedInput));
|
|
630
|
+
}
|
|
631
|
+
if (tool === "get-class-source" || tool === "get-class-members") {
|
|
632
|
+
return gatedGuidance(tool, [
|
|
633
|
+
`${tool}.target must be an object: {"type":"resolve","kind":"version|jar|coordinate","value":"..."} or {"type":"artifact","artifactId":"..."}.`,
|
|
634
|
+
"Bare string targets are not accepted; wrap the value under target.type/target.kind/target.value."
|
|
635
|
+
], buildSourceLookupSuggestedParams(tool, normalizedInput));
|
|
636
|
+
}
|
|
637
|
+
if (tool === "validate-project") {
|
|
638
|
+
return gatedGuidance(tool, [
|
|
639
|
+
"validate-project.subject must be an object with subject.kind=workspace|mixin|access-widener|access-transformer.",
|
|
640
|
+
"task=\"project-summary\" uses {\"subject\":{\"kind\":\"workspace\",\"projectPath\":\"/workspace\"}}.",
|
|
641
|
+
"Legacy include names like projectSummary/detectedConfig/validationSummary are not accepted; use include:[\"workspace\"] only when you need discovery details."
|
|
642
|
+
], buildValidateProjectSuggestedParams(normalizedInput));
|
|
643
|
+
}
|
|
644
|
+
if (tool === "analyze-mod") {
|
|
645
|
+
return gatedGuidance(tool, [
|
|
646
|
+
"analyze-mod.subject must be an object with subject.kind=jar|class.",
|
|
647
|
+
"task=\"summary\" uses {\"subject\":{\"kind\":\"jar\",\"jarPath\":\"/path/to/mod.jar\"}}.",
|
|
648
|
+
"Legacy include names like metadata/entrypoints/mixins/dependencies are not accepted; use detail=\"standard\" to surface the metadata block, and canonical include groups only for warnings/files/source/samples/timings."
|
|
649
|
+
], buildAnalyzeModSuggestedParams(normalizedInput));
|
|
650
|
+
}
|
|
651
|
+
return undefined;
|
|
652
|
+
}
|
|
653
|
+
export function mapErrorToProblem(caughtError, requestId, context) {
|
|
654
|
+
if (caughtError instanceof ZodError) {
|
|
655
|
+
const guidance = context?.tool
|
|
656
|
+
? buildInvalidInputGuidance(context.tool, context.normalizedInput)
|
|
657
|
+
: undefined;
|
|
658
|
+
const baseHints = guidance?.hints ?? ["Check fieldErrors and submit a valid tool argument payload."];
|
|
659
|
+
const hintsWithFallback = guidance?.primaryDropped
|
|
660
|
+
? [...baseHints, VALIDATION_FALLBACK_HINT]
|
|
661
|
+
: baseHints;
|
|
662
|
+
return {
|
|
663
|
+
type: "https://minecraft-modding-mcp.dev/problems/invalid-input",
|
|
664
|
+
title: "Invalid input",
|
|
665
|
+
detail: "Request validation failed.",
|
|
666
|
+
status: 400,
|
|
667
|
+
code: ERROR_CODES.INVALID_INPUT,
|
|
668
|
+
instance: requestId,
|
|
669
|
+
fieldErrors: toFieldErrorsFromZod(caughtError),
|
|
670
|
+
hints: hintsWithFallback,
|
|
671
|
+
...(guidance?.suggestedCall ? { suggestedCall: guidance.suggestedCall } : {}),
|
|
672
|
+
...(guidance?.exampleCalls ? { exampleCalls: guidance.exampleCalls } : {}),
|
|
673
|
+
...(context?.tool === "validate-mixin" ? { failedStage: "input-validation" } : {})
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
if (isAppError(caughtError)) {
|
|
677
|
+
const { suggestedCall, exampleCalls, primaryDropped } = extractValidatedSuggestionAndExamples(caughtError.details);
|
|
678
|
+
let failedStage = extractFailedStageFromDetails(caughtError.details);
|
|
679
|
+
if (!failedStage
|
|
680
|
+
&& context?.tool === "validate-mixin"
|
|
681
|
+
&& caughtError.code === ERROR_CODES.INVALID_INPUT) {
|
|
682
|
+
failedStage = "input-validation";
|
|
683
|
+
}
|
|
684
|
+
const baseHints = toHints(caughtError.details);
|
|
685
|
+
const hintsWithFallback = primaryDropped && !suggestedCall
|
|
686
|
+
? [...(baseHints ?? []), VALIDATION_FALLBACK_HINT]
|
|
687
|
+
: baseHints;
|
|
688
|
+
return {
|
|
689
|
+
type: `https://minecraft-modding-mcp.dev/problems/${caughtError.code.toLowerCase()}`,
|
|
690
|
+
title: "Tool execution error",
|
|
691
|
+
detail: caughtError.message,
|
|
692
|
+
status: statusForErrorCode(caughtError.code),
|
|
693
|
+
code: caughtError.code,
|
|
694
|
+
instance: requestId,
|
|
695
|
+
fieldErrors: extractFieldErrorsFromDetails(caughtError.details),
|
|
696
|
+
hints: hintsWithFallback,
|
|
697
|
+
...(suggestedCall ? { suggestedCall } : {}),
|
|
698
|
+
...(exampleCalls ? { exampleCalls } : {}),
|
|
699
|
+
...(failedStage ? { failedStage } : {})
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
return {
|
|
703
|
+
type: "https://minecraft-modding-mcp.dev/problems/internal",
|
|
704
|
+
title: "Internal server error",
|
|
705
|
+
detail: "Unexpected server error.",
|
|
706
|
+
status: 500,
|
|
707
|
+
code: ERROR_CODES.INTERNAL,
|
|
708
|
+
instance: requestId
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Copy documented error-only meta fields from AppError.details into the
|
|
713
|
+
* public envelope. Scoped to `ERR_STAGE_BUDGET_PRE_PARSE` per
|
|
714
|
+
* docs/tool-reference.md §Meta fields.
|
|
715
|
+
*/
|
|
716
|
+
export function applyErrorMetaExtensions(meta, error) {
|
|
717
|
+
if (!isAppError(error))
|
|
718
|
+
return;
|
|
719
|
+
if (error.code !== ERROR_CODES.STAGE_BUDGET_PRE_PARSE)
|
|
720
|
+
return;
|
|
721
|
+
const details = error.details;
|
|
722
|
+
if (!details)
|
|
723
|
+
return;
|
|
724
|
+
if (details.stageBudgetExhausted === true) {
|
|
725
|
+
meta.stageBudgetExhausted = true;
|
|
726
|
+
}
|
|
727
|
+
if (typeof details.budgetMs === "number") {
|
|
728
|
+
meta.budgetMs = details.budgetMs;
|
|
729
|
+
}
|
|
730
|
+
if (typeof details.elapsedMs === "number") {
|
|
731
|
+
meta.elapsedMs = details.elapsedMs;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
//# sourceMappingURL=tool-guidance.js.map
|