@adhisang/minecraft-modding-mcp 3.1.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +37 -18
- package/dist/access-transformer-parser.d.ts +17 -0
- package/dist/access-transformer-parser.js +97 -0
- package/dist/cache-registry.d.ts +1 -1
- package/dist/cache-registry.js +10 -2
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +24 -0
- package/dist/config.d.ts +10 -1
- package/dist/config.js +52 -1
- package/dist/decompiler/vineflower.js +22 -21
- package/dist/entry-tools/analyze-mod-service.d.ts +4 -4
- package/dist/entry-tools/analyze-symbol-service.d.ts +22 -22
- package/dist/entry-tools/analyze-symbol-service.js +13 -2
- package/dist/entry-tools/inspect-minecraft-service.d.ts +168 -168
- package/dist/entry-tools/inspect-minecraft-service.js +8 -2
- package/dist/entry-tools/manage-cache-service.d.ts +4 -4
- package/dist/entry-tools/validate-project-service.d.ts +153 -16
- package/dist/entry-tools/validate-project-service.js +442 -25
- package/dist/gradle-paths.d.ts +4 -0
- package/dist/gradle-paths.js +57 -0
- package/dist/index.js +148 -30
- package/dist/lru-list.d.ts +31 -0
- package/dist/lru-list.js +102 -0
- package/dist/mapping-pipeline-service.d.ts +12 -1
- package/dist/mapping-pipeline-service.js +28 -1
- package/dist/mapping-service.d.ts +16 -0
- package/dist/mapping-service.js +405 -68
- package/dist/minecraft-explorer-service.d.ts +13 -0
- package/dist/minecraft-explorer-service.js +8 -4
- package/dist/mixin-validator.d.ts +33 -2
- package/dist/mixin-validator.js +218 -17
- package/dist/mod-analyzer.d.ts +1 -0
- package/dist/mod-analyzer.js +17 -1
- package/dist/mod-decompile-service.js +4 -4
- package/dist/mod-remap-service.js +1 -54
- package/dist/mod-search-service.d.ts +1 -0
- package/dist/mod-search-service.js +84 -51
- package/dist/observability.d.ts +18 -1
- package/dist/observability.js +44 -1
- package/dist/response-utils.d.ts +69 -0
- package/dist/response-utils.js +227 -0
- package/dist/source-jar-reader.d.ts +16 -0
- package/dist/source-jar-reader.js +103 -1
- package/dist/source-resolver.d.ts +9 -1
- package/dist/source-resolver.js +23 -16
- package/dist/source-service.d.ts +119 -3
- package/dist/source-service.js +1836 -218
- package/dist/storage/artifacts-repo.d.ts +4 -1
- package/dist/storage/artifacts-repo.js +33 -5
- package/dist/storage/files-repo.d.ts +0 -2
- package/dist/storage/files-repo.js +0 -11
- package/dist/storage/migrations.d.ts +1 -1
- package/dist/storage/migrations.js +10 -2
- package/dist/storage/schema.d.ts +2 -0
- package/dist/storage/schema.js +25 -0
- package/dist/tool-contract-manifest.js +8 -6
- package/dist/types.d.ts +20 -0
- package/dist/workspace-mapping-service.d.ts +13 -0
- package/dist/workspace-mapping-service.js +146 -14
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,55 @@ 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.0.0] - 2026-04-18
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- BREAKING: `resolve-artifact`, `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, and `check-symbol-exists` now default `compact` to `true` (was `false`). Pass `compact: false` to restore the full diagnostic shape.
|
|
12
|
+
- BREAKING: `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, `check-symbol-exists`, and `analyze-symbol` now default `maxCandidates` to `5` (was `200`; `200` is still the upper bound).
|
|
13
|
+
- BREAKING: `find-mapping` now defaults `signatureMode` to `"name-only"` (was effectively `"exact"`). `kind="method"` lookups without a `descriptor` no longer fail; pass `signatureMode: "exact"` explicitly for strict descriptor matching.
|
|
14
|
+
- BREAKING: `resolve-artifact` with `mapping="mojang"` and `target.kind="version"` against a still-obfuscated Minecraft version now succeeds by tiny-remapping the binary jar and decompiling the result, tagged `qualityFlags: ["binary-remapped", "decompiled"]` and `provenance.transformChain: ["binary-remap:obf->mojang", "decompile:vineflower"]`. The remapped jar is cached at `<cacheDir>/remapped/<artifactId>.jar`. Coordinate and jar targets are not eligible. `ERR_MAPPING_NOT_APPLIED` is still raised when tiny-remapper, the Mojang tiny mapping file, or the version's Mojang mappings are missing.
|
|
15
|
+
- `find-mapping` and `check-symbol-exists` accept an empty `descriptor` as equivalent to omitting it.
|
|
16
|
+
- Compact mode on mapping tools keeps the top three unresolved candidates with full metadata and slims the tail to `{kind, symbol, owner, name, descriptor, confidence, matchKind}`. A new `candidateDetailsTruncated` flag signals this slim, distinct from the existing `candidatesTruncated` (upstream truncation).
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `find-mapping` exposes `signatureMode` as a first-class input. `"exact"` matches `owner + name + descriptor`; `"name-only"` matches by `owner + name` and ranks overloads by confidence. `resolve-method-mapping-exact` retains strict exact-triple semantics.
|
|
20
|
+
- `get-class-source`, `get-class-members`, `search-class-source`, and `list-artifact-files` accept an opt-in `compact` parameter (default `false`). It strips diagnostic envelopes (`provenance`, `artifactContents`, `qualityFlags`, plus `context` for `get-class-members`) while preserving primary payloads (`sourceText`, `members`/`counts`, `hits`, `items`).
|
|
21
|
+
- `manage-cache` exposes the Mojang remapped jar under a new `binary-remap` cache kind with `selector.artifactId` filtering. LRU eviction unlinks the matching remapped jar so cache accounting stays consistent.
|
|
22
|
+
- `validate-mixin` top-level errors now carry `failedStage` on the `ProblemDetails` envelope (one of `input-validation | resolve | mapping-health | parse | target-lookup`), so callers can branch without parsing `message`.
|
|
23
|
+
- `validate-mixin` `quickSummary` appends notes when `provenance.scopeFallback` fires or `toolHealth.overallHealthy` is false.
|
|
24
|
+
- Ambiguous mapping responses in `find-mapping`, `resolve-method-mapping-exact`, and `check-symbol-exists` include recovery guidance in `warnings` (descriptor hints, `signatureMode="exact"` retries, `disambiguation.ownerHint`, raising `maxCandidates`).
|
|
25
|
+
- `docs/tool-reference.md` includes a "Which Tool for Which Question" decision table; `README.md` links to it from the Documentation section.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `check-symbol-exists` projects the caller's JVM descriptor to the obfuscated namespace before filtering method overloads, so `signatureMode="exact"` retries work with descriptors that reference remapped Minecraft classes. Mixed descriptors such as `(Lnet/minecraft/world/item/ItemStack;Ljava/lang/String;)V` resolve via partial projection instead of falling back to the unprojected source descriptor.
|
|
29
|
+
- `find-mapping` with `signatureMode="exact"` and `kind="method"` filters resolved candidates by the (projected) requested descriptor. A caller who supplied `foo(Z)V` is no longer told that `foo(I)V` is the exact mapping.
|
|
30
|
+
- Compact mode slim candidate projection retains `kind` and `symbol` alongside `owner`, `name`, `descriptor`, `confidence`, and `matchKind`, so clients keying off `kind` or `symbol` are no longer silently broken.
|
|
31
|
+
- `normalizeMethodDescriptor` rejects descriptors with more than 255 leading `[` (JVM §4.3.2) and rejects malformed shapes such as `()`, `(I)`, and `(L;)V` with `ERR_INVALID_INPUT`.
|
|
32
|
+
|
|
33
|
+
## [3.2.0] - 2026-04-12
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- `resolve-artifact`, `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, and `check-symbol-exists` now accept an optional `compact` parameter (default `false`). When `true`, empty arrays, null values, and empty objects are stripped from the top-level response. For `resolve-artifact`, compact mode additionally omits `provenance`, `artifactContents`, `sampleEntries`, `adjacentSourceCandidates`, `binaryJarPath`, `coordinate`, `repoUrl`, and `resolvedSourceJarPath`. For mapping tools, compact mode omits the redundant `candidates` array when the result is a single full-confidence exact-match resolution.
|
|
37
|
+
- `validate-access-widener` now accepts `projectPath`, `scope`, and `preferProjectVersion` for runtime-aware validation against Loom runtime jars, and reports additive `provenance`, `resolvedInRuntime`, and `resolvedRuntimeAccess` evidence for matched class, method, and field entries.
|
|
38
|
+
- Added `validate-access-transformer` for Forge / NeoForge Access Transformer validation, including `atNamespace` support, workspace-driven namespace inference, runtime artifact provenance, and per-entry runtime access evidence.
|
|
39
|
+
- `analyze-mod-jar` now surfaces packaged Access Transformer paths alongside mod metadata.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- `validate-access-widener` and `validate-access-transformer` runtime-aware method validation now preserves remapped JVM descriptors through exact and fallback member remaps, eliminating false-negative `method not found` results for entries whose descriptors reference remapped Minecraft classes such as `Level#setBlock(BlockPos, BlockState, int)`.
|
|
43
|
+
- `validate-access-widener` runtime-aware `scope: "merged"` now prefers explicit `*merged-intermediary*` / `*merged-mojang*` runtime jars over ambiguous `minecraft-merged.jar` candidates, and Loom tiny lookup now scans workspace and Gradle user-home caches so runtime validation can resolve descriptor remaps in normal Loom setups.
|
|
44
|
+
- `validate-project` now forwards workspace runtime context to discovered Access Widener validation so project-summary runs can use the same runtime-aware behavior as direct `validate-access-widener` calls.
|
|
45
|
+
- `validate-project` now discovers Access Transformer files, supports `task="access-transformer"`, and can include those validations in workspace summaries when `discover` requests them.
|
|
46
|
+
- `resolve-artifact`, `get-class-source`, `get-class-members`, and `inspect-minecraft` source/class-member flows now treat unobfuscated releases such as `26.1+` as native `mojang` runtime namespaces for both version and versioned-coordinate targets, avoiding false `ERR_MAPPING_NOT_APPLIED` failures and wrong-version Loom source-jar approximations when no exact source jar is present.
|
|
47
|
+
- `validate-mixin` tool-health diagnostics now treat unobfuscated `mojang` runtime names as available, while still flagging `intermediary`/`yarn` as unavailable on `26.1+`.
|
|
48
|
+
- `validate-project task="project-summary"` now pre-resolves `preferProjectVersion=true` consistently across discovered Access Widener and workspace Mixin checks, and returns a blocked summary with version-agnostic recovery guidance when discovered validators need a version but neither the request nor `gradle.properties` can supply one.
|
|
49
|
+
- `check-symbol-exists` and `analyze-symbol task="exists"` now fall back to unobfuscated runtime bytecode for `mojang`/runtime-name existence checks on `26.1+`, preserve the original `mapping_unavailable` result when the runtime JAR cannot be resolved, and return a targeted warning when callers provide only a short class name.
|
|
50
|
+
- Loom tiny mapping discovery no longer performs unbounded directory traversal when the version-specific cache directory is absent, preventing excessive memory consumption on systems with large Gradle caches.
|
|
51
|
+
- Mapping graph cache eviction after lifecycle scans now correctly releases all cached entries for a version instead of silently skipping them.
|
|
52
|
+
|
|
53
|
+
### Performance
|
|
54
|
+
- `resolve-artifact` source-jar detection and mapping tiny-jar loading now reuse a single ZIP walk per jar probe instead of reopening and fully enumerating matching archives on each helper call.
|
|
55
|
+
- `search-mod-source`, `decompile-mod-jar`, `get-mod-class-source`, `validate-project` workspace discovery, and workspace mapping detection now avoid synchronous hot-path file/glob reads and use bounded concurrent text reads where safe, reducing event-loop stalls on larger decompiled outputs and multi-module workspaces.
|
|
56
|
+
|
|
8
57
|
## [3.1.1] - 2026-03-21
|
|
9
58
|
|
|
10
59
|
### Fixed
|
package/README.md
CHANGED
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://github.com/adhi-jp/minecraft-modding-mcp/actions/workflows/ci.yml)
|
|
7
7
|
|
|
8
|
-
**[日本語](docs/README-ja.md)
|
|
8
|
+
**English** | [日本語](docs/README-ja.md)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **Note**: This project is entirely vibe-coded — built with AI-assisted development without formal specs.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
---
|
|
13
13
|
|
|
14
|
-
[MCP](https://modelcontextprotocol.io/)
|
|
14
|
+
`@adhisang/minecraft-modding-mcp` is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants structured access to Minecraft source code, mappings, mod JARs, registry data, and validation workflows. It works with Claude Desktop, Claude Code, VS Code, Codex CLI, Gemini CLI, and other MCP-capable clients.
|
|
15
15
|
|
|
16
|
-
**
|
|
16
|
+
**36 tools** (6 entry + 30 expert) | **7 resources** | **4 namespace mappings** | **SQLite-backed cache**
|
|
17
17
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
20
|
- **Source Exploration**: browse and search decompiled Minecraft source code with line-level precision and cursor-paginated file listing
|
|
21
21
|
- **Multi-Mapping Conversion**: translate class, field, and method names between `obfuscated`, `mojang`, `intermediary`, and `yarn`
|
|
22
22
|
- **Version Comparison**: diff class signatures and registry entries between Minecraft versions
|
|
23
|
-
- **Mod JAR Analysis**: extract metadata, dependencies, entrypoints,
|
|
24
|
-
- **Mixin and Access
|
|
23
|
+
- **Mod JAR Analysis**: extract metadata, dependencies, entrypoints, Mixin configs, and packaged Access Transformer paths from Fabric, Forge, and NeoForge mod JARs
|
|
24
|
+
- **Mixin, Access Widener, and Access Transformer Validation**: validate source, `.accesswidener`, and Forge/NeoForge access transformer files against a target Minecraft version
|
|
25
25
|
- **NBT Round-Trip**: decode NBT binary to typed JSON, apply RFC 6902 patches, and encode it back to NBT
|
|
26
26
|
- **Registry Data and Runtime Metrics**: query generated registry snapshots and inspect cache and latency counters
|
|
27
27
|
- **MCP Resources**: expose versions, class source, artifact metadata, and mappings through URI-based resources
|
|
@@ -47,8 +47,17 @@ If automatic JAR downloads are blocked in your environment, set `MCP_VINEFLOWER_
|
|
|
47
47
|
|
|
48
48
|
CLI clients:
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
Claude Code:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
claude mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
OpenAI Codex CLI:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
codex mcp add minecraft-modding -- npx -y @adhisang/minecraft-modding-mcp
|
|
60
|
+
```
|
|
52
61
|
|
|
53
62
|
Run `claude mcp list` or `codex mcp list` after registration to verify the server is available.
|
|
54
63
|
|
|
@@ -136,7 +145,7 @@ All six return `result.summary` first, and can include `summary.nextActions` whe
|
|
|
136
145
|
| `analyze-symbol` | symbol existence checks, mapping conversion, lifecycle tracing, and workspace symbol resolution |
|
|
137
146
|
| `compare-minecraft` | version-pair diffs, class diffs, registry diffs, and migration-oriented overviews |
|
|
138
147
|
| `analyze-mod` | mod metadata, decompile/search flows, class source, and safe remap preview/apply |
|
|
139
|
-
| `validate-project` | workspace summaries plus direct Mixin and Access
|
|
148
|
+
| `validate-project` | workspace summaries plus direct Mixin, Access Widener, and Access Transformer validation |
|
|
140
149
|
| `manage-cache` | cache inventory, verification, and preview/apply cleanup workflows |
|
|
141
150
|
|
|
142
151
|
### Workflow Notes
|
|
@@ -146,8 +155,9 @@ Keep only the high-frequency notes here. For the full pitfall list, exact contra
|
|
|
146
155
|
- `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.
|
|
147
156
|
- 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.
|
|
148
157
|
- `trace-symbol-lifecycle` expects `Class.method` in `symbol`. Keep exact overload matching in the separate `descriptor` field.
|
|
149
|
-
-
|
|
150
|
-
- `analyze-mod` and `validate-project`
|
|
158
|
+
- 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
|
+
- `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. When no version can be resolved from the request or `gradle.properties`, the summary blocks with version-agnostic recovery guidance.
|
|
151
161
|
|
|
152
162
|
### Inspect Minecraft source from a version
|
|
153
163
|
|
|
@@ -216,7 +226,7 @@ Keep only the high-frequency notes here. For the full pitfall list, exact contra
|
|
|
216
226
|
"subject": {
|
|
217
227
|
"kind": "workspace",
|
|
218
228
|
"projectPath": "/workspace/modid",
|
|
219
|
-
"discover": ["mixins", "access-wideners"]
|
|
229
|
+
"discover": ["mixins", "access-wideners", "access-transformers"]
|
|
220
230
|
},
|
|
221
231
|
"preferProjectVersion": true,
|
|
222
232
|
"preferProjectMapping": true
|
|
@@ -224,10 +234,12 @@ Keep only the high-frequency notes here. For the full pitfall list, exact contra
|
|
|
224
234
|
}
|
|
225
235
|
```
|
|
226
236
|
|
|
237
|
+
Workspace summaries still default to discovering mixins and access wideners. Add `"access-transformers"` to `subject.discover` when you want Access Transformer files included in the summary run.
|
|
238
|
+
|
|
227
239
|
## Documentation
|
|
228
240
|
|
|
229
241
|
- [Detailed example requests](docs/examples.md) for copyable payloads and common workflows
|
|
230
|
-
- [Tool and configuration reference](docs/tool-reference.md) for exact inputs, outputs, resource behavior, environment variables, and migration notes
|
|
242
|
+
- [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
|
|
231
243
|
- [日本語 README](docs/README-ja.md) for a Japanese onboarding overview
|
|
232
244
|
|
|
233
245
|
## Tool Surface
|
|
@@ -243,7 +255,7 @@ Start with these top-level workflow tools unless you already know the exact spec
|
|
|
243
255
|
| `analyze-symbol` | Handle symbol existence checks, namespace mapping, lifecycle tracing, workspace symbol resolution, and API overviews |
|
|
244
256
|
| `compare-minecraft` | Compare version pairs, class diffs, registry diffs, and migration-oriented summaries |
|
|
245
257
|
| `analyze-mod` | Summarize mod metadata, decompile and search mod code, inspect class source, and preview or apply remaps |
|
|
246
|
-
| `validate-project` | Summarize workspaces and run direct Mixin or Access
|
|
258
|
+
| `validate-project` | Summarize workspaces and run direct Mixin, Access Widener, or Access Transformer validation |
|
|
247
259
|
| `manage-cache` | List, verify, and preview or apply cache cleanup and rebuild operations |
|
|
248
260
|
<!-- END GENERATED TOOL TABLE: v3-entry-tools -->
|
|
249
261
|
|
|
@@ -265,6 +277,8 @@ Tools for browsing Minecraft versions, resolving source artifacts, and reading o
|
|
|
265
277
|
| `index-artifact` | Rebuild indexed metadata for an existing artifact |
|
|
266
278
|
<!-- END GENERATED TOOL TABLE: source-exploration -->
|
|
267
279
|
|
|
280
|
+
For unobfuscated releases such as `26.1+`, `mapping="mojang"` uses the runtime/decompile path directly and skips Loom source-jar discovery, while `intermediary` and `yarn` fall back to `obfuscated` with a warning.
|
|
281
|
+
|
|
268
282
|
### Version Comparison & Symbol Tracking
|
|
269
283
|
|
|
270
284
|
Tools for comparing class and registry changes across Minecraft versions and tracing symbol existence over time.
|
|
@@ -291,6 +305,10 @@ Tools for converting symbol names between namespaces and checking symbol existen
|
|
|
291
305
|
| `check-symbol-exists` | Check whether a class, field, or method exists in a namespace |
|
|
292
306
|
<!-- END GENERATED TOOL TABLE: mapping-symbols -->
|
|
293
307
|
|
|
308
|
+
`resolve-artifact`, `find-mapping`, `resolve-method-mapping-exact`, `resolve-workspace-symbol`, and `check-symbol-exists` default `compact` to `true`: empty fields are stripped, `resolve-artifact` omits diagnostic fields (`provenance`, `artifactContents`, etc.), and mapping tools omit the redundant `candidates` array on full-confidence exact matches and slim the tail to `{kind, symbol, owner, name, descriptor, confidence, matchKind}` (signalled by `candidateDetailsTruncated`) for unresolved results with more than three candidates. Pass `compact: false` for the full diagnostic shape.
|
|
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
|
+
|
|
294
312
|
### NBT Utilities
|
|
295
313
|
|
|
296
314
|
Tools for decoding, patching, and encoding Java Edition NBT binary data using a typed JSON representation.
|
|
@@ -310,7 +328,7 @@ Tools for extracting metadata from mod JARs, decompiling mod source, searching m
|
|
|
310
328
|
<!-- BEGIN GENERATED TOOL TABLE: mod-analysis -->
|
|
311
329
|
| Tool | Purpose |
|
|
312
330
|
| --- | --- |
|
|
313
|
-
| `analyze-mod-jar` | Extract mod metadata, dependencies, entrypoints,
|
|
331
|
+
| `analyze-mod-jar` | Extract mod metadata, dependencies, entrypoints, mixin config info, and packaged access transformer paths from a JAR |
|
|
314
332
|
| `decompile-mod-jar` | Decompile a mod JAR and optionally return one class source |
|
|
315
333
|
| `get-mod-class-source` | Read one class source from the decompiled mod cache |
|
|
316
334
|
| `search-mod-source` | Search decompiled mod source by class, method, field, or content |
|
|
@@ -319,13 +337,14 @@ Tools for extracting metadata from mod JARs, decompiling mod source, searching m
|
|
|
319
337
|
|
|
320
338
|
### Validation
|
|
321
339
|
|
|
322
|
-
Tools for validating Mixin source and Access
|
|
340
|
+
Tools for validating Mixin source, Access Widener files, and Forge/NeoForge Access Transformer files against a target Minecraft version. `validate-access-widener` defaults to vanilla bytecode validation; pass `projectPath`, `scope`, and `preferProjectVersion` for runtime-aware mode, which returns runtime `provenance` plus per-entry `resolvedRuntimeAccess` evidence. `validate-access-transformer` infers `atNamespace` from Forge/NeoForge workspace context when `projectPath` is provided and uses loader runtime artifacts for `scope="loader"`.
|
|
323
341
|
|
|
324
342
|
<!-- BEGIN GENERATED TOOL TABLE: validation -->
|
|
325
343
|
| Tool | Purpose |
|
|
326
344
|
| --- | --- |
|
|
327
345
|
| `validate-mixin` | Validate Mixin source against a target Minecraft version |
|
|
328
|
-
| `validate-access-widener` | Validate Access Widener content against a target Minecraft version |
|
|
346
|
+
| `validate-access-widener` | Validate Access Widener content against a target Minecraft version, optionally using runtime-aware Loom artifacts |
|
|
347
|
+
| `validate-access-transformer` | Validate Access Transformer content against a target Minecraft version, optionally using Forge/NeoForge runtime artifacts |
|
|
329
348
|
<!-- END GENERATED TOOL TABLE: validation -->
|
|
330
349
|
|
|
331
350
|
### Registry & Diagnostics
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type AccessTransformerAccessAction = "public" | "protected" | "package-private" | "private";
|
|
2
|
+
export type AccessTransformerFinalAction = "add" | "remove";
|
|
3
|
+
export type AccessTransformerEntry = {
|
|
4
|
+
line: number;
|
|
5
|
+
targetKind: "class" | "field" | "method";
|
|
6
|
+
owner: string;
|
|
7
|
+
target: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
descriptor?: string;
|
|
10
|
+
accessAction: AccessTransformerAccessAction;
|
|
11
|
+
finalAction?: AccessTransformerFinalAction;
|
|
12
|
+
};
|
|
13
|
+
export type ParsedAccessTransformer = {
|
|
14
|
+
entries: AccessTransformerEntry[];
|
|
15
|
+
parseWarnings: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function parseAccessTransformer(content: string): ParsedAccessTransformer;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
function parseAccessDeclaration(raw) {
|
|
2
|
+
const match = raw.match(/^(public|protected|default|private)([+-]f)?$/i);
|
|
3
|
+
if (!match) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const finalModifier = match[2]?.toLowerCase();
|
|
7
|
+
return {
|
|
8
|
+
accessAction: match[1]?.toLowerCase() === "default"
|
|
9
|
+
? "package-private"
|
|
10
|
+
: match[1]?.toLowerCase(),
|
|
11
|
+
...(finalModifier === "+f" ? { finalAction: "add" } : {}),
|
|
12
|
+
...(finalModifier === "-f" ? { finalAction: "remove" } : {})
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function splitMemberToken(tokens) {
|
|
16
|
+
if (tokens.length === 0) {
|
|
17
|
+
return { targetKind: "class" };
|
|
18
|
+
}
|
|
19
|
+
if (tokens.length === 1) {
|
|
20
|
+
const token = tokens[0] ?? "";
|
|
21
|
+
const descriptorStart = token.indexOf("(");
|
|
22
|
+
if (descriptorStart >= 0) {
|
|
23
|
+
return {
|
|
24
|
+
targetKind: "method",
|
|
25
|
+
name: token.slice(0, descriptorStart),
|
|
26
|
+
descriptor: token.slice(descriptorStart)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
targetKind: "field",
|
|
31
|
+
name: token
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
targetKind: "method",
|
|
36
|
+
name: tokens[0],
|
|
37
|
+
descriptor: tokens.slice(1).join("")
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function parseAccessTransformer(content) {
|
|
41
|
+
const entries = [];
|
|
42
|
+
const parseWarnings = [];
|
|
43
|
+
const lines = content.split(/\r?\n/);
|
|
44
|
+
for (let index = 0; index < lines.length; index++) {
|
|
45
|
+
const lineNumber = index + 1;
|
|
46
|
+
const rawLine = (lines[index] ?? "").trim();
|
|
47
|
+
if (!rawLine || rawLine.startsWith("#")) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const withoutComment = rawLine.replace(/\s+#.*$/, "").trim();
|
|
51
|
+
if (!withoutComment) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const parts = withoutComment.split(/\s+/);
|
|
55
|
+
if (parts.length < 2) {
|
|
56
|
+
parseWarnings.push(`Line ${lineNumber}: Incomplete access transformer entry "${withoutComment}".`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const declaration = parseAccessDeclaration(parts[0] ?? "");
|
|
60
|
+
if (!declaration) {
|
|
61
|
+
parseWarnings.push(`Line ${lineNumber}: Unsupported access declaration "${parts[0]}".`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const owner = parts[1] ?? "";
|
|
65
|
+
if (!owner) {
|
|
66
|
+
parseWarnings.push(`Line ${lineNumber}: Incomplete access transformer entry "${withoutComment}".`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const member = splitMemberToken(parts.slice(2));
|
|
70
|
+
if (member.targetKind === "method" && (!member.name || !member.descriptor)) {
|
|
71
|
+
parseWarnings.push(`Line ${lineNumber}: Method entry requires a method name and JVM descriptor.`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if ((member.targetKind === "field" || member.targetKind === "method") && !member.name) {
|
|
75
|
+
parseWarnings.push(`Line ${lineNumber}: Member entry requires a target name.`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const target = member.targetKind === "class"
|
|
79
|
+
? owner
|
|
80
|
+
: `${owner}#${member.name}${member.descriptor ?? ""}`;
|
|
81
|
+
entries.push({
|
|
82
|
+
line: lineNumber,
|
|
83
|
+
owner,
|
|
84
|
+
target,
|
|
85
|
+
targetKind: member.targetKind,
|
|
86
|
+
...(member.name ? { name: member.name } : {}),
|
|
87
|
+
...(member.descriptor ? { descriptor: member.descriptor } : {}),
|
|
88
|
+
accessAction: declaration.accessAction,
|
|
89
|
+
...(declaration.finalAction ? { finalAction: declaration.finalAction } : {})
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
entries,
|
|
94
|
+
parseWarnings
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=access-transformer-parser.js.map
|
package/dist/cache-registry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PathRuntimeInfo } from "./path-converter.js";
|
|
2
|
-
export declare const PUBLIC_CACHE_KINDS: readonly ["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap"];
|
|
2
|
+
export declare const PUBLIC_CACHE_KINDS: readonly ["artifact-index", "downloads", "mapping", "registry", "decompiled-source", "mod-remap", "binary-remap"];
|
|
3
3
|
export type PublicCacheKind = (typeof PUBLIC_CACHE_KINDS)[number];
|
|
4
4
|
export declare const CACHE_HEALTH_STATES: readonly ["healthy", "partial", "stale", "orphaned", "corrupt", "in_use"];
|
|
5
5
|
export type CacheHealthState = (typeof CACHE_HEALTH_STATES)[number];
|
package/dist/cache-registry.js
CHANGED
|
@@ -10,7 +10,8 @@ export const PUBLIC_CACHE_KINDS = [
|
|
|
10
10
|
"mapping",
|
|
11
11
|
"registry",
|
|
12
12
|
"decompiled-source",
|
|
13
|
-
"mod-remap"
|
|
13
|
+
"mod-remap",
|
|
14
|
+
"binary-remap"
|
|
14
15
|
];
|
|
15
16
|
export const CACHE_HEALTH_STATES = [
|
|
16
17
|
"healthy",
|
|
@@ -37,6 +38,8 @@ function kindRoot(config, cacheKind) {
|
|
|
37
38
|
return join(config.cacheDir, "decompiled");
|
|
38
39
|
case "mod-remap":
|
|
39
40
|
return join(config.cacheDir, "remapped-mods");
|
|
41
|
+
case "binary-remap":
|
|
42
|
+
return join(config.cacheDir, "remapped");
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
async function listFilesRecursive(root) {
|
|
@@ -439,7 +442,12 @@ async function fileBackedEntries(config, cacheKind) {
|
|
|
439
442
|
inUse: filePath.endsWith(".lock") ||
|
|
440
443
|
filePath.endsWith(".wal") ||
|
|
441
444
|
filePath.endsWith(".journal"),
|
|
442
|
-
...(cacheKind === "downloads" || cacheKind === "mod-remap"
|
|
445
|
+
...(cacheKind === "downloads" || cacheKind === "mod-remap" || cacheKind === "binary-remap"
|
|
446
|
+
? { jarPath: filePath }
|
|
447
|
+
: {}),
|
|
448
|
+
...(cacheKind === "binary-remap"
|
|
449
|
+
? { artifactId: normalizedEntryId.replace(/\.jar$/i, "") }
|
|
450
|
+
: {})
|
|
443
451
|
}
|
|
444
452
|
});
|
|
445
453
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function mapWithConcurrencyLimit<T, R>(items: readonly T[], limit: number, mapper: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export async function mapWithConcurrencyLimit(items, limit, mapper) {
|
|
2
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
3
|
+
throw new Error("limit must be a positive integer");
|
|
4
|
+
}
|
|
5
|
+
if (items.length === 0) {
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
const results = new Array(items.length);
|
|
9
|
+
let nextIndex = 0;
|
|
10
|
+
const workerCount = Math.min(limit, items.length);
|
|
11
|
+
const worker = async () => {
|
|
12
|
+
while (true) {
|
|
13
|
+
const currentIndex = nextIndex;
|
|
14
|
+
nextIndex += 1;
|
|
15
|
+
if (currentIndex >= items.length) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
results[currentIndex] = await mapper(items[currentIndex], currentIndex);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
await Promise.all(Array.from({ length: workerCount }, async () => worker()));
|
|
22
|
+
return results;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=concurrency.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Config } from "./types.js";
|
|
1
|
+
import type { ArtifactTargetKind, Config, MappingVariant } from "./types.js";
|
|
2
2
|
declare const DEFAULTS: {
|
|
3
3
|
readonly cacheDir: "~/.cache/minecraft-modding-mcp";
|
|
4
4
|
readonly sourceRepos: readonly ["https://repo1.maven.org/maven2", "https://maven.fabricmc.net", "https://maven.minecraftforge.net", "https://maven.neoforged.net/releases"];
|
|
@@ -24,4 +24,13 @@ declare const DEFAULTS: {
|
|
|
24
24
|
};
|
|
25
25
|
export declare function loadConfig(): Config;
|
|
26
26
|
export declare function stableArtifactId(parts: string[]): string;
|
|
27
|
+
export interface ArtifactAliasInput {
|
|
28
|
+
artifactId: string;
|
|
29
|
+
kind: ArtifactTargetKind;
|
|
30
|
+
value: string;
|
|
31
|
+
mappingVariant?: MappingVariant;
|
|
32
|
+
resolvedVersion?: string;
|
|
33
|
+
coordinate?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function buildArtifactAlias(input: ArtifactAliasInput): string;
|
|
27
36
|
export { DEFAULTS };
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { basename, isAbsolute, resolve } from "node:path";
|
|
4
4
|
import { normalizePathForHost } from "./path-converter.js";
|
|
5
5
|
const DEFAULTS = {
|
|
6
6
|
cacheDir: "~/.cache/minecraft-modding-mcp",
|
|
@@ -182,5 +182,56 @@ export function stableArtifactId(parts) {
|
|
|
182
182
|
.join("|");
|
|
183
183
|
return createHash("sha256").update(normalizer).digest("hex");
|
|
184
184
|
}
|
|
185
|
+
// 12 hex chars (48 bits) of artifactId entropy keeps alias collisions astronomically
|
|
186
|
+
// unlikely while staying short enough to copy/paste. A shorter prefix would let two
|
|
187
|
+
// distinct artifacts whose readable tokens (kind, version, mapping, scope, variant)
|
|
188
|
+
// happen to match share an alias and trip the schema-v4 UNIQUE constraint.
|
|
189
|
+
const ARTIFACT_ALIAS_HASH_LEN = 12;
|
|
190
|
+
function slugifyAliasPart(value) {
|
|
191
|
+
return value
|
|
192
|
+
.toLowerCase()
|
|
193
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
194
|
+
.replace(/^-+|-+$/g, "");
|
|
195
|
+
}
|
|
196
|
+
function aliasJarBase(jarPath) {
|
|
197
|
+
const base = basename(jarPath);
|
|
198
|
+
return base.toLowerCase().endsWith(".jar") ? base.slice(0, -4) : base;
|
|
199
|
+
}
|
|
200
|
+
// Generates a deterministic, human-readable alias canonical to the artifact row.
|
|
201
|
+
// The alias is 1:1 with `artifactId`: only dimensions baked into `artifactId`
|
|
202
|
+
// itself (kind, value/version/coordinate, mappingVariant) appear in the alias,
|
|
203
|
+
// plus a 12-hex-char (48-bit) suffix taken from `artifactId`. Request-level
|
|
204
|
+
// dimensions like `mapping` and `scope` are intentionally excluded — including
|
|
205
|
+
// them would make resolveArtifact rotate the alias for the same row whenever
|
|
206
|
+
// a caller passed a different mapping/scope, breaking aliases already returned
|
|
207
|
+
// to earlier callers. Two distinct artifactIds whose readable tokens collide and
|
|
208
|
+
// whose first 48 hash bits also collide would trip the schema-v4 alias UNIQUE
|
|
209
|
+
// constraint at upsert time — a hard error, not silent drift.
|
|
210
|
+
// Phase 3.1a: display-only. Phase 3.1b stores it for lookup.
|
|
211
|
+
export function buildArtifactAlias(input) {
|
|
212
|
+
const tokens = [];
|
|
213
|
+
if (input.kind === "version") {
|
|
214
|
+
tokens.push("mc", input.resolvedVersion ?? input.value);
|
|
215
|
+
}
|
|
216
|
+
else if (input.kind === "coordinate") {
|
|
217
|
+
tokens.push("coord", input.coordinate ?? input.value);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
tokens.push("jar", aliasJarBase(input.value));
|
|
221
|
+
}
|
|
222
|
+
// mappingVariant is canonical — `artifactIdForJar` / `artifactIdForCoordinate`
|
|
223
|
+
// bake "mojang-remapped" into the artifactId, so the same artifactId always
|
|
224
|
+
// produces the same alias regardless of how many times resolveArtifact is
|
|
225
|
+
// called. The token here is purely a human-readable hint; the 12-char hash
|
|
226
|
+
// suffix would already separate remapped artifacts from pass-through ones.
|
|
227
|
+
if (input.mappingVariant === "mojang-remapped") {
|
|
228
|
+
tokens.push("remapped");
|
|
229
|
+
}
|
|
230
|
+
tokens.push(input.artifactId.slice(0, ARTIFACT_ALIAS_HASH_LEN));
|
|
231
|
+
return tokens
|
|
232
|
+
.map(slugifyAliasPart)
|
|
233
|
+
.filter(Boolean)
|
|
234
|
+
.join("-");
|
|
235
|
+
}
|
|
185
236
|
export { DEFAULTS };
|
|
186
237
|
//# sourceMappingURL=config.js.map
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { access, constants } from "node:fs/promises";
|
|
2
|
-
import { mkdirSync,
|
|
1
|
+
import { access, constants, mkdir, readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { basename, join, relative, sep } from "node:path";
|
|
5
|
+
import { mapWithConcurrencyLimit } from "../concurrency.js";
|
|
5
6
|
import { createError, ERROR_CODES, isAppError } from "../errors.js";
|
|
6
7
|
import { assertJavaAvailable, runJavaProcess } from "../java-process.js";
|
|
7
8
|
import { log } from "../logger.js";
|
|
8
9
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
10
|
+
const DECOMPILED_JAVA_READ_CONCURRENCY = 8;
|
|
9
11
|
const VINEFLOWER_FLAG_PROFILES = [
|
|
10
12
|
{ label: "default", flags: ["-din=1", "-rbr=1", "-dgs=1"] },
|
|
11
13
|
{ label: "relaxed", flags: ["-din=1", "-rbr=0", "-dgs=0"] },
|
|
@@ -47,14 +49,14 @@ async function assertVineflowerAvailable(vineflowerJarPath) {
|
|
|
47
49
|
});
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
function
|
|
52
|
+
async function collectJavaFilesRecursive(baseDir, currentDir = "") {
|
|
51
53
|
const absoluteBase = currentDir ? join(baseDir, currentDir) : baseDir;
|
|
52
|
-
const entries =
|
|
54
|
+
const entries = await readdir(absoluteBase, { withFileTypes: true });
|
|
53
55
|
const result = [];
|
|
54
56
|
for (const entry of entries) {
|
|
55
57
|
const next = currentDir ? join(currentDir, entry.name) : entry.name;
|
|
56
58
|
if (entry.isDirectory()) {
|
|
57
|
-
result.push(...
|
|
59
|
+
result.push(...await collectJavaFilesRecursive(baseDir, next));
|
|
58
60
|
continue;
|
|
59
61
|
}
|
|
60
62
|
if (entry.isFile() && entry.name.endsWith(".java")) {
|
|
@@ -66,23 +68,21 @@ function collectJavaFilesSync(baseDir, currentDir = "") {
|
|
|
66
68
|
async function collectJavaFiles(baseDir) {
|
|
67
69
|
try {
|
|
68
70
|
const fastGlobModule = (await import("fast-glob"));
|
|
69
|
-
const
|
|
70
|
-
if (typeof
|
|
71
|
-
return
|
|
71
|
+
const glob = fastGlobModule.default?.glob;
|
|
72
|
+
if (typeof glob === "function") {
|
|
73
|
+
return (await glob("**/*.java", { cwd: baseDir, onlyFiles: true }))
|
|
74
|
+
.sort((left, right) => left.localeCompare(right));
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
catch {
|
|
75
78
|
// optional dependency: fallback to recursive traversal
|
|
76
79
|
}
|
|
77
|
-
return
|
|
80
|
+
return (await collectJavaFilesRecursive(baseDir))
|
|
81
|
+
.map((candidate) => candidate.split(sep).join("/"))
|
|
82
|
+
.sort((left, right) => left.localeCompare(right));
|
|
78
83
|
}
|
|
79
84
|
function readFileTreeText(filePath) {
|
|
80
|
-
return
|
|
81
|
-
import("node:fs/promises")
|
|
82
|
-
.then((fs) => fs.readFile(filePath, "utf8"))
|
|
83
|
-
.then(resolve)
|
|
84
|
-
.catch(reject);
|
|
85
|
-
});
|
|
85
|
+
return readFile(filePath, "utf8");
|
|
86
86
|
}
|
|
87
87
|
function decompileOutputDir(cacheDir, binaryJarPath, signature) {
|
|
88
88
|
const digest = createHash("sha256").update(binaryJarPath).update(signature).digest("hex");
|
|
@@ -130,17 +130,18 @@ export async function decompileBinaryJar(binaryJarPath, cacheDir, options) {
|
|
|
130
130
|
const signature = options.signature ?? basename(normalizedBinaryJarPath);
|
|
131
131
|
const outputDir = decompileOutputDir(cacheDir, normalizedBinaryJarPath, signature).replace(/[/\\]$/, "");
|
|
132
132
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
await mkdir(outputDir, { recursive: true });
|
|
134
|
+
const outputDirStats = await stat(outputDir).catch(() => undefined);
|
|
135
|
+
if (outputDirStats) {
|
|
135
136
|
const existingJavaFiles = await collectJavaFiles(outputDir);
|
|
136
137
|
if (existingJavaFiles.length > 0) {
|
|
137
|
-
const results = await
|
|
138
|
+
const results = await mapWithConcurrencyLimit(existingJavaFiles, DECOMPILED_JAVA_READ_CONCURRENCY, async (candidate) => {
|
|
138
139
|
const abs = join(outputDir, candidate);
|
|
139
140
|
return {
|
|
140
141
|
filePath: normalizeOutputPath(outputDir, abs),
|
|
141
142
|
content: await readFileTreeText(abs)
|
|
142
143
|
};
|
|
143
|
-
})
|
|
144
|
+
});
|
|
144
145
|
emitDecompileLog("decompile.done", {
|
|
145
146
|
durationMs: Date.now() - startedAt,
|
|
146
147
|
artifactIdCandidate: options.artifactIdCandidate,
|
|
@@ -181,13 +182,13 @@ export async function decompileBinaryJar(binaryJarPath, cacheDir, options) {
|
|
|
181
182
|
}
|
|
182
183
|
});
|
|
183
184
|
}
|
|
184
|
-
const javaFiles = await
|
|
185
|
+
const javaFiles = await mapWithConcurrencyLimit(javaFileNames, DECOMPILED_JAVA_READ_CONCURRENCY, async (candidate) => {
|
|
185
186
|
const abs = join(outputDir, candidate);
|
|
186
187
|
return {
|
|
187
188
|
filePath: normalizeOutputPath(outputDir, abs),
|
|
188
189
|
content: await readFileTreeText(abs)
|
|
189
190
|
};
|
|
190
|
-
})
|
|
191
|
+
});
|
|
191
192
|
emitDecompileLog("decompile.done", {
|
|
192
193
|
durationMs: Date.now() - startedAt,
|
|
193
194
|
artifactIdCandidate: options.artifactIdCandidate,
|
|
@@ -75,7 +75,7 @@ export declare const analyzeModSchema: z.ZodEffects<z.ZodObject<{
|
|
|
75
75
|
include: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
|
|
76
76
|
}, "strip", z.ZodTypeAny, {
|
|
77
77
|
limit: number;
|
|
78
|
-
searchType: "class" | "
|
|
78
|
+
searchType: "class" | "field" | "method" | "all" | "content";
|
|
79
79
|
task: "search" | "remap" | "summary" | "class-source" | "decompile";
|
|
80
80
|
subject: {
|
|
81
81
|
kind: "jar";
|
|
@@ -111,7 +111,7 @@ export declare const analyzeModSchema: z.ZodEffects<z.ZodObject<{
|
|
|
111
111
|
targetMapping?: "mojang" | "yarn" | undefined;
|
|
112
112
|
outputJar?: string | undefined;
|
|
113
113
|
query?: string | undefined;
|
|
114
|
-
searchType?: "class" | "
|
|
114
|
+
searchType?: "class" | "field" | "method" | "all" | "content" | undefined;
|
|
115
115
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
116
116
|
include?: string[] | undefined;
|
|
117
117
|
includeFiles?: boolean | undefined;
|
|
@@ -119,7 +119,7 @@ export declare const analyzeModSchema: z.ZodEffects<z.ZodObject<{
|
|
|
119
119
|
executionMode?: "preview" | "apply" | undefined;
|
|
120
120
|
}>, {
|
|
121
121
|
limit: number;
|
|
122
|
-
searchType: "class" | "
|
|
122
|
+
searchType: "class" | "field" | "method" | "all" | "content";
|
|
123
123
|
task: "search" | "remap" | "summary" | "class-source" | "decompile";
|
|
124
124
|
subject: {
|
|
125
125
|
kind: "jar";
|
|
@@ -155,7 +155,7 @@ export declare const analyzeModSchema: z.ZodEffects<z.ZodObject<{
|
|
|
155
155
|
targetMapping?: "mojang" | "yarn" | undefined;
|
|
156
156
|
outputJar?: string | undefined;
|
|
157
157
|
query?: string | undefined;
|
|
158
|
-
searchType?: "class" | "
|
|
158
|
+
searchType?: "class" | "field" | "method" | "all" | "content" | undefined;
|
|
159
159
|
detail?: "full" | "summary" | "standard" | undefined;
|
|
160
160
|
include?: string[] | undefined;
|
|
161
161
|
includeFiles?: boolean | undefined;
|