mcdev-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +77 -0
  2. package/README.md +365 -0
  3. package/dist/callgraph/index.d.ts +14 -0
  4. package/dist/callgraph/index.d.ts.map +1 -0
  5. package/dist/callgraph/index.js +201 -0
  6. package/dist/callgraph/index.js.map +1 -0
  7. package/dist/callgraph/query.d.ts +20 -0
  8. package/dist/callgraph/query.d.ts.map +1 -0
  9. package/dist/callgraph/query.js +95 -0
  10. package/dist/callgraph/query.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +318 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/decompiler/download.d.ts +31 -0
  16. package/dist/decompiler/download.d.ts.map +1 -0
  17. package/dist/decompiler/download.js +145 -0
  18. package/dist/decompiler/download.js.map +1 -0
  19. package/dist/decompiler/downloader.d.ts +7 -0
  20. package/dist/decompiler/downloader.d.ts.map +1 -0
  21. package/dist/decompiler/downloader.js +4 -0
  22. package/dist/decompiler/downloader.js.map +1 -0
  23. package/dist/decompiler/index.d.ts +16 -0
  24. package/dist/decompiler/index.d.ts.map +1 -0
  25. package/dist/decompiler/index.js +74 -0
  26. package/dist/decompiler/index.js.map +1 -0
  27. package/dist/decompiler/remapper.d.ts +9 -0
  28. package/dist/decompiler/remapper.d.ts.map +1 -0
  29. package/dist/decompiler/remapper.js +174 -0
  30. package/dist/decompiler/remapper.js.map +1 -0
  31. package/dist/decompiler/tools.d.ts +3 -0
  32. package/dist/decompiler/tools.d.ts.map +1 -0
  33. package/dist/decompiler/tools.js +79 -0
  34. package/dist/decompiler/tools.js.map +1 -0
  35. package/dist/decompiler/vineflower.d.ts +3 -0
  36. package/dist/decompiler/vineflower.d.ts.map +1 -0
  37. package/dist/decompiler/vineflower.js +37 -0
  38. package/dist/decompiler/vineflower.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +63 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/indexer/index.d.ts +17 -0
  44. package/dist/indexer/index.d.ts.map +1 -0
  45. package/dist/indexer/index.js +134 -0
  46. package/dist/indexer/index.js.map +1 -0
  47. package/dist/indexer/parser.d.ts +11 -0
  48. package/dist/indexer/parser.d.ts.map +1 -0
  49. package/dist/indexer/parser.js +188 -0
  50. package/dist/indexer/parser.js.map +1 -0
  51. package/dist/indexer/types.d.ts +14 -0
  52. package/dist/indexer/types.d.ts.map +1 -0
  53. package/dist/indexer/types.js +2 -0
  54. package/dist/indexer/types.js.map +1 -0
  55. package/dist/storage/index.d.ts +2 -0
  56. package/dist/storage/index.d.ts.map +1 -0
  57. package/dist/storage/index.js +2 -0
  58. package/dist/storage/index.js.map +1 -0
  59. package/dist/storage/source-store.d.ts +43 -0
  60. package/dist/storage/source-store.d.ts.map +1 -0
  61. package/dist/storage/source-store.js +279 -0
  62. package/dist/storage/source-store.js.map +1 -0
  63. package/dist/tools/index.d.ts +503 -0
  64. package/dist/tools/index.d.ts.map +1 -0
  65. package/dist/tools/index.js +535 -0
  66. package/dist/tools/index.js.map +1 -0
  67. package/dist/utils/config.d.ts +13 -0
  68. package/dist/utils/config.d.ts.map +1 -0
  69. package/dist/utils/config.js +12 -0
  70. package/dist/utils/config.js.map +1 -0
  71. package/dist/utils/paths.d.ts +30 -0
  72. package/dist/utils/paths.d.ts.map +1 -0
  73. package/dist/utils/paths.js +131 -0
  74. package/dist/utils/paths.js.map +1 -0
  75. package/dist/utils/types.d.ts +79 -0
  76. package/dist/utils/types.d.ts.map +1 -0
  77. package/dist/utils/types.js +2 -0
  78. package/dist/utils/types.js.map +1 -0
  79. package/dist/utils/version-manifest.d.ts +10 -0
  80. package/dist/utils/version-manifest.d.ts.map +1 -0
  81. package/dist/utils/version-manifest.js +64 -0
  82. package/dist/utils/version-manifest.js.map +1 -0
  83. package/dist/version-manager.d.ts +11 -0
  84. package/dist/version-manager.d.ts.map +1 -0
  85. package/dist/version-manager.js +29 -0
  86. package/dist/version-manager.js.map +1 -0
  87. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,77 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 mcdev-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ --------------------------------------------------------------------------------
