@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
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,67 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.1.1] - 2026-05-10
|
|
9
|
+
|
|
10
|
+
### Documentation
|
|
11
|
+
- `package.json` `description` and `keywords` now mirror the GitHub repository's `description` and topics. `description` summarizes the actual feature surface (source inspection, Mojang/Yarn/Intermediary mappings, version diffs, Fabric/Forge/NeoForge mod JAR analysis, Mixin/Access Widener/Access Transformer validation); `keywords` expands from three entries to the published 15-topic set.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Concurrent class source/member lookups in the same MCP server process now share one in-flight source indexing/decompile rebuild for the same binary fallback artifact.
|
|
15
|
+
- `validate-project task="project-summary"` no longer performs heavyweight source indexing for its `minecraft.artifact.resolved` task probe. The probe now uses lightweight artifact metadata while preserving the public `tasks` response shape.
|
|
16
|
+
- `validate-mixin` mapping-health checks no longer load the full Tiny mapping graph for `obfuscated` or `mojang` requests, preventing `validate-project task="project-summary"` worker restarts on large Mojang-mapped workspaces.
|
|
17
|
+
- `validate-project task="project-summary"` task report no longer marks executed validators as `skipped` when the lightweight `minecraft.artifact.resolved` probe fails. Mixin / access-widener / access-transformer entries now reflect their real outcome (`ok` with `counts`, or `error`).
|
|
18
|
+
- `validate-mixin` `toolHealth.tinyMappingsAvailable` now means "Tiny is sufficient for the request": `true` when Tiny is not required (`obfuscated` / `mojang`) or is loaded, `false` only when `intermediary` / `yarn` was requested and Tiny is unavailable. `confidenceScore` is no longer penalized when Tiny is intentionally skipped, including on graph-load failure.
|
|
19
|
+
- `validate-project task="project-summary"` lightweight artifact probe defaults omitted `scope` to `"vanilla"` to match `validate-mixin`'s resolve stage, skipping workspace-wide source-jar discovery unless the caller explicitly requests `scope="merged"` or `scope="loader"`.
|
|
20
|
+
- `validate-project task="project-summary"` stage notifications are now best-effort. Telemetry/transport failures no longer abort the summary, count as validation errors, hide nested `validate-mixin` work behind zero-count summaries, or surface as `ERR_ARTIFACT_PROBE_FAILED` in `tasks["minecraft.artifact.resolved"]`.
|
|
21
|
+
|
|
22
|
+
## [4.1.0] - 2026-05-09
|
|
23
|
+
|
|
24
|
+
### Documentation
|
|
25
|
+
- README onboarding and the Japanese README now clarify MCP client setup and packaged documentation links, and the npm package includes the Markdown docs those links reference.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- `validate-project task="project-summary"` now returns an additive `tasks` per-probe status report alongside the existing `summary` / `project` / `workspace` blocks. The seven probes (`workspace.detected`, `gradle.readable`, `loom.cache.found`, `minecraft.artifact.resolved`, `mixins.validated`, `accessWideners.validated`, `accessTransformers.validated`) each carry `status: "ok" | "skipped" | "missing" | "error"` plus optional sub-fields (e.g. `evidence`, `propertiesPath`, `buildScripts`, `cachePath`, `artifactId`, `mapping`, `counts`). The headline `result.summary.status` is unchanged; the new field surfaces which probes succeeded even when the overall status is `blocked`. With `detail: "summary"` (or when `include` does not contain `"workspace"`), each entry is slimmed to `status` / `error?` / `warnings?`. Set `VALIDATE_PROJECT_TASKS_OFF=1` to omit the field entirely.
|
|
29
|
+
- `get-class-members` now returns an additive `status: "ok" | "members_unavailable" | "partial"` field. `"ok"` covers both populated classes (`counts.total > 0`) and genuinely empty classes whose binary signature parsed without error and produced no decompiled fallback. `"partial"` fires whenever `decompiledFallback` is populated (bytecode returned zero but indexed source supplied member names; `qualityFlags` includes `"members-from-decompiled-source"`). `"members_unavailable"` fires when binary signature extraction throws a non-`ERR_CLASS_NOT_FOUND` error and no decompiled fallback is available; the response then carries `unavailableReason: string` and a `suggestedCall: { tool: "get-class-source", params }` whose params validate against `get-class-source`'s input schema. `ERR_CLASS_NOT_FOUND` still propagates as a thrown error. The shape is purely additive — `members` / `counts` / `decompiledFallback` / `decompiledMemberCounts` / `qualityFlags` are unchanged for callers that ignore `status`. Set `MEMBERS_STATUS_LEGACY=1` to omit the new fields entirely (legacy shape).
|
|
30
|
+
- `verify-mixin-target` (new tool): single-call probe that answers "does this owner / member exist, and which `@Shadow` / `@Accessor` / `@Invoker` should the mixin use?" Inputs accept `target.kind="workspace" | "version" | "coordinate" | "dependency" | "jar"`, an optional `mixinMemberName` (caller-authored mixin field/method name), and a discriminated `member: { kind: "method" | "field", name, descriptor? }`. Output carries `exists`, `matches[]`, `candidates[]` (descriptor-mismatch and Levenshtein-near misses via the same `suggestSimilar` helper used by `validate-mixin`), and an `accessorAdvice` block with `suggestedAnnotation` (`"@Shadow"` / `"@Accessor"` / `"@Invoker"` / `"@Inject-only"` / `null`), a deterministic `exampleSnippet`, and `candidates` when the rule table cannot decide between `@Shadow` and `@Invoker`. `accessorAdvice` is emitted only when `matches.length === 1` (a single unique match): descriptor-mismatch / nearest-neighbor / candidate-only responses carry no advice, and ambiguous overload responses (descriptor omitted, multiple matches) also carry no advice — re-call with an explicit `descriptor` to disambiguate. `@Accessor` setter templates (when `mixinMemberName` matches `^set[A-Z]`) emit `void name(<type> value);` instead of the zero-arg getter shape. `"@Inject-only"` is a pseudo-tag — not a real annotation — that signals "target already visible, no `@Shadow` required". Owner-not-found surfaces `ERR_CLASS_NOT_FOUND` with `details.suggestedCall.tool === "find-class"`. Namespace mismatch (explicit `mapping` differs from resolved `mappingApplied`) surfaces `ERR_NAMESPACE_MISMATCH` with `details.requestedMapping` and `details.mappingApplied` rather than silently returning a misleading `exists:false`; auto-translation of owner/member names across namespaces is deferred. Set `VERIFY_MIXIN_TARGET_OFF=1` to remove the tool from `tools/list` entirely (direct calls then return the SDK "Tool not found" tool-result envelope — `{ content: [{ type: "text", text: "MCP error -32602: Tool verify-mixin-target not found" }], isError: true }` — so callers cannot rely on `error.code === "ERR_*"` while the toggle is set).
|
|
31
|
+
- `ProblemDetails.code` may now be `ERR_WORKER_RESTART`, `ERR_MIXIN_PARSE_FAILED`, `ERR_STAGE_BUDGET_PRE_PARSE`, `ERR_WORKSPACE_VERSION_UNRESOLVED`, `ERR_DEPENDENCY_VERSION_UNRESOLVED`, or `ERR_BATCH_ABORTED`. Restart envelopes are produced by the supervisor when a worker exits while handling `tools/call`; `ERR_STAGE_BUDGET_PRE_PARSE` is raised by `validate-mixin` when a pre-parse stage exhausts its soft-deadline; `ERR_WORKSPACE_VERSION_UNRESOLVED` / `ERR_DEPENDENCY_VERSION_UNRESOLVED` carry structured `suggestedCall` payloads for caller-side recovery; `ERR_BATCH_ABORTED` (HTTP 412) fills un-started slots in batch tools when `failFast: true` and an earlier entry already failed.
|
|
32
|
+
- `validate-mixin` now reports `result.targetOutcomes[]` (per-target `status: "ok" | "deferred-budget" | "tool-issue"` plus optional `slowTarget` / `elapsedMs` / `budgetMs`) and `summary.targetsDeferredBudget` / `summary.degradedReason: "stage-budget" | "stage-budget-pre-target"` so callers can distinguish completed work from work skipped by the soft-deadline.
|
|
33
|
+
- `meta.restart` (synthetic worker-restart responses only) carries `tool` / `durationMs` / `lastStage` / `lastStageElapsedMs` / `lastStageMeta` / `exit` / `retryRecommendation` for caller diagnostics. `meta.stageBudgetExhausted` / `meta.budgetMs` / `meta.elapsedMs` accompany `ERR_STAGE_BUDGET_PRE_PARSE` error envelopes so callers can detect budget-driven failures from the public envelope without parsing the message string.
|
|
34
|
+
- `validate-mixin` batch-mode results (`paths` / `config` / `project`) now preserve typed AppError metadata on per-entry errors: each `results[i]` carries optional `errorCode` and `errorDetails` (`failedStage`, `stageBudgetExhausted`, `budgetMs`, `elapsedMs`, …) so callers can distinguish budget-driven failures from generic per-file processing errors.
|
|
35
|
+
- `target.kind="workspace"` is now accepted by `resolve-artifact`, `get-class-source`, and `get-class-members`. The synthesizer reads `gradle.properties` and `build.gradle(.kts)` from `projectPath` to detect Minecraft version, compile mapping, and loader, then rewrites the call to the resolved `target.kind="version"` shape. Detected facts and a `cacheHit` flag surface on `provenance.workspaceResolution`.
|
|
36
|
+
- `target.kind="dependency"` (with optional `versionFromProject`) is now accepted by the same three tools. It probes four de-duplicated `gradle.properties` keys (`name_version`, `camelCaseVersion`, `group_name_version`, `groupNameVersion`) and falls back to `~/.gradle/caches/modules-2/files-2.1/<group>/<name>/`, picking the semver-newest non-snapshot. Dependency JARs disable the Mojang binary-remap path; mapping mismatches between the caller's `mapping` and the artifact namespace surface as warnings instead of being remapped.
|
|
37
|
+
- `provenance.workspaceResolution` and `provenance.dependencyResolution` are emitted whenever the new target kinds are used. The new target kinds and the `manage-cache` workspace integration are scoped to the three tools whose input shape carries a `target` field; `find-class`, `search-class-source`, `list-artifact-files`, and `find-mapping` keep their existing `artifactId` / `version`-based shapes unchanged in this release.
|
|
38
|
+
- `manage-cache` exposes a new `cacheKinds: "workspace"` for the in-memory `WorkspaceContextCache`. Listing returns one entry per cached `projectPath`; `delete` invalidates entries by `selector.projectPath`. `prune` / `rebuild` / `verify` are no-ops for this kind.
|
|
39
|
+
- `ProblemDetails.exampleCalls?: Array<{ tool: string; params: Record<string, unknown>; reason: string }>` — additive always-valid fallback emitted when the primary `suggestedCall` payload fails the schema-validation gate. Each entry already passed `getToolSchema(tool).safeParse(params)` at construction time and is safe for the agent to re-call as-is. Construction sites supply alternatives via the `examples: [{ params, reason }]` argument to `buildSuggestedCall(...)`.
|
|
40
|
+
- `tool-schema-registry` runtime registry (internal module exporting `registerToolSchema` / `getToolSchema` / `validateToolParams` / `listRegisteredTools`) populated at server startup from the same zod schemas already used by the `server.tool(...)` registrations. Powers the new `suggestedCall` validation gate; a registry-completeness test in `tests/tool-schema-registry.test.ts` asserts every tool name from `EXPECTED_TOOLS` has a registered schema.
|
|
41
|
+
- `batch-class-source`, `batch-class-members`, `batch-symbol-exists`, and `batch-mappings` (4 new tools) read source / list members / probe symbol existence / translate mappings for fixed shortlists (1..50 entries) in a single call. Each batch shares one resolved artifact (`summary.sharedArtifactId`) instead of paying N artifact-resolution round-trips, dispatches per entry through the existing bounded worker pool (`concurrency: 1..8`, default 4), and returns a per-entry `{ index, status: "ok" | "error", result?, error?, warnings, durationMs }` envelope plus an aggregate `summary: { total, ok, error }`. `failFast: true` halts dispatch on the first entry error — un-started entries are returned with `error.code === "ERR_BATCH_ABORTED"` while in-flight workers complete (no AbortSignal wiring). `compact: true` (default) applies the matching single-tool's compact projection per entry. Per-entry errors carry a `suggestedCall` proposing the matching single tool (`get-class-source` / `get-class-members` / `check-symbol-exists` / `find-mapping`) with the shared artifact threaded through; the suggestion is validated through the same schema gate as single-tool errors. `batch-symbol-exists` accepts only `target.kind="workspace" | "version"` because library/coordinate/jar artifacts carry library versions, not Minecraft versions, which would corrupt the mapping query (rejected at the schema gate with `ERR_INVALID_INPUT`). `batch-mappings` requires top-level `version` (single-version batch); per-entry `version` is rejected as an unrecognized key. `batch-class-source` rejects duplicate `entries[].outputFile` values at the schema gate with `ERR_INVALID_INPUT` (`fieldErrors[0].path === "entries.<i>.outputFile"`), since concurrent worker dispatch would otherwise race on the same file. The shared envelope, `failFast` semantics, per-entry retry mapping, and disabled-tool envelope shape are documented in the new `Batch lookup contract` section of `docs/tool-reference.md`. Set `BATCH_TOOLS_OFF=1` to remove all four tools from `tools/list` (rollback path); direct calls then return the SDK "Tool not found" tool-result envelope (`{ content: [{ type: "text", text: "MCP error -32602: Tool <name> not found" }], isError: true }`), so callers cannot rely on `error.code === "ERR_*"` while the toggle is set.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- `ERR_MAPPING_NOT_APPLIED` now returns a `suggestedCall` of `{ target: { kind: "workspace" }, projectPath, mapping: <detected> }` whenever `projectPath` is supplied, the workspace's compile mapping is non-obfuscated, the failed target was `target.kind="version"`, AND the workspace's detected `minecraftVersion` matches the failed `value`. Coordinate, jar, synthesized dependency failures, and version-mismatched workspaces all keep the legacy obfuscated retry so the suggested retry never silently redirects to a different artifact. Cache hits short-circuit; cache misses now run bounded detection of both compile mapping and Minecraft version (build.gradle / gradle.properties reads only) before deciding whether to suggest the workspace retry. Set `WORKSPACE_FALLBACK_LEGACY=1` to restore the previous obfuscated retry shape.
|
|
45
|
+
- `target.kind="workspace"` now honors a top-level `scope` field. The precedence is `target.scope` → top-level `scope` → loader-derived default (`merged` when a loader is detected, otherwise `vanilla`); previously the loader-derived default silently shadowed the caller's top-level `scope`.
|
|
46
|
+
- Dependency targets (`target.kind="dependency"`) no longer fail with `ERR_MAPPING_NOT_APPLIED` when the caller asks for `mojang` / `intermediary` / `yarn` against a binary-only artifact. The synthesizer keeps `forceBinaryRemapDisabled=true`, but the resolver now bypasses Mojang remap enforcement on dependency-origin failures, returns the JAR with `mappingApplied: "obfuscated"` and `qualityFlags: ["dependency-mapping-unverified"]`, and surfaces a warning that the requested mapping is not enforced. Callers MUST treat the artifact as namespace-unknown and validate symbol availability themselves; `mappingApplied` is no longer fabricated to the requested mapping value.
|
|
47
|
+
- `target.kind="dependency"` now rejects unsafe Maven version tokens before synthesizing the coordinate. `gradle.properties` values that contain path separators, `..`, NUL, control characters, or any character outside `[A-Za-z0-9._+-]` are filtered out (the next configured property key is tried instead, with the rejection recorded under `attempts[]` as `gradle.properties:<key>:rejected-unsafe-version`). Modules-2 directory entries that fail the same validation are excluded from candidates. Explicit `target.version` strings that fail validation raise `ERR_INVALID_INPUT` with `fieldErrors[0].path === "target.version"`.
|
|
48
|
+
- `target.kind="workspace"` no longer falls back to the latest stable Minecraft version when `gradle.properties` does not declare one. Both `strict: true` and `strict: false` now raise `ERR_WORKSPACE_VERSION_UNRESOLVED` when the workspace version cannot be detected, so callers cannot silently resolve and index the wrong Minecraft API surface. The `details.strict` flag records which strict value was supplied.
|
|
49
|
+
- `target.kind="dependency"` no longer picks the semver-newest entry when `~/.gradle/caches/modules-2/files-2.1/<group>/<name>/` contains multiple cached versions. The synthesizer now raises `ERR_DEPENDENCY_VERSION_UNRESOLVED` with `details.ambiguous=true` and `details.candidatesSeen[]` enumerating the cached versions, so a global cache populated by unrelated projects cannot resolve a version the workspace does not actually use. Single-entry caches and `gradle.properties` matches keep their previous behavior.
|
|
50
|
+
- `get-class-members` now passes the caller's raw `mapping` (preserving `undefined`) into the resolver, mirroring `get-class-source`. A workspace target with an omitted `mapping` now resolves through the workspace's detected compile mapping instead of the obfuscated normalization, eliminating the silent obfuscated-result regression.
|
|
51
|
+
- When the worker process exits while handling `tools/call`, the supervisor returns a structured `{ error, meta }` envelope (synthetic `CallToolResult` with `isError: true`) instead of the previous raw JSON-RPC `-32603` error. Non-`tools/call` requests (`initialize`, `tools/list`, etc.) still receive the legacy envelope.
|
|
52
|
+
- `validate-mixin` runs each stage against an independent soft-deadline. When the `target-lookup` stage exhausts its budget mid-loop, the response is `validationStatus: "partial"` with completed targets retained and remaining ones recorded as `deferred-budget`. Pre-parse stages that exhaust their budget surface as `ERR_STAGE_BUDGET_PRE_PARSE` errors.
|
|
53
|
+
- `validate-mixin` budget-driven partial results no longer trigger the `loom-first → maven-first` retry heuristic. The retry path targets mapping infrastructure failures, not soft-deadline cuts; without this guard a stage-budget partial would re-run the full validation under `maven-first` and defeat the cooperative-deadline contract.
|
|
54
|
+
- `stdio-supervisor` records one worker-exit timestamp per `tool` per actual exit, regardless of how many concurrent `tools/call` requests were in flight. Per-pending-request recording inflated `recentRestarts` to N for a single crash and produced false `retryRecommendation: "report-bug"` under concurrent load.
|
|
55
|
+
- `validate-mixin` `targetOutcomes[]` now emits the `tool-issue` status with a `reason` for completed-but-unreliable targets (mapping / signature / remap failures). Previously the per-target outcome was unconditionally `status: "ok"` even when the underlying target classified as `validation-incomplete`, hiding per-target failures from `includeIssues=false` callers. Whole member-remap exceptions (the entire batch failing) now also flag the target as `tool-issue` with `reason: "member-remap-failed-whole"`; previously only per-member remap failures triggered the classifier.
|
|
56
|
+
- `stdio-supervisor` `lastStageStartedAt` is now refreshed only when the worker emits a different stage name (or on the first emit). Per-target progress notifications during `target-lookup` no longer reset the stage timer, so synthetic worker-restart envelopes report `meta.restart.lastStageElapsedMs` measured from stage entry — not from the most recent per-target update — restoring the documented diagnostic contract.
|
|
57
|
+
- `validate-mixin` now enforces the `inputValidation` stage budget (default 5_000 ms): a slow `sourcePath` read, version normalization, or related input-stage I/O surfaces as `ERR_STAGE_BUDGET_PRE_PARSE` with `failedStage: "input-validation"` instead of hanging the call. Previously the budget was declared in `MixinStageBudgets` but never checked.
|
|
58
|
+
- Synthetic worker-restart envelopes no longer expose `error.suggestedCall` when redaction modified the captured tool arguments (truncated long strings, redacted secret-bearing keys, or trimmed arrays / objects). The redacted form is still emitted on the diagnostic-only `meta.restart.redactedToolArgs` field along with `meta.restart.redactedToolArgsModified` so debug surfaces can inspect the placeholder values without granting them retry semantics.
|
|
59
|
+
- Every `ProblemDetails.suggestedCall` payload an agent receives is now validated against the registered zod schema for the named tool BEFORE leaving the process. Invalid payloads (e.g. the bug shape where `target.value` held a JSON-stringified inner target, producing chained `ERR_INVALID_INPUT` on retry) are dropped from the published envelope; when the gate drops a primary suggestion, `error.hints` gains the literal sentence `"suggested call payload failed schema validation; using fallback examples"` so the caller can observe the elision. Construction sites can pass `examples: [{ params, reason }]` to the new `buildSuggestedCall(...)` helper to surface always-valid fallbacks via `error.exampleCalls[]`. `suggestedCall.params` is published byte-identical to the caller-supplied object — the gate never injects schema defaults into the published payload. Set `SUGGESTED_CALL_VALIDATE_OFF=1` at process start to bypass the gate entirely (raw payloads pass through; the fallback hint is not added) as an emergency rollback path.
|
|
60
|
+
- The `validate-mixin` issue construction (`mixin-validator.ts` × 6 sites) and the supervisor's worker-restart envelope synthesis (`stdio-supervisor.ts` × 1 site) now route their result-level `suggestedCall` payloads through the same `buildSuggestedCall(...)` schema gate as error-side suggestions. Previously these 7 assignment-style construction sites (`obj.suggestedCall = { tool, params }`) bypassed the gate's literal-only invariant test, so a malformed payload would have been published unchanged. The invariant test (`tests/suggested-call-invariant.test.ts`) now also rejects assignment-style construction in `src/`, with `[literal]` / `[assign]` markers in offender reports.
|
|
61
|
+
- `buildSyntheticCallToolResult` now skips the `suggestedCall` synthesis entirely when `ctx.toolName` is missing (the supervisor's `tool = ctx.toolName ?? "unknown"` fallback path). Previously the synthesized `tool: "unknown"` flowed through `buildSuggestedCall`'s fail-open unknown-tool branch and published a `suggestedCall: { tool: "unknown", params: {...} }` payload that was not re-callable by the agent — violating the gate's stated invariant. The diagnostic-only `meta.restart.redactedToolArgs` field still surfaces the args so debug surfaces can inspect them. The `buildSuggestedCall` helper's fail-open behavior for unregistered tools is preserved because many service-level tests exercise code without booting `src/index.ts` and expect the fail-open contract; the fix is targeted at the one production code path (the supervisor) that was actually leaking unre-callable payloads.
|
|
62
|
+
- `batch-class-source`'s schema-level duplicate-`outputFile` guard now normalizes paths via `path.resolve` (mirroring the writer's `getClassSource` semantics) before comparing entries. Previously the guard keyed by `entry.outputFile.trim()` only, so semantically-equivalent aliases (`out.java` vs `./out.java` vs `dir/../out.java`) bypassed the check and concurrent writes still raced on the same physical file. The error message now cites the canonical resolved path so the user sees what collided.
|
|
63
|
+
- `errorToBatchEntryProblem` for non-`AppError` failures now emits a fixed sanitized `detail: "Unexpected server error."` to clients (matching the single-tool `mapErrorToProblem` generic-error contract) and logs the raw message server-side (`log("error", "batch.entry.unhandled", { instance, reason })`) for diagnostics. Previously the public per-entry `error.detail` carried `Error.message` verbatim, which could expose internal filesystem paths, parser internals, or assertion text through the public envelope while the top-level batch call still returned a normal result envelope.
|
|
64
|
+
- `buildSyntheticCallToolResult` now also drops `suggestedCall` when `ctx.toolName` is present but unregistered (typo, disabled tool, or version-skewed name from an older server run). The supervisor consults `getToolSchema` itself before invoking the gate; `buildSuggestedCall` continues to fail open for unregistered names by design (service-level tests that do not boot `src/index.ts` rely on the fail-open contract). The diagnostic-only `meta.restart.redactedToolArgs` field still surfaces the args.
|
|
65
|
+
- Batch lookup `summary` now carries `sharedArtifactWarnings?: string[]` populated from the one-shot shared `resolveArtifact` call. Previously the resolution warnings (version approximation, mapping fallback, source coverage gaps, workspace/dependency resolution caveats) were captured into the batch service's local `SharedArtifact` object and discarded, while per-entry calls dispatched by `artifactId` never re-ran the resolution. The field is omitted when no warnings were produced. Applies to `batch-class-source`, `batch-class-members`, and `batch-symbol-exists`; `batch-mappings` does not run a shared artifact resolution and is unaffected.
|
|
66
|
+
- `statusForErrorCode` now maps `ERR_STAGE_BUDGET_PRE_PARSE` to HTTP-style status 408 (Request Timeout). Previously the code fell through to status 500, misclassifying a controlled `validate-mixin` budget exhaustion (caller-recoverable via `mixinConfigPath` shrink, budget raise, or `MIXIN_STAGE_BUDGETS_OFF=1`) as an internal server failure.
|
|
67
|
+
- `statusForErrorCode` now maps `ERR_WORKSPACE_VERSION_UNRESOLVED` and `ERR_DEPENDENCY_VERSION_UNRESOLVED` to HTTP-style status 422 (Unprocessable Entity). Previously they fell through to status 500, misclassifying a caller-recoverable input gap (caller can retry by passing `target.kind="version"` with an explicit Minecraft version, or by pointing `projectPath` at a workspace whose `gradle.properties` carries `minecraft_version`) as an internal server failure. `batch-symbol-exists` is the most likely surface for this gap because workspace targets without a detectable Minecraft version are the new path's primary failure mode.
|
|
68
|
+
|
|
8
69
|
## [4.0.0] - 2026-04-18
|
|
9
70
|
|
|
10
71
|
### Changed
|
package/README.md
CHANGED
|
@@ -11,20 +11,21 @@
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
`@adhisang/minecraft-modding-mcp` is an
|
|
14
|
+
`@adhisang/minecraft-modding-mcp` is an MCP server for AI-assisted Minecraft modding workflows, built on the [Model Context Protocol](https://modelcontextprotocol.io/). Use it when an agent needs to inspect Minecraft source, resolve mappings, compare versions, analyze mod JARs, validate Mixin, Access Widener, or Access Transformer files, or work with NBT and registry data from an MCP client.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
It runs over stdio and works with Claude Desktop, Claude Code, VS Code, Codex CLI, Gemini CLI, and other MCP-capable clients.
|
|
17
|
+
|
|
18
|
+
**37 tools** (6 entry + 31 expert) | **7 resources** | **4 namespace mappings** | **SQLite-backed cache**
|
|
17
19
|
|
|
18
20
|
## Features
|
|
19
21
|
|
|
20
|
-
- **Source
|
|
21
|
-
- **
|
|
22
|
-
- **Version
|
|
23
|
-
- **Mod JAR
|
|
24
|
-
- **
|
|
25
|
-
- **NBT
|
|
26
|
-
- **
|
|
27
|
-
- **MCP Resources**: expose versions, class source, artifact metadata, and mappings through URI-based resources
|
|
22
|
+
- **Source exploration**: browse, list, and search decompiled Minecraft source with line-level context
|
|
23
|
+
- **Mapping-aware symbol work**: convert class, field, and method names between `obfuscated`, `mojang`, `intermediary`, and `yarn`
|
|
24
|
+
- **Version comparison**: compare class signatures, registry entries, and migration-oriented summaries across Minecraft versions
|
|
25
|
+
- **Mod JAR analysis**: read Fabric, Forge, and NeoForge metadata, entrypoints, Mixin configs, dependencies, source, and remap previews
|
|
26
|
+
- **Project validation**: validate Mixin source, `.accesswidener` files, and Forge/NeoForge Access Transformer files against the target version
|
|
27
|
+
- **NBT, registry, cache, and diagnostics**: patch NBT payloads, inspect generated registry data, and manage cache/runtime state
|
|
28
|
+
- **MCP resources**: expose versions, class source, artifact metadata, and mappings through URI-based resources
|
|
28
29
|
|
|
29
30
|
## Quick Start
|
|
30
31
|
|
|
@@ -41,11 +42,11 @@ Start the server locally:
|
|
|
41
42
|
npx -y @adhisang/minecraft-modding-mcp
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
If automatic JAR downloads are blocked in your environment, set `MCP_VINEFLOWER_JAR_PATH` and `MCP_TINY_REMAPPER_JAR_PATH`
|
|
45
|
+
Use this same command in MCP client configs. If automatic JAR downloads are blocked in your environment, set `MCP_VINEFLOWER_JAR_PATH` and `MCP_TINY_REMAPPER_JAR_PATH` there.
|
|
45
46
|
|
|
46
47
|
### Client Setup
|
|
47
48
|
|
|
48
|
-
CLI clients
|
|
49
|
+
CLI clients can register the package command directly.
|
|
49
50
|
|
|
50
51
|
Claude Code:
|
|
51
52
|
|
|
@@ -61,7 +62,7 @@ codex mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp
|
|
|
61
62
|
|
|
62
63
|
Run `claude mcp list` or `codex mcp list` after registration to verify the server is available.
|
|
63
64
|
|
|
64
|
-
The stdio transport auto-detects
|
|
65
|
+
The stdio transport auto-detects newline-delimited and `Content-Length` framing, so the same server command works across Codex and standard MCP clients.
|
|
65
66
|
|
|
66
67
|
#### Claude Desktop
|
|
67
68
|
|
|
@@ -135,9 +136,9 @@ Pass environment variables to override defaults:
|
|
|
135
136
|
|
|
136
137
|
## Start Here
|
|
137
138
|
|
|
138
|
-
These six top-level workflow tools cover the common
|
|
139
|
+
These six top-level workflow tools cover the common paths and return summary-first results. They are the best default starting points for agents and MCP clients.
|
|
139
140
|
|
|
140
|
-
All six return `result.summary` first
|
|
141
|
+
All six return `result.summary` first and can include `summary.nextActions` when there is a clear follow-up step. Pick the tool from the table, then use the examples and reference docs for exact payloads.
|
|
141
142
|
|
|
142
143
|
| Tool | Start here for |
|
|
143
144
|
| --- | --- |
|
|
@@ -150,14 +151,16 @@ All six return `result.summary` first, and can include `summary.nextActions` whe
|
|
|
150
151
|
|
|
151
152
|
### Workflow Notes
|
|
152
153
|
|
|
153
|
-
|
|
154
|
+
These notes cover high-frequency decisions during onboarding. For the full pitfall list, exact contracts, migration notes, and environment variables, see [docs/tool-reference.md](docs/tool-reference.md).
|
|
154
155
|
|
|
155
156
|
- `search-class-source` defaults to `queryMode="auto"` and keeps separator queries such as `foo.bar`, `foo_bar`, and `foo$bar` on the indexed path. Use `queryMode="literal"` for an explicit full substring scan.
|
|
156
157
|
- If you do not already have an artifact, prefer `subject.kind="workspace"` for `inspect-minecraft` instead of guessing artifact details. When artifact context is the only missing input, a retryable `suggestedCall` preserves the requested task.
|
|
157
158
|
- `trace-symbol-lifecycle` expects `Class.method` in `symbol`. Keep exact overload matching in the separate `descriptor` field.
|
|
158
159
|
- For unobfuscated releases such as `26.1+`, `check-symbol-exists` and `analyze-symbol task="exists"` validate `mojang` lookups against runtime bytecode when no mapping graph exists, and return `mapping_unavailable` when the runtime JAR itself is unreachable.
|
|
159
160
|
- `analyze-mod` and `validate-project` require structured `subject` objects and canonical `include` groups; stale string-subject or domain-include payloads return `ERR_INVALID_INPUT` with a retryable `suggestedCall`.
|
|
160
|
-
- `validate-project task="project-summary"` propagates `preferProjectVersion=true` across discovered Mixin, Access Widener, and Access Transformer checks.
|
|
161
|
+
- `validate-project task="project-summary"` propagates `preferProjectVersion=true` across discovered Mixin, Access Widener, and Access Transformer checks. If no version can be resolved from the request or `gradle.properties`, the summary returns recovery guidance instead of guessing.
|
|
162
|
+
- `validate-mixin` and `validate-project` keep `mapping-health` lightweight for `obfuscated` and `mojang` validation, avoiding full Tiny mapping graph loads unless `intermediary` or `yarn` namespaces are requested.
|
|
163
|
+
- `validate-project task="project-summary"` uses a lightweight artifact probe for `tasks["minecraft.artifact.resolved"]`; it does not decompile Minecraft or rebuild the source index just to report per-probe status. Set `VALIDATE_PROJECT_TASKS_OFF=1` to omit the additive `tasks` field.
|
|
161
164
|
|
|
162
165
|
### Inspect Minecraft source from a version
|
|
163
166
|
|
|
@@ -239,7 +242,7 @@ Workspace summaries still default to discovering mixins and access wideners. Add
|
|
|
239
242
|
## Documentation
|
|
240
243
|
|
|
241
244
|
- [Detailed example requests](docs/examples.md) for copyable payloads and common workflows
|
|
242
|
-
- [Tool and configuration reference](docs/tool-reference.md) for exact inputs, outputs, resource behavior, environment variables, and migration notes
|
|
245
|
+
- [Tool and configuration reference](docs/tool-reference.md) for exact inputs, outputs, resource behavior, environment variables, and migration notes. Start with the [Which Tool for Which Question](docs/tool-reference.md#which-tool-for-which-question) decision table when you are not sure which tool to call.
|
|
243
246
|
- [日本語 README](docs/README-ja.md) for a Japanese onboarding overview
|
|
244
247
|
|
|
245
248
|
## Tool Surface
|
|
@@ -305,9 +308,7 @@ Tools for converting symbol names between namespaces and checking symbol existen
|
|
|
305
308
|
| `check-symbol-exists` | Check whether a class, field, or method exists in a namespace |
|
|
306
309
|
<!-- END GENERATED TOOL TABLE: mapping-symbols -->
|
|
307
310
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
`get-class-source`, `get-class-members`, `search-class-source`, and `list-artifact-files` accept the same `compact` parameter as opt-in (default `false`). When enabled it strips `provenance`, `artifactContents`, `qualityFlags`, and (for `get-class-members`) `context`, while preserving primary payloads (`sourceText`, `members`/`counts`, `hits`, `items`). See [docs/tool-reference.md](docs/tool-reference.md) for the full per-tool field list.
|
|
311
|
+
Several lookup tools support `compact` result shaping for shorter responses. See [docs/tool-reference.md](docs/tool-reference.md) for defaults and the full per-tool field list.
|
|
311
312
|
|
|
312
313
|
### NBT Utilities
|
|
313
314
|
|
|
@@ -337,14 +338,15 @@ Tools for extracting metadata from mod JARs, decompiling mod source, searching m
|
|
|
337
338
|
|
|
338
339
|
### Validation
|
|
339
340
|
|
|
340
|
-
Tools for validating Mixin source, Access Widener files, and Forge/NeoForge Access Transformer files against a target Minecraft version.
|
|
341
|
+
Tools for validating Mixin source, Access Widener files, and Forge/NeoForge Access Transformer files against a target Minecraft version. Workspace options let validation use loader/runtime context when a project path is available.
|
|
341
342
|
|
|
342
343
|
<!-- BEGIN GENERATED TOOL TABLE: validation -->
|
|
343
344
|
| Tool | Purpose |
|
|
344
345
|
| --- | --- |
|
|
345
|
-
| `validate-mixin` | Validate Mixin source against a target Minecraft version |
|
|
346
|
+
| `validate-mixin` | Validate Mixin source against a target Minecraft version (returns `validationStatus: "partial"` with `targetOutcomes` when a stage budget defers work) |
|
|
346
347
|
| `validate-access-widener` | Validate Access Widener content against a target Minecraft version, optionally using runtime-aware Loom artifacts |
|
|
347
348
|
| `validate-access-transformer` | Validate Access Transformer content against a target Minecraft version, optionally using Forge/NeoForge runtime artifacts |
|
|
349
|
+
| `verify-mixin-target` | Single-call probe for owner / member existence with `@Shadow` / `@Accessor` / `@Invoker` advice |
|
|
348
350
|
<!-- END GENERATED TOOL TABLE: validation -->
|
|
349
351
|
|
|
350
352
|
### Registry & Diagnostics
|
|
@@ -358,6 +360,21 @@ Tools for querying generated registry data and inspecting server runtime state.
|
|
|
358
360
|
| `get-runtime-metrics` | Inspect runtime metrics and latency snapshots |
|
|
359
361
|
<!-- END GENERATED TOOL TABLE: registry-diagnostics -->
|
|
360
362
|
|
|
363
|
+
### Batch Lookup
|
|
364
|
+
|
|
365
|
+
Tools that share one resolved artifact or Minecraft version across a fixed shortlist. Results include one status per item plus an aggregate `summary`. See [Batch lookup contract](docs/tool-reference.md#batch-lookup-contract) for failure handling and retry mapping.
|
|
366
|
+
|
|
367
|
+
Within one MCP server process, batch class lookups that need the same binary fallback share one in-flight source indexing/decompile rebuild for that artifact.
|
|
368
|
+
|
|
369
|
+
<!-- BEGIN GENERATED TOOL TABLE: batch-lookup -->
|
|
370
|
+
| Tool | Purpose |
|
|
371
|
+
| --- | --- |
|
|
372
|
+
| `batch-class-source` | Read source for many classes against one shared resolved artifact (1..50 entries per call) |
|
|
373
|
+
| `batch-class-members` | List members for many classes against one shared resolved artifact (1..50 entries per call) |
|
|
374
|
+
| `batch-symbol-exists` | Probe symbol existence for many entries against one shared Minecraft-version artifact (workspace / version targets only) |
|
|
375
|
+
| `batch-mappings` | Translate many symbols across mapping namespaces with one shared Minecraft version (no shared artifact) |
|
|
376
|
+
<!-- END GENERATED TOOL TABLE: batch-lookup -->
|
|
377
|
+
|
|
361
378
|
Detailed parameter constraints, migration notes, resource behavior, and the full environment-variable matrix live in [docs/tool-reference.md](docs/tool-reference.md).
|
|
362
379
|
|
|
363
380
|
## Development
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const SUGGESTED_CALL_VALIDATE_OFF: boolean;
|
|
2
|
+
export type SuggestedCallExample = {
|
|
3
|
+
params: unknown;
|
|
4
|
+
reason: string;
|
|
5
|
+
};
|
|
6
|
+
export type SuggestedCallSpec = {
|
|
7
|
+
tool: string;
|
|
8
|
+
params: unknown;
|
|
9
|
+
examples?: SuggestedCallExample[];
|
|
10
|
+
};
|
|
11
|
+
export type ValidatedSuggestedCall = {
|
|
12
|
+
tool: string;
|
|
13
|
+
params: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
export type ValidatedExampleCall = {
|
|
16
|
+
tool: string;
|
|
17
|
+
params: Record<string, unknown>;
|
|
18
|
+
reason: string;
|
|
19
|
+
valid: true;
|
|
20
|
+
};
|
|
21
|
+
export type SuggestedCallOutput = {
|
|
22
|
+
suggestedCall?: ValidatedSuggestedCall;
|
|
23
|
+
exampleCalls?: ValidatedExampleCall[];
|
|
24
|
+
/** Set to `true` when the caller supplied `params` but the gate dropped it.
|
|
25
|
+
* Spread into AppError `details`; `mapErrorToProblem` reads the marker to
|
|
26
|
+
* append the fallback hint to `error.hints` and strips it before emission. */
|
|
27
|
+
_suggestedCallPrimaryDropped?: true;
|
|
28
|
+
};
|
|
29
|
+
export declare function buildSuggestedCall(spec: SuggestedCallSpec): SuggestedCallOutput;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getToolSchema, validateToolParams } from "./tool-schema-registry.js";
|
|
2
|
+
export const SUGGESTED_CALL_VALIDATE_OFF = process.env.SUGGESTED_CALL_VALIDATE_OFF === "1";
|
|
3
|
+
function asParamsRecord(params) {
|
|
4
|
+
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
return params;
|
|
8
|
+
}
|
|
9
|
+
export function buildSuggestedCall(spec) {
|
|
10
|
+
if (SUGGESTED_CALL_VALIDATE_OFF) {
|
|
11
|
+
const rawParams = asParamsRecord(spec.params);
|
|
12
|
+
if (rawParams) {
|
|
13
|
+
return { suggestedCall: { tool: spec.tool, params: rawParams } };
|
|
14
|
+
}
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
const primaryParams = asParamsRecord(spec.params);
|
|
18
|
+
if (primaryParams) {
|
|
19
|
+
// Unknown-tool fail-open: the registry is populated at index.ts startup;
|
|
20
|
+
// service-level tests that do not boot index.ts run with an empty
|
|
21
|
+
// registry and rely on this pass-through. Callers that synthesize a tool
|
|
22
|
+
// name from runtime data (e.g. `?? "unknown"`) MUST skip this helper, or
|
|
23
|
+
// a non-callable payload escapes via this branch.
|
|
24
|
+
if (!getToolSchema(spec.tool)) {
|
|
25
|
+
return { suggestedCall: { tool: spec.tool, params: primaryParams } };
|
|
26
|
+
}
|
|
27
|
+
const primary = validateToolParams(spec.tool, primaryParams);
|
|
28
|
+
if (primary.valid) {
|
|
29
|
+
return { suggestedCall: { tool: spec.tool, params: primaryParams } };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const droppedMarker = spec.params !== undefined ? { _suggestedCallPrimaryDropped: true } : {};
|
|
33
|
+
if (spec.examples && spec.examples.length > 0) {
|
|
34
|
+
const validated = spec.examples
|
|
35
|
+
.map((example) => {
|
|
36
|
+
const exampleParams = asParamsRecord(example.params);
|
|
37
|
+
if (!exampleParams) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const result = validateToolParams(spec.tool, exampleParams);
|
|
41
|
+
if (!result.valid) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
tool: spec.tool,
|
|
46
|
+
params: exampleParams,
|
|
47
|
+
reason: example.reason,
|
|
48
|
+
valid: true
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
.filter((entry) => entry !== null);
|
|
52
|
+
if (validated.length > 0) {
|
|
53
|
+
return { exampleCalls: validated, ...droppedMarker };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return droppedMarker;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=build-suggested-call.js.map
|
package/dist/cache-registry.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PathRuntimeInfo } from "./path-converter.js";
|
|
2
|
-
|
|
2
|
+
import { type WorkspaceContextCache } from "./workspace-context-cache.js";
|
|
3
|
+
export declare const PUBLIC_CACHE_KINDS: readonly ["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap", "workspace"];
|
|
3
4
|
export type PublicCacheKind = (typeof PUBLIC_CACHE_KINDS)[number];
|
|
4
5
|
export declare const CACHE_HEALTH_STATES: readonly ["healthy", "partial", "stale", "orphaned", "corrupt", "in_use"];
|
|
5
6
|
export type CacheHealthState = (typeof CACHE_HEALTH_STATES)[number];
|
|
@@ -37,6 +38,7 @@ export type CacheRegistryConfig = {
|
|
|
37
38
|
cacheDir: string;
|
|
38
39
|
sqlitePath: string;
|
|
39
40
|
pathRuntimeInfo?: PathRuntimeInfo;
|
|
41
|
+
workspaceContextCache?: WorkspaceContextCache;
|
|
40
42
|
};
|
|
41
43
|
export interface CacheRegistry {
|
|
42
44
|
summarize(input: {
|
package/dist/cache-registry.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join, resolve } from "node:path";
|
|
|
4
4
|
import { createError, ERROR_CODES } from "./errors.js";
|
|
5
5
|
import { normalizeOptionalPathForHost } from "./path-converter.js";
|
|
6
6
|
import Database from "./storage/sqlite.js";
|
|
7
|
+
import { getProcessWorkspaceContextCache } from "./workspace-context-cache.js";
|
|
7
8
|
export const PUBLIC_CACHE_KINDS = [
|
|
8
9
|
"artifact-index",
|
|
9
10
|
"downloads",
|
|
@@ -11,7 +12,8 @@ export const PUBLIC_CACHE_KINDS = [
|
|
|
11
12
|
"registry",
|
|
12
13
|
"decompiled-source",
|
|
13
14
|
"mod-remap",
|
|
14
|
-
"binary-remap"
|
|
15
|
+
"binary-remap",
|
|
16
|
+
"workspace"
|
|
15
17
|
];
|
|
16
18
|
export const CACHE_HEALTH_STATES = [
|
|
17
19
|
"healthy",
|
|
@@ -40,6 +42,8 @@ function kindRoot(config, cacheKind) {
|
|
|
40
42
|
return join(config.cacheDir, "remapped-mods");
|
|
41
43
|
case "binary-remap":
|
|
42
44
|
return join(config.cacheDir, "remapped");
|
|
45
|
+
case "workspace":
|
|
46
|
+
return "<in-memory:workspace-context-cache>";
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
async function listFilesRecursive(root) {
|
|
@@ -417,6 +421,26 @@ async function artifactIndexEntries(config) {
|
|
|
417
421
|
db.close();
|
|
418
422
|
}
|
|
419
423
|
}
|
|
424
|
+
function workspaceCacheEntries(workspaceCache) {
|
|
425
|
+
const contexts = workspaceCache.list();
|
|
426
|
+
return contexts.map((ctx) => ({
|
|
427
|
+
cacheKind: "workspace",
|
|
428
|
+
entryId: ctx.projectPath,
|
|
429
|
+
path: ctx.projectPath,
|
|
430
|
+
sizeBytes: 0,
|
|
431
|
+
status: "healthy",
|
|
432
|
+
meta: {
|
|
433
|
+
projectPath: ctx.projectPath,
|
|
434
|
+
minecraftVersion: ctx.minecraftVersion,
|
|
435
|
+
compileMapping: ctx.compileMapping,
|
|
436
|
+
loader: ctx.loader,
|
|
437
|
+
detectedAt: new Date(ctx.detectedAt).toISOString(),
|
|
438
|
+
updatedAt: new Date(ctx.detectedAt).toISOString(),
|
|
439
|
+
partial: ctx.partial === true,
|
|
440
|
+
dependencyVersionCount: ctx.dependencyVersions.size
|
|
441
|
+
}
|
|
442
|
+
}));
|
|
443
|
+
}
|
|
420
444
|
async function fileBackedEntries(config, cacheKind) {
|
|
421
445
|
const root = kindRoot(config, cacheKind);
|
|
422
446
|
const files = await listFilesRecursive(root);
|
|
@@ -454,18 +478,25 @@ async function fileBackedEntries(config, cacheKind) {
|
|
|
454
478
|
return entries;
|
|
455
479
|
}
|
|
456
480
|
export function createCacheRegistry(config) {
|
|
481
|
+
const workspaceCache = config.workspaceContextCache ?? getProcessWorkspaceContextCache();
|
|
457
482
|
async function collectEntries(cacheKinds, selector) {
|
|
458
483
|
const selectedKinds = cacheKinds?.length ? cacheKinds : [...PUBLIC_CACHE_KINDS];
|
|
459
484
|
const preparedSelector = prepareSelector(selector, config.pathRuntimeInfo);
|
|
460
485
|
const now = Date.now();
|
|
461
|
-
const entries = await Promise.all(selectedKinds.map((cacheKind) =>
|
|
462
|
-
|
|
463
|
-
|
|
486
|
+
const entries = await Promise.all(selectedKinds.map((cacheKind) => {
|
|
487
|
+
if (cacheKind === "artifact-index") {
|
|
488
|
+
return artifactIndexEntries(config);
|
|
489
|
+
}
|
|
490
|
+
if (cacheKind === "workspace") {
|
|
491
|
+
return Promise.resolve(workspaceCacheEntries(workspaceCache));
|
|
492
|
+
}
|
|
493
|
+
return fileBackedEntries(config, cacheKind);
|
|
494
|
+
}));
|
|
464
495
|
const enriched = entries
|
|
465
496
|
.flat()
|
|
466
497
|
.map((entry) => ({
|
|
467
498
|
...entry,
|
|
468
|
-
status: deriveEntryStatus(entry, config, now)
|
|
499
|
+
status: entry.cacheKind === "workspace" ? entry.status : deriveEntryStatus(entry, config, now)
|
|
469
500
|
}));
|
|
470
501
|
return sortEntries(enriched.filter((entry) => matchesSelector(entry, preparedSelector, config.pathRuntimeInfo)));
|
|
471
502
|
}
|
|
@@ -475,8 +506,17 @@ export function createCacheRegistry(config) {
|
|
|
475
506
|
const entries = await collectEntries(selectedKinds, input.selector);
|
|
476
507
|
const kinds = {};
|
|
477
508
|
for (const cacheKind of selectedKinds) {
|
|
478
|
-
const root = kindRoot(config, cacheKind);
|
|
479
509
|
const rows = entries.filter((entry) => entry.cacheKind === cacheKind);
|
|
510
|
+
if (cacheKind === "workspace") {
|
|
511
|
+
kinds[cacheKind] = {
|
|
512
|
+
cacheKind,
|
|
513
|
+
entryCount: rows.length,
|
|
514
|
+
totalBytes: 0,
|
|
515
|
+
status: "healthy"
|
|
516
|
+
};
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
const root = kindRoot(config, cacheKind);
|
|
480
520
|
kinds[cacheKind] = {
|
|
481
521
|
cacheKind,
|
|
482
522
|
entryCount: rows.length,
|
|
@@ -519,6 +559,10 @@ export function createCacheRegistry(config) {
|
|
|
519
559
|
db?.prepare("DELETE FROM artifacts WHERE artifact_id = ?").run([entry.entryId]);
|
|
520
560
|
continue;
|
|
521
561
|
}
|
|
562
|
+
if (entry.cacheKind === "workspace") {
|
|
563
|
+
workspaceCache.invalidate(entry.entryId);
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
522
566
|
if (existsSync(entry.path)) {
|
|
523
567
|
await rm(entry.path, { force: true });
|
|
524
568
|
}
|
|
@@ -72,11 +72,11 @@ export declare const analyzeSymbolSchema: z.ZodEffects<z.ZodObject<{
|
|
|
72
72
|
};
|
|
73
73
|
signatureMode: "exact" | "name-only";
|
|
74
74
|
maxCandidates: number;
|
|
75
|
-
projectPath?: string | undefined;
|
|
76
75
|
version?: string | undefined;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
projectPath?: string | undefined;
|
|
77
|
+
sourceMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
78
|
+
targetMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
79
|
+
classNameMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
80
80
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
81
81
|
include?: string[] | undefined;
|
|
82
82
|
includeKinds?: ("class" | "field" | "method")[] | undefined;
|
|
@@ -89,11 +89,11 @@ export declare const analyzeSymbolSchema: z.ZodEffects<z.ZodObject<{
|
|
|
89
89
|
descriptor?: string | undefined;
|
|
90
90
|
owner?: string | undefined;
|
|
91
91
|
};
|
|
92
|
-
projectPath?: string | undefined;
|
|
93
92
|
version?: string | undefined;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
projectPath?: string | undefined;
|
|
94
|
+
sourceMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
95
|
+
targetMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
96
|
+
classNameMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
97
97
|
nameMode?: "auto" | "fqcn" | undefined;
|
|
98
98
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
99
99
|
include?: string[] | undefined;
|
|
@@ -112,11 +112,11 @@ export declare const analyzeSymbolSchema: z.ZodEffects<z.ZodObject<{
|
|
|
112
112
|
};
|
|
113
113
|
signatureMode: "exact" | "name-only";
|
|
114
114
|
maxCandidates: number;
|
|
115
|
-
projectPath?: string | undefined;
|
|
116
115
|
version?: string | undefined;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
projectPath?: string | undefined;
|
|
117
|
+
sourceMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
118
|
+
targetMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
119
|
+
classNameMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
120
120
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
121
121
|
include?: string[] | undefined;
|
|
122
122
|
includeKinds?: ("class" | "field" | "method")[] | undefined;
|
|
@@ -129,11 +129,11 @@ export declare const analyzeSymbolSchema: z.ZodEffects<z.ZodObject<{
|
|
|
129
129
|
descriptor?: string | undefined;
|
|
130
130
|
owner?: string | undefined;
|
|
131
131
|
};
|
|
132
|
-
projectPath?: string | undefined;
|
|
133
132
|
version?: string | undefined;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
projectPath?: string | undefined;
|
|
134
|
+
sourceMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
135
|
+
targetMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
136
|
+
classNameMapping?: "obfuscated" | "mojang" | "intermediary" | "yarn" | undefined;
|
|
137
137
|
nameMode?: "auto" | "fqcn" | undefined;
|
|
138
138
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
139
139
|
include?: string[] | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { GetClassMembersInput, GetClassMembersOutput, ResolveArtifactInput, ResolveArtifactOutput } from "../source-service.js";
|
|
2
|
+
import type { ArtifactScope, MappingSourcePriority, ResolveArtifactTargetInput, SourceMapping } from "../types.js";
|
|
3
|
+
import { type BatchOutput } from "./batch-runner.js";
|
|
4
|
+
export type BatchClassMembersDeps = {
|
|
5
|
+
resolveArtifact: (input: ResolveArtifactInput) => Promise<ResolveArtifactOutput>;
|
|
6
|
+
getClassMembers: (input: GetClassMembersInput) => Promise<GetClassMembersOutput>;
|
|
7
|
+
};
|
|
8
|
+
export type BatchClassMembersEntry = {
|
|
9
|
+
className: string;
|
|
10
|
+
access?: "public" | "all";
|
|
11
|
+
includeSynthetic?: boolean;
|
|
12
|
+
includeInherited?: boolean;
|
|
13
|
+
memberPattern?: string;
|
|
14
|
+
maxMembers?: number;
|
|
15
|
+
};
|
|
16
|
+
export type BatchClassMembersInput = {
|
|
17
|
+
target: ResolveArtifactTargetInput;
|
|
18
|
+
mapping?: SourceMapping;
|
|
19
|
+
sourcePriority?: MappingSourcePriority;
|
|
20
|
+
allowDecompile?: boolean;
|
|
21
|
+
projectPath?: string;
|
|
22
|
+
scope?: ArtifactScope;
|
|
23
|
+
preferProjectVersion?: boolean;
|
|
24
|
+
strictVersion?: boolean;
|
|
25
|
+
concurrency?: number;
|
|
26
|
+
failFast?: boolean;
|
|
27
|
+
compact?: boolean;
|
|
28
|
+
entries: readonly BatchClassMembersEntry[];
|
|
29
|
+
};
|
|
30
|
+
export declare class BatchClassMembersService {
|
|
31
|
+
private readonly deps;
|
|
32
|
+
constructor(deps: BatchClassMembersDeps);
|
|
33
|
+
execute(input: BatchClassMembersInput): Promise<BatchOutput<Record<string, unknown>>>;
|
|
34
|
+
}
|