24
+
25
+ ## Third-Party Licenses
26
+
27
+ This project includes or uses third-party software under the following licenses:
28
+
29
+ ### DecompilerMC
30
+
31
+ The decompiler integration logic in `src/decompiler/` is adapted and translated from Python to TypeScript based on DecompilerMC's architecture.
32
+
33
+ Source: https://github.com/hube12/DecompilerMC
34
+
35
+ MIT License
36
+
37
+ Copyright (c) 2020 Neil
38
+
39
+ Permission is hereby granted, free of charge, to any person obtaining a copy
40
+ of this software and associated documentation files (the "Software"), to deal
41
+ in the Software without restriction, including without limitation the rights
42
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
+ copies of the Software, and to permit persons to whom the Software is
44
+ furnished to do so, subject to the following conditions:
45
+
46
+ The above copyright notice and this permission notice shall be included in all
47
+ copies or substantial portions of the Software.
48
+
49
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55
+ SOFTWARE.
56
+
57
+ ### Vineflower
58
+
59
+ This project uses Vineflower for decompiling Minecraft JAR files.
60
+
61
+ Source: https://github.com/Vineflower/vineflower
62
+
63
+ Apache License 2.0
64
+
65
+ Copyright (c) 2021-2023 Vineflower contributors
66
+
67
+ Licensed under the Apache License, Version 2.0 (the "License");
68
+ you may not use this file except in compliance with the License.
69
+ You may obtain a copy of the License at
70
+
71
+ http://www.apache.org/licenses/LICENSE-2.0
72
+
73
+ Unless required by applicable law or agreed to in writing, software
74
+ distributed under the License is distributed on an "AS IS" BASIS,
75
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
76
+ See the License for the specific language governing permissions and
77
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,365 @@
1
+ # mcdev-mcp
2
+
3
+ [![CI](https://github.com/weikengchen/mcdev-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/weikengchen/mcdev-mcp/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ An **MCP (Model Context Protocol) server** that empowers AI coding agents to work effectively with Minecraft mod development. Provides accurate, up-to-date access to decompiled Minecraft source code using official Mojang mappings.
7
+
8
+ ## Features
9
+
10
+ - **Decompiled Source Access** — Auto-downloads and decompiles Minecraft client using [Vineflower](https://github.com/Vineflower/vineflower)
11
+ - **Dev Snapshot Support** — Works with development snapshots (e.g., `26.1-snapshot-10`) that lack ProGuard mappings
12
+ - **Symbol Search** — Search for classes, methods, and fields by name
13
+ - **Source Retrieval** — Get full class source or individual methods with context
14
+ - **Package Exploration** — List all classes under a package path or discover available packages
15
+ - **Class Hierarchy** — Find subclasses and interface implementors
16
+ - **Call Graph Analysis** — Find method callers and callees across the entire codebase
17
+ - **Zero Configuration** — Auto-initializes on first use if sources are cached
18
+
19
+ ## Quick Start
20
+
21
+ > **Security note — `init` is intentionally terminal-only.** The MCP server only exposes read/query tools. Downloading and decompiling Minecraft sources must be triggered by you in the terminal; an AI agent connected to the server has no tool surface to trigger `init`, `rebuild`, `clean`, or `callgraph`.
22
+
23
+ ### 1. Initialize in your terminal
24
+
25
+ ```bash
26
+ # Download, decompile, and index Minecraft sources (~2-5 minutes)
27
+ npx mcdev-mcp init -v 1.21.11
28
+ ```
29
+
30
+ This command:
31
+ 1. Downloads the Minecraft client JAR
32
+ 2. Decompiles using Vineflower (pure Java, 8 threads)
33
+ 3. Builds the symbol index (classes, methods, fields, inheritance)
34
+ 4. Generates call graph for `mc_find_refs`
35
+
36
+ Data is stored under `~/.mcdev-mcp/`, so it persists across `npx` invocations.
37
+
38
+ ### 2. Add to your MCP client
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "mcdev": {
44
+ "command": "npx",
45
+ "args": ["-y", "mcdev-mcp", "serve"]
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ The `serve` subcommand starts the MCP server over stdio. Your MCP client (Claude Desktop, Cursor, etc.) launches it automatically — you never run `serve` directly.
52
+
53
+ ### Supported Versions
54
+
55
+ | Version Type | Example | Notes |
56
+ |--------------|---------|-------|
57
+ | Dev snapshots | `26.1-snapshot-10` | Already unobfuscated, no mappings needed |
58
+ | Release (>= 1.21.11) | `1.21.11` | Uses pre-unobfuscated JAR when available |
59
+ | Old versions | `< 1.21.11` | Not supported |
60
+
61
+ > **Note:** Minecraft is now using a new versioning scheme (26.x). Versions before 1.21.11 are not supported.
62
+
63
+ ### (Optional) Skip Call Graph
64
+
65
+ ```bash
66
+ # Skip callgraph generation if you don't need mc_find_refs
67
+ npx mcdev-mcp init -v 1.21.11 --skip-callgraph
68
+
69
+ # Generate callgraph later
70
+ npx mcdev-mcp callgraph -v 1.21.11
71
+ ```
72
+
73
+ ### Verify Installation
74
+
75
+ ```bash
76
+ npx mcdev-mcp status
77
+ ```
78
+
79
+ > **Note:** The `mc_set_version` tool must be called before using any other MCP tools. If the version isn't initialized, the AI will be instructed to ask you to run `init`.
80
+
81
+ ### Install from source (development)
82
+
83
+ ```bash
84
+ git clone https://github.com/weikengchen/mcdev-mcp.git
85
+ cd mcdev-mcp
86
+ npm install
87
+ npm run build
88
+
89
+ # Use the local build instead of npx
90
+ node dist/cli.js init -v 1.21.11
91
+ node dist/cli.js serve # stdio MCP server; MCP clients launch this
92
+ ```
93
+
94
+ > **Upgrading from an older version?** If you have a previous installation using DecompilerMC, run `npx mcdev-mcp clean --all` first to remove old cached data.
95
+
96
+ ## MCP Tools
97
+
98
+ ### Version Management
99
+
100
+ Before using any other tools, set the active Minecraft version:
101
+
102
+ ### `mc_set_version`
103
+ Set the active Minecraft version for this session. Must be called before other tools.
104
+
105
+ ```json
106
+ {
107
+ "version": "1.21.11"
108
+ }
109
+ ```
110
+
111
+ ### `mc_list_versions`
112
+ List all Minecraft versions that have been initialized.
113
+
114
+ ```json
115
+ {}
116
+ ```
117
+
118
+ ### Tool Requirements
119
+
120
+ | Tool | Requires `init` | Requires `callgraph` |
121
+ |------|-----------------|---------------------|
122
+ | `mc_set_version` | - | - |
123
+ | `mc_list_versions` | - | - |
124
+ | `mc_search` | ✓ | - |
125
+ | `mc_get_class` | ✓ | - |
126
+ | `mc_get_method` | ✓ | - |
127
+ | `mc_list_classes` | ✓ | - |
128
+ | `mc_list_packages` | ✓ | - |
129
+ | `mc_find_hierarchy` | ✓ | - |
130
+ | `mc_find_refs` | ✓ | ✓ |
131
+
132
+ ### `mc_search`
133
+ Search for Minecraft classes, methods, or fields by name pattern.
134
+
135
+ ```json
136
+ {
137
+ "query": "Minecraft",
138
+ "type": "class"
139
+ }
140
+ ```
141
+
142
+ ### `mc_get_class`
143
+ Get the full decompiled source code for a class.
144
+
145
+ ```json
146
+ {
147
+ "className": "net.minecraft.client.Minecraft"
148
+ }
149
+ ```
150
+
151
+ ### `mc_get_method`
152
+ Get source code for a specific method with context.
153
+
154
+ ```json
155
+ {
156
+ "className": "net.minecraft.client.Minecraft",
157
+ "methodName": "tick"
158
+ }
159
+ ```
160
+
161
+ ### `mc_find_refs`
162
+ Find who calls a method (callers) or what it calls (callees).
163
+
164
+ ```json
165
+ {
166
+ "className": "net.minecraft.client.MouseHandler",
167
+ "methodName": "setup",
168
+ "direction": "callers"
169
+ }
170
+ ```
171
+
172
+ | Direction | Description |
173
+ |-----------|-------------|
174
+ | `callers` | Find methods that call this method |
175
+ | `callees` | Find methods this method calls |
176
+
177
+ > **Note:** Requires callgraph to be generated (included in `init` by default).
178
+
179
+ ### `mc_list_classes`
180
+ List all classes under a specific package path (includes subpackages).
181
+
182
+ ```json
183
+ {
184
+ "packagePath": "net.minecraft.client.gui.screens"
185
+ }
186
+ ```
187
+
188
+ ### `mc_list_packages`
189
+ List all available packages. Optionally filter by namespace.
190
+
191
+ ```json
192
+ {
193
+ "namespace": "minecraft"
194
+ }
195
+ ```
196
+
197
+ | Namespace | Description |
198
+ |-----------|-------------|
199
+ | `minecraft` | Minecraft client classes |
200
+ | `fabric` | Fabric API classes (if indexed) |
201
+
202
+ ### `mc_find_hierarchy`
203
+ Find classes that extend or implement a given class or interface.
204
+
205
+ ```json
206
+ {
207
+ "className": "net.minecraft.world.entity.Entity",
208
+ "direction": "subclasses"
209
+ }
210
+ ```
211
+
212
+ | Direction | Description |
213
+ |-----------|-------------|
214
+ | `subclasses` | Classes that extend this class |
215
+ | `implementors` | Classes that implement this interface |
216
+
217
+ ## Requirements
218
+
219
+ | Dependency | Version | Purpose |
220
+ |------------|---------|---------|
221
+ | Node.js | 18+ | Runtime |
222
+ | Java | 8+ | Decompilation (Vineflower) & callgraph |
223
+ | ~2GB | disk | Decompiled sources + cache |
224
+
225
+ > **Note:** Java 17+ is recommended for the `callgraph` command due to Gradle compatibility.
226
+
227
+ ## CLI Commands
228
+
229
+ Invoke via `npx mcdev-mcp <command>` (or `node dist/cli.js <command>` from a source checkout).
230
+
231
+ | Command | Description |
232
+ |---------|-------------|
233
+ | `serve` | Start the MCP server over stdio (launched by MCP clients — not run by humans) |
234
+ | `init -v <version>` | Download, decompile, index Minecraft sources, and generate callgraph |
235
+ | `callgraph -v <version>` | Generate call graph for `mc_find_refs` |
236
+ | `status` | Show all initialized versions |
237
+ | `rebuild -v <version>` | Rebuild the symbol index from cached sources |
238
+ | `clean --all` | Clean all cached data |
239
+
240
+ ### Re-indexing
241
+
242
+ To re-index a version:
243
+
244
+ ```bash
245
+ # Clean existing data for a version
246
+ npx mcdev-mcp clean -v 1.21.11 --all
247
+
248
+ # Re-initialize
249
+ npx mcdev-mcp init -v 1.21.11
250
+ ```
251
+
252
+ ## Architecture
253
+
254
+ ```
255
+ mcdev-mcp/
256
+ ├── src/
257
+ │ ├── index.ts # MCP server entry point
258
+ │ ├── cli.ts # CLI commands
259
+ │ ├── tools/ # MCP tool implementations
260
+ │ ├── decompiler/ # Vineflower integration (pure TypeScript/Java)
261
+ │ ├── indexer/ # Symbol index builder
262
+ │ ├── callgraph/ # Call graph generation & queries
263
+ │ └── storage/ # Source & index storage
264
+ └── dist/ # Compiled output
265
+ ```
266
+
267
+ ### How It Works
268
+
269
+ ```
270
+ ┌─────────────────────────────────────────────────────────────┐
271
+ │ MCP Client (AI Agent) │
272
+ └─────────────────────────────────────────────────────────────┘
273
+
274
+
275
+ ┌─────────────────────────────────────────────────────────────┐
276
+ │ mcdev-mcp Server │
277
+ │ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
278
+ │ │ search │ │get_class │ │get_method│ │ find_refs │ │
279
+ │ └────┬────┘ └────┬─────┘ └────┬─────┘ └─────┬─────┘ │
280
+ │ ┌─────────────┐ ┌───────────────┐ ┌─────────────────┐ │
281
+ │ │list_classes │ │list_packages │ │ find_hierarchy │ │
282
+ │ └──────┬──────┘ └───────┬───────┘ └────────┬────────┘ │
283
+ │ └────────────────┼──────────────────┘ │
284
+ │ │ │
285
+ │ ┌──────────────────┴───────────────────┐ │
286
+ │ ▼ ▼ │
287
+ │ ┌──────────┐ ┌─────────────┐ │
288
+ │ │ Index │ │ Callgraph │ │
289
+ │ │ (JSON) │ │ (SQLite) │ │
290
+ │ └────┬─────┘ └──────┬──────┘ │
291
+ └───────┼────────────────────────────────────────┼────────────┘
292
+ ▼ ▼
293
+ ┌───────────────────┐ ┌─────────────────────┐
294
+ │ Decompiled Src │ │ java-callgraph2 │
295
+ │ (Vineflower) │ │ (static analysis) │
296
+ └───────────────────┘ └─────────────────────┘
297
+ ```
298
+
299
+ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for detailed design documentation.
300
+
301
+ ## Directory Structure
302
+
303
+ ```
304
+ ~/.mcdev-mcp/
305
+ ├── tools/
306
+ │ └── vineflower.jar # Downloaded once
307
+ ├── java-callgraph2/ # Call graph tool
308
+ ├── cache/
309
+ │ └── {version}/
310
+ │ ├── jars/ # Downloaded JARs
311
+ │ └── client/ # Decompiled Minecraft sources
312
+ ├── index/
313
+ │ └── {version}/
314
+ │ ├── manifest.json # Index metadata
315
+ │ └── minecraft/ # Per-package symbol indices
316
+ └── tmp/ # Temporary files (cleaned by --all)
317
+ ```
318
+
319
+ ## Development
320
+
321
+ ```bash
322
+ npm run build # Compile TypeScript
323
+ npm test # Run tests
324
+ npm run lint # Lint code
325
+ ```
326
+
327
+ ## Limitations
328
+
329
+ - **Static Analysis Only**: `mc_find_refs` cannot trace calls through reflection, JNI callbacks, or lambda/method references created dynamically
330
+ - **Client Only**: Server-side classes are not included
331
+
332
+ ## Legal Notice
333
+
334
+ This tool decompiles Minecraft source code for development reference purposes. Please respect Mojang's intellectual property:
335
+
336
+ **You MAY:**
337
+ - Decompile and study the code for understanding and learning
338
+ - Use the knowledge to develop mods that don't contain substantial Mojang code
339
+ - Reference class/method names for mod development
340
+
341
+ **You may NOT:**
342
+ - Distribute decompiled source code
343
+ - Distribute modified versions of Minecraft
344
+ - Use decompiled code commercially without permission
345
+
346
+ Per the [Minecraft EULA](https://www.minecraft.net/eula): *"You may not distribute any Modded Versions of our game or software"* and *"Mods are okay to distribute; hacked versions or Modded Versions of the game client or server software are not okay to distribute."*
347
+
348
+ This tool is for **reference only** — do not copy decompiled code directly into your projects.
349
+
350
+ ## Third-Party Components
351
+
352
+ This project includes or uses third-party software under the following licenses:
353
+
354
+ - **[DecompilerMC](https://github.com/hube12/DecompilerMC)** (MIT) — Decompiler logic adapted and translated from Python to TypeScript in `src/decompiler/`
355
+ - **[Vineflower](https://github.com/Vineflower/vineflower)** (Apache-2.0) — Java decompiler used for source generation
356
+ - **[java-callgraph2](https://github.com/Adrninistrator/java-callgraph2)** — Cloned at runtime for static call graph generation
357
+
358
+ Additional runtime dependencies (downloaded/used):
359
+ - **[Mojang](https://www.minecraft.net/)** — Official ProGuard mappings and Minecraft client JAR
360
+
361
+ See [LICENSE](LICENSE) for full license text and third-party attributions.
362
+
363
+ ## License
364
+
365
+ [MIT](LICENSE) — Copyright (c) 2025 mcdev-mcp contributors
@@ -0,0 +1,14 @@
1
+ export declare function getJavaCGDir(): string;
2
+ export declare function getJavaCGJarPath(): string;
3
+ export declare function getJavaCGLibDir(): string;
4
+ export declare function getDecompilerMCDir(): string;
5
+ export declare function getRemappedJarPath(version: string): string;
6
+ export type ProgressCallback = (stage: string, progress: number, message: string) => void;
7
+ export declare function ensureJavaCG(progressCb?: ProgressCallback): Promise<string>;
8
+ export declare function ensureRemappedJar(version: string, progressCb?: ProgressCallback): Promise<string>;
9
+ export declare function generateCallgraph(version: string, progressCb?: ProgressCallback): Promise<string>;
10
+ export declare function hasCallgraphDb(version: string): boolean;
11
+ export declare function parseCallgraphAndCreateDb(version: string, callgraphFile: string, progressCb?: ProgressCallback): number;
12
+ export declare function ensureCallgraph(version: string, progressCb?: ProgressCallback): Promise<void>;
13
+ export { openDb, closeDb, findCallers, findCallees, searchMethods, getCallgraphStats } from './query.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/callgraph/index.ts"],"names":[],"mappings":"AASA,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAGzC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1F,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDjF;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BvG;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BvG;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAqDvH;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAInG;AAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,201 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { spawn } from 'child_process';
4
+ import Database from 'better-sqlite3';
5
+ import { ensureDir, getHomeDir, getMinecraftJarPath } from '../utils/paths.js';
6
+ import { getCallgraphDir, getCallgraphDbPath } from './query.js';
7
+ const SPECIAL_SOURCE_VERSION = '1.11.4';
8
+ export function getJavaCGDir() {
9
+ return path.join(getHomeDir(), 'java-callgraph2');
10
+ }
11
+ export function getJavaCGJarPath() {
12
+ // gen_run_jar creates jar_output_dir/jar/run_javacg2.jar
13
+ return path.join(getJavaCGDir(), 'jar_output_dir', 'jar', 'run_javacg2.jar');
14
+ }
15
+ export function getJavaCGLibDir() {
16
+ return path.join(getJavaCGDir(), 'jar_output_dir', 'lib');
17
+ }
18
+ export function getDecompilerMCDir() {
19
+ return path.join(getHomeDir(), 'DecompilerMC');
20
+ }
21
+ export function getRemappedJarPath(version) {
22
+ return path.join(getCallgraphDir(version), 'client-remapped.jar');
23
+ }
24
+ export async function ensureJavaCG(progressCb) {
25
+ const jarPath = getJavaCGJarPath();
26
+ if (fs.existsSync(jarPath))
27
+ return jarPath;
28
+ const jcDir = getJavaCGDir();
29
+ const gradlewPath = path.join(jcDir, 'gradlew');
30
+ const gradlewBatPath = path.join(jcDir, 'gradlew.bat');
31
+ const isWindows = process.platform === 'win32';
32
+ const gradlewCmd = isWindows ? 'gradlew.bat' : 'gradlew';
33
+ const gradlewExists = isWindows ? fs.existsSync(gradlewBatPath) : fs.existsSync(gradlewPath);
34
+ if (progressCb)
35
+ progressCb('javacg', 0, 'Cloning java-callgraph2...');
36
+ // Clone if gradlew doesn't exist (covers incomplete/corrupted clones)
37
+ if (!gradlewExists) {
38
+ if (fs.existsSync(jcDir)) {
39
+ fs.rmSync(jcDir, { recursive: true, force: true });
40
+ }
41
+ await new Promise((resolve, reject) => {
42
+ const proc = spawn('git', ['clone', 'https://github.com/Adrninistrator/java-callgraph2.git', jcDir], { stdio: 'inherit' });
43
+ proc.on('error', (err) => reject(new Error(`git clone failed: ${err.message}`)));
44
+ proc.on('close', (code) => code === 0 ? resolve() : reject(new Error(`git clone failed: ${code}`)));
45
+ });
46
+ }
47
+ // Update gradle wrapper to Gradle 9.3.1 (supports Java 25)
48
+ const gradleWrapperProps = path.join(jcDir, 'gradle', 'wrapper', 'gradle-wrapper.properties');
49
+ if (fs.existsSync(gradleWrapperProps)) {
50
+ fs.writeFileSync(gradleWrapperProps, 'distributionUrl=https\\://services.gradle.org/distributions/gradle-9.3.1-bin.zip\n');
51
+ }
52
+ // Make gradlew executable (Unix only)
53
+ if (!isWindows && fs.existsSync(gradlewPath)) {
54
+ fs.chmodSync(gradlewPath, 0o755);
55
+ }
56
+ // Patch build.gradle for Gradle 9.x compatibility (remove deprecated properties)
57
+ const buildGradlePath = path.join(jcDir, 'build.gradle');
58
+ if (fs.existsSync(buildGradlePath)) {
59
+ let buildGradle = fs.readFileSync(buildGradlePath, 'utf-8');
60
+ buildGradle = buildGradle.replace(/sourceCompatibility\s*=\s*1\.8\s*\n?/g, '');
61
+ buildGradle = buildGradle.replace(/targetCompatibility\s*=\s*1\.8\s*\n?/g, '');
62
+ fs.writeFileSync(buildGradlePath, buildGradle);
63
+ }
64
+ if (progressCb)
65
+ progressCb('javacg', 50, 'Building java-callgraph2 with Gradle 9.3...');
66
+ // Use gen_run_jar task instead of shadowJar (creates run_javacg2.jar with lib/ folder)
67
+ await new Promise((resolve, reject) => {
68
+ const proc = spawn(gradlewCmd, ['gen_run_jar'], { cwd: jcDir, stdio: 'inherit', shell: isWindows });
69
+ proc.on('error', (err) => reject(new Error(`gradle build failed: ${err.message}`)));
70
+ proc.on('close', (code) => code === 0 ? resolve() : reject(new Error(`gradle build failed: ${code}`)));
71
+ });
72
+ if (progressCb)
73
+ progressCb('javacg', 100, 'java-callgraph2 ready.');
74
+ return jarPath;
75
+ }
76
+ export async function ensureRemappedJar(version, progressCb) {
77
+ const remappedJar = getRemappedJarPath(version);
78
+ if (fs.existsSync(remappedJar))
79
+ return remappedJar;
80
+ const clientJar = getMinecraftJarPath(version);
81
+ const dmcdDir = getDecompilerMCDir();
82
+ const tsrgMappings = path.join(dmcdDir, 'mappings', version, 'client.tsrg');
83
+ const specialSource = path.join(dmcdDir, 'lib', `SpecialSource-${SPECIAL_SOURCE_VERSION}.jar`);
84
+ // For dev snapshots (no mappings), use client.jar directly
85
+ if (!fs.existsSync(tsrgMappings)) {
86
+ if (progressCb)
87
+ progressCb('remap', 0, 'No mappings found, using unobfuscated jar directly...');
88
+ ensureDir(path.dirname(remappedJar));
89
+ fs.copyFileSync(clientJar, remappedJar);
90
+ if (progressCb)
91
+ progressCb('remap', 100, 'Jar ready (no remapping needed).');
92
+ return remappedJar;
93
+ }
94
+ if (progressCb)
95
+ progressCb('remap', 0, 'Creating remapped jar...');
96
+ ensureDir(path.dirname(remappedJar));
97
+ return new Promise((resolve, reject) => {
98
+ const proc = spawn('java', ['-Xmx2g', '-jar', specialSource, '--in-jar', clientJar, '--out-jar', remappedJar, '--srg-in', tsrgMappings, '--kill-lvt'], { stdio: 'inherit' });
99
+ proc.on('error', (err) => reject(new Error(`SpecialSource failed: ${err.message}`)));
100
+ proc.on('close', (code) => code === 0 && fs.existsSync(remappedJar) ? (progressCb?.('remap', 100, 'Remapped jar created.'), resolve(remappedJar)) : reject(new Error(`SpecialSource failed: ${code}`)));
101
+ });
102
+ }
103
+ export async function generateCallgraph(version, progressCb) {
104
+ const javacgPath = await ensureJavaCG(progressCb);
105
+ const libDir = getJavaCGLibDir();
106
+ const outputDir = getCallgraphDir(version);
107
+ const remappedJar = await ensureRemappedJar(version, progressCb);
108
+ // java-callgraph2 outputs to {jar}-output_javacg2/method_call.txt
109
+ const expectedOutput = path.join(outputDir, `${path.basename(remappedJar)}-output_javacg2`, 'method_call.txt');
110
+ if (fs.existsSync(expectedOutput))
111
+ return expectedOutput;
112
+ ensureDir(outputDir);
113
+ if (progressCb)
114
+ progressCb('callgraph', 0, 'Generating callgraph...');
115
+ // java-callgraph2 expects config in _javacg2_config/ directory
116
+ const configDir = path.join(outputDir, '_javacg2_config');
117
+ ensureDir(configDir);
118
+ fs.writeFileSync(path.join(configDir, 'jar_dir.properties'), remappedJar);
119
+ fs.writeFileSync(path.join(configDir, 'config.properties'), `output.dir=${outputDir}\nparse.method.call.info=1\n`);
120
+ // Build classpath: jar + all libs
121
+ const libJars = fs.existsSync(libDir)
122
+ ? fs.readdirSync(libDir).filter(f => f.endsWith('.jar')).map(f => path.join(libDir, f))
123
+ : [];
124
+ const classpathSep = process.platform === 'win32' ? ';' : ':';
125
+ const classpath = [javacgPath, ...libJars].join(classpathSep);
126
+ return new Promise((resolve, reject) => {
127
+ const proc = spawn('java', ['-Xmx4g', '-cp', classpath, 'com.adrninistrator.javacg2.entry.JavaCG2Entry', configDir], { cwd: outputDir, stdio: 'inherit' });
128
+ proc.on('error', (err) => reject(new Error(`java-callgraph2 failed: ${err.message}`)));
129
+ proc.on('close', (code) => code === 0 || fs.existsSync(expectedOutput) ? (progressCb?.('callgraph', 100, 'Callgraph generated.'), resolve(expectedOutput)) : reject(new Error(`java-callgraph2 failed: ${code}`)));
130
+ });
131
+ }
132
+ export function hasCallgraphDb(version) {
133
+ return fs.existsSync(getCallgraphDbPath(version));
134
+ }
135
+ export function parseCallgraphAndCreateDb(version, callgraphFile, progressCb) {
136
+ if (progressCb)
137
+ progressCb('index', 0, 'Parsing callgraph...');
138
+ const content = fs.readFileSync(callgraphFile, 'utf-8');
139
+ const lines = content.split('\n');
140
+ const dbPath = getCallgraphDbPath(version);
141
+ if (fs.existsSync(dbPath))
142
+ fs.unlinkSync(dbPath);
143
+ const db = new Database(dbPath);
144
+ db.exec(`CREATE TABLE calls (id INTEGER PRIMARY KEY, caller_class TEXT, caller_method TEXT, caller_desc TEXT, callee_class TEXT, callee_method TEXT, callee_desc TEXT, line_number INTEGER); CREATE INDEX idx_callee ON calls(callee_class, callee_method); CREATE INDEX idx_caller ON calls(caller_class, caller_method);`);
145
+ const insert = db.prepare('INSERT INTO calls VALUES (NULL, ?, ?, ?, ?, ?, ?, ?)');
146
+ const insertMany = db.transaction((items) => { for (const item of items)
147
+ insert.run(...item); });
148
+ let count = 0;
149
+ const batch = [];
150
+ // Format: seq num caller callee line return_type ...
151
+ // caller format: class:method(args)
152
+ // callee format: (TYPE)class:method(args) where TYPE is VIR/STA/SPE
153
+ for (const line of lines) {
154
+ if (!line.trim() || line.startsWith('#'))
155
+ continue;
156
+ const parts = line.split('\t');
157
+ if (parts.length < 5)
158
+ continue;
159
+ const callerRaw = parts[2] || '';
160
+ const calleeRaw = parts[3] || '';
161
+ const lineNumber = parts[4] ? parseInt(parts[4], 10) : null;
162
+ // Parse caller: class:method(args)
163
+ const callerMatch = callerRaw.match(/^(.+):(.+)(\([^)]*\))$/);
164
+ // Parse callee: (TYPE)class:method(args)
165
+ const calleeMatch = calleeRaw.match(/^\([A-Z]+\)(.+):(.+)(\([^)]*\))$/);
166
+ if (callerMatch && calleeMatch) {
167
+ batch.push([
168
+ callerMatch[1], callerMatch[2], callerMatch[3],
169
+ calleeMatch[1], calleeMatch[2], calleeMatch[3],
170
+ lineNumber
171
+ ]);
172
+ if (batch.length >= 10000) {
173
+ insertMany(batch);
174
+ count += batch.length;
175
+ batch.length = 0;
176
+ if (progressCb && count % 100000 === 0)
177
+ progressCb('index', 50, `Indexed ${count}...`);
178
+ }
179
+ }
180
+ }
181
+ if (batch.length > 0) {
182
+ insertMany(batch);
183
+ count += batch.length;
184
+ }
185
+ db.pragma('optimize');
186
+ db.close();
187
+ if (progressCb)
188
+ progressCb('index', 100, `Indexed ${count} call references.`);
189
+ return count;
190
+ }
191
+ export async function ensureCallgraph(version, progressCb) {
192
+ if (hasCallgraphDb(version)) {
193
+ if (progressCb)
194
+ progressCb('callgraph', 100, 'Callgraph database ready.');
195
+ return;
196
+ }
197
+ const callgraphFile = await generateCallgraph(version, progressCb);
198
+ parseCallgraphAndCreateDb(version, callgraphFile, progressCb);
199
+ }
200
+ export { openDb, closeDb, findCallers, findCallees, searchMethods, getCallgraphStats } from './query.js';
201
+ //# sourceMappingURL=index.js.map