universal-game-modder 0.1.4

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 (92) hide show
  1. package/ACCEPTABLE_USE.md +49 -0
  2. package/CHANGELOG.md +119 -0
  3. package/LICENSE +21 -0
  4. package/LICENSE-EULA.md +62 -0
  5. package/README.md +162 -0
  6. package/VERIFICATION.md +132 -0
  7. package/dist/backends/child-pool.js +91 -0
  8. package/dist/backends/mcp-child.js +102 -0
  9. package/dist/backends/mcp-child.js.map +1 -0
  10. package/dist/core/config.d.ts +10 -0
  11. package/dist/core/config.js +48 -0
  12. package/dist/core/config.js.map +1 -0
  13. package/dist/core/engine-detector.d.ts +13 -0
  14. package/dist/core/engine-detector.js +247 -0
  15. package/dist/core/engine-detector.js.map +1 -0
  16. package/dist/core/event-bus.js +18 -0
  17. package/dist/core/file-classifier.js +394 -0
  18. package/dist/core/model-db.js +517 -0
  19. package/dist/core/model-db.js.map +1 -0
  20. package/dist/core/router.d.ts +6 -0
  21. package/dist/core/router.js +143 -0
  22. package/dist/core/router.js.map +1 -0
  23. package/dist/core/session.js +114 -0
  24. package/dist/decoders/audio-export.js +57 -0
  25. package/dist/decoders/mesh-export.d.ts +20 -0
  26. package/dist/decoders/mesh-export.js +174 -0
  27. package/dist/decoders/mesh-export.js.map +1 -0
  28. package/dist/decoders/native/disassembler.js +85 -0
  29. package/dist/decoders/native/disassembler.js.map +1 -0
  30. package/dist/decoders/png-encode.d.ts +17 -0
  31. package/dist/decoders/png-encode.js +33 -0
  32. package/dist/decoders/texture-decode.js +278 -0
  33. package/dist/decoders/texture-decode.js.map +1 -0
  34. package/dist/decoders/unity/audioclip.d.ts +55 -0
  35. package/dist/decoders/unity/audioclip.js +87 -0
  36. package/dist/decoders/unity/audioclip.js.map +1 -0
  37. package/dist/decoders/unity/binary-reader.d.ts +45 -0
  38. package/dist/decoders/unity/binary-reader.js +141 -0
  39. package/dist/decoders/unity/binary-reader.js.map +1 -0
  40. package/dist/decoders/unity/mesh.js +198 -0
  41. package/dist/decoders/unity/mesh.js.map +1 -0
  42. package/dist/decoders/unity/ress-reader.d.ts +33 -0
  43. package/dist/decoders/unity/ress-reader.js +82 -0
  44. package/dist/decoders/unity/ress-reader.js.map +1 -0
  45. package/dist/decoders/unity/serialized-file.d.ts +65 -0
  46. package/dist/decoders/unity/serialized-file.js +144 -0
  47. package/dist/decoders/unity/texture2d.js +185 -0
  48. package/dist/decoders/unity/vertex-data.d.ts +54 -0
  49. package/dist/decoders/unity/vertex-data.js +174 -0
  50. package/dist/decoders/unity/vertex-data.js.map +1 -0
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.js +23 -0
  53. package/dist/server.d.ts +1 -0
  54. package/dist/server.js +66 -0
  55. package/dist/tools/decode-tools.d.ts +29 -0
  56. package/dist/tools/decode-tools.js +441 -0
  57. package/dist/tools/delegates/jar-editor.d.ts +2 -0
  58. package/dist/tools/delegates/jar-editor.js +276 -0
  59. package/dist/tools/delegates/unity-decompiler.d.ts +2 -0
  60. package/dist/tools/delegates/unity-decompiler.js +291 -0
  61. package/dist/tools/delegates/unreal-assets.d.ts +2 -0
  62. package/dist/tools/delegates/unreal-assets.js +122 -0
  63. package/dist/tools/detection-tools.d.ts +2 -0
  64. package/dist/tools/detection-tools.js +164 -0
  65. package/dist/tools/detection-tools.js.map +1 -0
  66. package/dist/tools/index.d.ts +8 -0
  67. package/dist/tools/index.js +30 -0
  68. package/dist/tools/index.js.map +1 -0
  69. package/dist/tools/native/index.d.ts +2 -0
  70. package/dist/tools/native/index.js +1201 -0
  71. package/dist/tools/native-comprehension-tools.js +298 -0
  72. package/dist/tools/native-comprehension-tools.js.map +1 -0
  73. package/dist/tools/unpack-tools.d.ts +2 -0
  74. package/dist/tools/unpack-tools.js +382 -0
  75. package/dist/tools/workflow-tools.d.ts +2 -0
  76. package/dist/tools/workflow-tools.js +434 -0
  77. package/dist/utils/logger.d.ts +11 -0
  78. package/dist/utils/logger.js +49 -0
  79. package/dist/utils/logger.js.map +1 -0
  80. package/dist/utils/path-utils.d.ts +15 -0
  81. package/dist/utils/path-utils.js +24 -0
  82. package/dist/utils/path-utils.js.map +1 -0
  83. package/dist/utils/steam-finder.d.ts +8 -0
  84. package/dist/utils/steam-finder.js +32 -0
  85. package/dist/web/web-server.d.ts +1 -0
  86. package/dist/web/web-server.js +369 -0
  87. package/licenses/THIRD-PARTY-NOTICES.md +35 -0
  88. package/llms-install.md +34 -0
  89. package/package.json +69 -0
  90. package/server.json +20 -0
  91. package/setup.ps1 +34 -0
  92. package/ugm.config.json +9 -0
@@ -0,0 +1,517 @@
1
+ /**
2
+ * model-db.ts — The Model SQLite writer (shared core).
3
+ *
4
+ * Owns the `<game>.autopsy.db` file: the single, portable, per-game persistent
5
+ * understanding the whole Autopsy Engine reads and writes. This module is the
6
+ * ONLY thing that knows the on-disk schema (MODEL_SCHEMA.md V1 subset).
7
+ *
8
+ * Design contract (PR-1):
9
+ * - better-sqlite3, synchronous. One file per game.
10
+ * - CREATE TABLE IF NOT EXISTS for game / binary / asset / data_store, every
11
+ * fact-bearing row carrying provenance + source_tool columns.
12
+ * - Idempotent writes: UNIQUE natural keys + INSERT ... ON CONFLICT DO UPDATE,
13
+ * so re-running unpack_game never duplicates rows (append-and-confirm).
14
+ * - WAL journal mode for crash safety.
15
+ * - Read-only with respect to GAME files. The only thing this writes is the
16
+ * .autopsy.db itself.
17
+ */
18
+ import Database from 'better-sqlite3';
19
+ import { dirname } from 'path';
20
+ import { existsSync, mkdirSync } from 'fs';
21
+ /**
22
+ * The schema version this writer emits. Stored on the game row.
23
+ * v1 (PR-0): game / binary / asset / data_store.
24
+ * v2 (PR-3): + function / xref / symbol (ADDITIVE — v1 tables untouched; existing
25
+ * .autopsy.db files gain the empty new tables via CREATE TABLE IF NOT EXISTS).
26
+ */
27
+ export const AUTOPSY_SCHEMA_VERSION = 2;
28
+ /**
29
+ * AutopsyModel — opens/creates a `<game>.autopsy.db` and writes the V1 tables.
30
+ *
31
+ * Usage:
32
+ * const model = new AutopsyModel('C:/.../MyGame.autopsy.db');
33
+ * const gameId = model.upsertGame({ ... });
34
+ * model.addBinary({ game_id: gameId, ... });
35
+ * ...
36
+ * model.close();
37
+ */
38
+ export class AutopsyModel {
39
+ db;
40
+ dbPath;
41
+ constructor(dbPath) {
42
+ this.dbPath = dbPath;
43
+ // Ensure the containing directory exists (.autopsy/ dir or sibling of game).
44
+ const dir = dirname(dbPath);
45
+ if (dir && !existsSync(dir)) {
46
+ mkdirSync(dir, { recursive: true });
47
+ }
48
+ this.db = new Database(dbPath);
49
+ // WAL for crash safety + concurrent reads while we append.
50
+ this.db.pragma('journal_mode = WAL');
51
+ this.db.pragma('foreign_keys = ON');
52
+ // Reasonable durability without the full-fsync cost on every statement.
53
+ this.db.pragma('synchronous = NORMAL');
54
+ this.createSchema();
55
+ }
56
+ /** Create the V1 tables (idempotent). Called on every open. */
57
+ createSchema() {
58
+ this.db.exec(`
59
+ CREATE TABLE IF NOT EXISTS game (
60
+ id INTEGER PRIMARY KEY,
61
+ name TEXT NOT NULL,
62
+ install_path TEXT NOT NULL,
63
+ engine TEXT,
64
+ runtime TEXT,
65
+ arch TEXT,
66
+ package_type TEXT,
67
+ autopsy_version INTEGER NOT NULL,
68
+ provenance TEXT NOT NULL DEFAULT 'inferred',
69
+ source_tool TEXT NOT NULL DEFAULT 'unpack_game',
70
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
71
+ UNIQUE (install_path)
72
+ );
73
+
74
+ CREATE TABLE IF NOT EXISTS binary (
75
+ id INTEGER PRIMARY KEY,
76
+ game_id INTEGER NOT NULL REFERENCES game(id) ON DELETE CASCADE,
77
+ path TEXT NOT NULL,
78
+ kind TEXT NOT NULL,
79
+ managed INTEGER NOT NULL DEFAULT 0,
80
+ arch TEXT,
81
+ size INTEGER NOT NULL DEFAULT 0,
82
+ sha256 TEXT,
83
+ role TEXT,
84
+ notes TEXT,
85
+ provenance TEXT NOT NULL DEFAULT 'inferred',
86
+ source_tool TEXT NOT NULL DEFAULT 'unpack_game',
87
+ UNIQUE (game_id, path)
88
+ );
89
+
90
+ CREATE TABLE IF NOT EXISTS asset (
91
+ id INTEGER PRIMARY KEY,
92
+ game_id INTEGER NOT NULL REFERENCES game(id) ON DELETE CASCADE,
93
+ container_path TEXT NOT NULL,
94
+ internal_path TEXT NOT NULL DEFAULT '',
95
+ type TEXT NOT NULL DEFAULT 'other',
96
+ format TEXT,
97
+ decoded INTEGER NOT NULL DEFAULT 0,
98
+ decoded_path TEXT,
99
+ size INTEGER NOT NULL DEFAULT 0,
100
+ notes TEXT,
101
+ provenance TEXT NOT NULL DEFAULT 'inferred',
102
+ source_tool TEXT NOT NULL DEFAULT 'unpack_game',
103
+ UNIQUE (game_id, container_path, internal_path)
104
+ );
105
+
106
+ CREATE TABLE IF NOT EXISTS data_store (
107
+ id INTEGER PRIMARY KEY,
108
+ game_id INTEGER NOT NULL REFERENCES game(id) ON DELETE CASCADE,
109
+ path TEXT NOT NULL,
110
+ kind TEXT NOT NULL,
111
+ scope TEXT,
112
+ schema_known INTEGER NOT NULL DEFAULT 0,
113
+ notes TEXT,
114
+ provenance TEXT NOT NULL DEFAULT 'inferred',
115
+ source_tool TEXT NOT NULL DEFAULT 'unpack_game',
116
+ UNIQUE (game_id, path)
117
+ );
118
+
119
+ CREATE INDEX IF NOT EXISTS idx_binary_game ON binary(game_id);
120
+ CREATE INDEX IF NOT EXISTS idx_asset_game ON asset(game_id);
121
+ CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(game_id, type);
122
+ CREATE INDEX IF NOT EXISTS idx_data_store_game ON data_store(game_id);
123
+ `);
124
+ // ── Schema v2 (PR-3, V3 Native Comprehension) — ADDITIVE ────────────────
125
+ // New tables only. The v1 block above is byte-for-byte unchanged, so existing
126
+ // .autopsy.db files simply gain these three empty tables on next open.
127
+ // NB: "function" is a SQL keyword — the identifier is double-quoted everywhere.
128
+ this.db.exec(`
129
+ CREATE TABLE IF NOT EXISTS "function" (
130
+ id INTEGER PRIMARY KEY,
131
+ binary_id INTEGER NOT NULL REFERENCES binary(id) ON DELETE CASCADE,
132
+ rva INTEGER NOT NULL,
133
+ size INTEGER NOT NULL DEFAULT 0,
134
+ insn_count INTEGER NOT NULL DEFAULT 0,
135
+ name TEXT,
136
+ label TEXT,
137
+ notes TEXT,
138
+ provenance TEXT NOT NULL DEFAULT 'inferred',
139
+ source_tool TEXT NOT NULL DEFAULT 'disassemble_function',
140
+ UNIQUE (binary_id, rva)
141
+ );
142
+
143
+ CREATE TABLE IF NOT EXISTS xref (
144
+ id INTEGER PRIMARY KEY,
145
+ binary_id INTEGER NOT NULL REFERENCES binary(id) ON DELETE CASCADE,
146
+ from_rva INTEGER NOT NULL,
147
+ to_rva INTEGER NOT NULL,
148
+ kind TEXT NOT NULL,
149
+ mnemonic TEXT,
150
+ notes TEXT,
151
+ provenance TEXT NOT NULL DEFAULT 'verified',
152
+ source_tool TEXT NOT NULL DEFAULT 'build_call_graph',
153
+ UNIQUE (binary_id, from_rva, to_rva, kind)
154
+ );
155
+
156
+ CREATE TABLE IF NOT EXISTS symbol (
157
+ id INTEGER PRIMARY KEY,
158
+ binary_id INTEGER NOT NULL REFERENCES binary(id) ON DELETE CASCADE,
159
+ rva INTEGER NOT NULL,
160
+ name TEXT NOT NULL,
161
+ kind TEXT NOT NULL,
162
+ notes TEXT,
163
+ provenance TEXT NOT NULL DEFAULT 'verified',
164
+ source_tool TEXT NOT NULL DEFAULT 'ingest_pdb',
165
+ UNIQUE (binary_id, rva, kind)
166
+ );
167
+
168
+ CREATE INDEX IF NOT EXISTS idx_function_binary ON "function"(binary_id);
169
+ CREATE INDEX IF NOT EXISTS idx_xref_binary ON xref(binary_id);
170
+ CREATE INDEX IF NOT EXISTS idx_xref_to ON xref(binary_id, to_rva);
171
+ CREATE INDEX IF NOT EXISTS idx_symbol_binary ON symbol(binary_id);
172
+ `);
173
+ }
174
+ /**
175
+ * Insert-or-update the single game header row, keyed by install_path.
176
+ * Returns the game_id (stable across re-runs — append-and-confirm, A6).
177
+ */
178
+ upsertGame(input) {
179
+ const stmt = this.db.prepare(`
180
+ INSERT INTO game (
181
+ name, install_path, engine, runtime, arch, package_type,
182
+ autopsy_version, provenance, source_tool
183
+ ) VALUES (
184
+ @name, @install_path, @engine, @runtime, @arch, @package_type,
185
+ @autopsy_version, @provenance, @source_tool
186
+ )
187
+ ON CONFLICT (install_path) DO UPDATE SET
188
+ name = excluded.name,
189
+ engine = excluded.engine,
190
+ runtime = excluded.runtime,
191
+ arch = excluded.arch,
192
+ package_type = excluded.package_type,
193
+ autopsy_version = excluded.autopsy_version,
194
+ provenance = excluded.provenance,
195
+ source_tool = excluded.source_tool
196
+ RETURNING id
197
+ `);
198
+ const row = stmt.get({
199
+ name: input.name,
200
+ install_path: input.install_path,
201
+ engine: input.engine,
202
+ runtime: input.runtime,
203
+ arch: input.arch,
204
+ package_type: input.package_type,
205
+ autopsy_version: input.autopsy_version,
206
+ provenance: input.provenance,
207
+ source_tool: input.source_tool,
208
+ });
209
+ if (!row) {
210
+ throw new Error('upsertGame: INSERT ... RETURNING id produced no row');
211
+ }
212
+ return row.id;
213
+ }
214
+ /**
215
+ * Insert-or-update a binary, keyed by (game_id, path). Idempotent (A6).
216
+ * Returns the binary id.
217
+ */
218
+ addBinary(input) {
219
+ const stmt = this.db.prepare(`
220
+ INSERT INTO binary (
221
+ game_id, path, kind, managed, arch, size, sha256, role, notes,
222
+ provenance, source_tool
223
+ ) VALUES (
224
+ @game_id, @path, @kind, @managed, @arch, @size, @sha256, @role, @notes,
225
+ @provenance, @source_tool
226
+ )
227
+ ON CONFLICT (game_id, path) DO UPDATE SET
228
+ kind = excluded.kind,
229
+ managed = excluded.managed,
230
+ arch = excluded.arch,
231
+ size = excluded.size,
232
+ sha256 = excluded.sha256,
233
+ role = excluded.role,
234
+ notes = excluded.notes,
235
+ provenance = excluded.provenance,
236
+ source_tool = excluded.source_tool
237
+ RETURNING id
238
+ `);
239
+ const row = stmt.get({
240
+ game_id: input.game_id,
241
+ path: input.path,
242
+ kind: input.kind,
243
+ managed: input.managed ? 1 : 0,
244
+ arch: input.arch,
245
+ size: input.size,
246
+ sha256: input.sha256,
247
+ role: input.role,
248
+ notes: input.notes,
249
+ provenance: input.provenance,
250
+ source_tool: input.source_tool,
251
+ });
252
+ if (!row) {
253
+ throw new Error('addBinary: INSERT ... RETURNING id produced no row');
254
+ }
255
+ return row.id;
256
+ }
257
+ /**
258
+ * Insert-or-update an asset, keyed by (game_id, container_path, internal_path).
259
+ * Idempotent (A6). Unknown files arrive here as type='other' with a reason in
260
+ * notes — they are catalogued, never dropped (A3). Returns the asset id.
261
+ */
262
+ addAsset(input) {
263
+ const stmt = this.db.prepare(`
264
+ INSERT INTO asset (
265
+ game_id, container_path, internal_path, type, format, decoded,
266
+ decoded_path, size, notes, provenance, source_tool
267
+ ) VALUES (
268
+ @game_id, @container_path, @internal_path, @type, @format, @decoded,
269
+ @decoded_path, @size, @notes, @provenance, @source_tool
270
+ )
271
+ ON CONFLICT (game_id, container_path, internal_path) DO UPDATE SET
272
+ type = excluded.type,
273
+ format = excluded.format,
274
+ decoded = excluded.decoded,
275
+ decoded_path = excluded.decoded_path,
276
+ size = excluded.size,
277
+ notes = excluded.notes,
278
+ provenance = excluded.provenance,
279
+ source_tool = excluded.source_tool
280
+ RETURNING id
281
+ `);
282
+ const row = stmt.get({
283
+ game_id: input.game_id,
284
+ container_path: input.container_path,
285
+ internal_path: input.internal_path ?? '',
286
+ type: input.type,
287
+ format: input.format,
288
+ decoded: input.decoded ? 1 : 0,
289
+ decoded_path: input.decoded_path,
290
+ size: input.size,
291
+ notes: input.notes,
292
+ provenance: input.provenance,
293
+ source_tool: input.source_tool,
294
+ });
295
+ if (!row) {
296
+ throw new Error('addAsset: INSERT ... RETURNING id produced no row');
297
+ }
298
+ return row.id;
299
+ }
300
+ /**
301
+ * Insert-or-update a data_store, keyed by (game_id, path). Idempotent (A6).
302
+ * Containers (.pak/.bundle/.pck) may land here as kind='binary-blob' rather
303
+ * than being walked as Unity (A7). Returns the data_store id.
304
+ */
305
+ addDataStore(input) {
306
+ const stmt = this.db.prepare(`
307
+ INSERT INTO data_store (
308
+ game_id, path, kind, scope, schema_known, notes,
309
+ provenance, source_tool
310
+ ) VALUES (
311
+ @game_id, @path, @kind, @scope, @schema_known, @notes,
312
+ @provenance, @source_tool
313
+ )
314
+ ON CONFLICT (game_id, path) DO UPDATE SET
315
+ kind = excluded.kind,
316
+ scope = excluded.scope,
317
+ schema_known = excluded.schema_known,
318
+ notes = excluded.notes,
319
+ provenance = excluded.provenance,
320
+ source_tool = excluded.source_tool
321
+ RETURNING id
322
+ `);
323
+ const row = stmt.get({
324
+ game_id: input.game_id,
325
+ path: input.path,
326
+ kind: input.kind,
327
+ scope: input.scope,
328
+ schema_known: input.schema_known ? 1 : 0,
329
+ notes: input.notes,
330
+ provenance: input.provenance,
331
+ source_tool: input.source_tool,
332
+ });
333
+ if (!row) {
334
+ throw new Error('addDataStore: INSERT ... RETURNING id produced no row');
335
+ }
336
+ return row.id;
337
+ }
338
+ /**
339
+ * Insert-or-update a function, keyed by (binary_id, rva). Idempotent (A6).
340
+ * PR-3.1 writes the disassembled region's extent; name/label fill in later
341
+ * slices. Returns the function id.
342
+ */
343
+ addFunction(input) {
344
+ const stmt = this.db.prepare(`
345
+ INSERT INTO "function" (
346
+ binary_id, rva, size, insn_count, name, label, notes,
347
+ provenance, source_tool
348
+ ) VALUES (
349
+ @binary_id, @rva, @size, @insn_count, @name, @label, @notes,
350
+ @provenance, @source_tool
351
+ )
352
+ ON CONFLICT (binary_id, rva) DO UPDATE SET
353
+ size = excluded.size,
354
+ insn_count = excluded.insn_count,
355
+ name = COALESCE(excluded.name, "function".name),
356
+ label = COALESCE(excluded.label, "function".label),
357
+ notes = excluded.notes,
358
+ provenance = excluded.provenance,
359
+ source_tool = excluded.source_tool
360
+ RETURNING id
361
+ `);
362
+ const row = stmt.get({
363
+ binary_id: input.binary_id,
364
+ rva: input.rva,
365
+ size: input.size,
366
+ insn_count: input.insn_count,
367
+ name: input.name,
368
+ label: input.label,
369
+ notes: input.notes,
370
+ provenance: input.provenance,
371
+ source_tool: input.source_tool,
372
+ });
373
+ if (!row) {
374
+ throw new Error('addFunction: INSERT ... RETURNING id produced no row');
375
+ }
376
+ return row.id;
377
+ }
378
+ /**
379
+ * Insert-or-update a cross-reference, keyed by (binary_id, from_rva, to_rva,
380
+ * kind). Idempotent (A6). Returns the xref id.
381
+ */
382
+ addXref(input) {
383
+ const stmt = this.db.prepare(`
384
+ INSERT INTO xref (
385
+ binary_id, from_rva, to_rva, kind, mnemonic, notes,
386
+ provenance, source_tool
387
+ ) VALUES (
388
+ @binary_id, @from_rva, @to_rva, @kind, @mnemonic, @notes,
389
+ @provenance, @source_tool
390
+ )
391
+ ON CONFLICT (binary_id, from_rva, to_rva, kind) DO UPDATE SET
392
+ mnemonic = excluded.mnemonic,
393
+ notes = excluded.notes,
394
+ provenance = excluded.provenance,
395
+ source_tool = excluded.source_tool
396
+ RETURNING id
397
+ `);
398
+ const row = stmt.get({
399
+ binary_id: input.binary_id,
400
+ from_rva: input.from_rva,
401
+ to_rva: input.to_rva,
402
+ kind: input.kind,
403
+ mnemonic: input.mnemonic,
404
+ notes: input.notes,
405
+ provenance: input.provenance,
406
+ source_tool: input.source_tool,
407
+ });
408
+ if (!row) {
409
+ throw new Error('addXref: INSERT ... RETURNING id produced no row');
410
+ }
411
+ return row.id;
412
+ }
413
+ /**
414
+ * Insert-or-update a symbol, keyed by (binary_id, rva, kind). Idempotent (A6).
415
+ * Returns the symbol id.
416
+ */
417
+ addSymbol(input) {
418
+ const stmt = this.db.prepare(`
419
+ INSERT INTO symbol (
420
+ binary_id, rva, name, kind, notes, provenance, source_tool
421
+ ) VALUES (
422
+ @binary_id, @rva, @name, @kind, @notes, @provenance, @source_tool
423
+ )
424
+ ON CONFLICT (binary_id, rva, kind) DO UPDATE SET
425
+ name = excluded.name,
426
+ notes = excluded.notes,
427
+ provenance = excluded.provenance,
428
+ source_tool = excluded.source_tool
429
+ RETURNING id
430
+ `);
431
+ const row = stmt.get({
432
+ binary_id: input.binary_id,
433
+ rva: input.rva,
434
+ name: input.name,
435
+ kind: input.kind,
436
+ notes: input.notes,
437
+ provenance: input.provenance,
438
+ source_tool: input.source_tool,
439
+ });
440
+ if (!row) {
441
+ throw new Error('addSymbol: INSERT ... RETURNING id produced no row');
442
+ }
443
+ return row.id;
444
+ }
445
+ /**
446
+ * Run many writes inside one transaction. Returns the callback's result.
447
+ * Far faster for a full-install walk, and atomic: a crash mid-walk leaves
448
+ * the DB at its prior consistent state rather than half-populated.
449
+ */
450
+ transaction(fn) {
451
+ const wrapped = this.db.transaction(fn);
452
+ return wrapped();
453
+ }
454
+ /** Row counts per table — for the unpack summary / verifier / tests. */
455
+ counts() {
456
+ // `table` is a trusted literal from this method only (never user input).
457
+ // "function" is a SQL keyword, so callers pass the already-quoted identifier.
458
+ const one = (table) => {
459
+ const row = this.db
460
+ .prepare(`SELECT COUNT(*) AS n FROM ${table}`)
461
+ .get();
462
+ return row.n;
463
+ };
464
+ return {
465
+ game: one('game'),
466
+ binary: one('binary'),
467
+ asset: one('asset'),
468
+ data_store: one('data_store'),
469
+ function: one('"function"'),
470
+ xref: one('xref'),
471
+ symbol: one('symbol'),
472
+ };
473
+ }
474
+ /** Row counts scoped to a single game_id. Convenience for per-game summaries. */
475
+ countsForGame(gameId) {
476
+ const one = (table) => {
477
+ const row = this.db
478
+ .prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE game_id = ?`)
479
+ .get(gameId);
480
+ return row.n;
481
+ };
482
+ // Native tables (v2) key on binary_id, so scope them through binary(game_id).
483
+ const viaBinary = (table) => {
484
+ const row = this.db
485
+ .prepare(`SELECT COUNT(*) AS n FROM ${table} t
486
+ JOIN binary b ON b.id = t.binary_id
487
+ WHERE b.game_id = ?`)
488
+ .get(gameId);
489
+ return row.n;
490
+ };
491
+ return {
492
+ // The game table is keyed on id, not game_id.
493
+ game: this.db.prepare('SELECT COUNT(*) AS n FROM game WHERE id = ?').get(gameId).n,
494
+ binary: one('binary'),
495
+ asset: one('asset'),
496
+ data_store: one('data_store'),
497
+ function: viaBinary('"function"'),
498
+ xref: viaBinary('xref'),
499
+ symbol: viaBinary('symbol'),
500
+ };
501
+ }
502
+ /** Escape hatch for verifiers/tests that need a raw read. Read-only by convention. */
503
+ raw() {
504
+ return this.db;
505
+ }
506
+ /** Flush WAL back into the main DB and close the handle. */
507
+ close() {
508
+ try {
509
+ this.db.pragma('wal_checkpoint(TRUNCATE)');
510
+ }
511
+ catch {
512
+ // Best-effort checkpoint; closing is what matters.
513
+ }
514
+ this.db.close();
515
+ }
516
+ }
517
+ //# sourceMappingURL=model-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-db.js","sourceRoot":"","sources":["../../src/core/model-db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAmL3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,OAAO,YAAY;IACN,EAAE,CAAoB;IACvB,MAAM,CAAS;IAE/B,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,6EAA6E;QAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE/B,2DAA2D;QAC3D,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACpC,wEAAwE;QACxE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAEvC,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,+DAA+D;IACvD,YAAY;QAClB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiEZ,CAAC,CAAC;QAEH,2EAA2E;QAC3E,8EAA8E;QAC9E,uEAAuE;QACvE,gFAAgF;QAChF,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4CZ,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,KAAgB;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;KAkB5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,KAAkB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;KAmB5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,KAAiB;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;KAkB5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,EAAE;YACxC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,KAAqB;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;KAgB5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,KAAoB;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;KAiB5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,KAAgB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;KAc5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,KAAkB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;KAY5B,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAA+B,CAAC;QAEjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAI,EAAW;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxC,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,wEAAwE;IACxE,MAAM;QACJ,yEAAyE;QACzE,8EAA8E;QAC9E,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;iBAChB,OAAO,CAAC,6BAA6B,KAAK,EAAE,CAAC;iBAC7C,GAAG,EAAmB,CAAC;YAC1B,OAAO,GAAG,CAAC,CAAC,CAAC;QACf,CAAC,CAAC;QACF,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;YACjB,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC;YACrB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;YACnB,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC;YAC7B,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC;YAC3B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;YACjB,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC;SACtB,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,aAAa,CAAC,MAAc;QAC1B,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;iBAChB,OAAO,CAAC,6BAA6B,KAAK,oBAAoB,CAAC;iBAC/D,GAAG,CAAC,MAAM,CAAkB,CAAC;YAChC,OAAO,GAAG,CAAC,CAAC,CAAC;QACf,CAAC,CAAC;QACF,8EAA8E;QAC9E,MAAM,SAAS,GAAG,CAAC,KAAa,EAAU,EAAE;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;iBAChB,OAAO,CACN,6BAA6B,KAAK;;+BAEb,CACtB;iBACA,GAAG,CAAC,MAAM,CAAkB,CAAC;YAChC,OAAO,GAAG,CAAC,CAAC,CAAC;QACf,CAAC,CAAC;QACF,OAAO;YACL,8CAA8C;YAC9C,IAAI,EACF,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC,GAAG,CAAC,MAAM,CAG1E,CAAC,CAAC;YACH,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC;YACrB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC;YACnB,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC;YAC7B,QAAQ,EAAE,SAAS,CAAC,YAAY,CAAC;YACjC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;YACvB,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC;SAC5B,CAAC;IACJ,CAAC;IAED,sFAAsF;IACtF,GAAG;QACD,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,4DAA4D;IAC5D,KAAK;QACH,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import { BackendName } from '../backends/child-pool.js';
2
+ export type ToolBackend = 'native' | 'workflow' | BackendName;
3
+ export declare function getToolBackend(toolName: string): ToolBackend | undefined;
4
+ export declare function getAllToolNames(): string[];
5
+ export declare function getToolsByBackend(backend: ToolBackend): string[];
6
+ export declare function isValidTool(toolName: string): boolean;
@@ -0,0 +1,143 @@
1
+ // Static route map: tool name -> backend
2
+ const ROUTE_MAP = new Map([
3
+ // === Detection & Session (workflow) ===
4
+ ['detect_engine', 'workflow'],
5
+ ['load_game', 'workflow'],
6
+ ['game_status', 'workflow'],
7
+ ['list_available_tools', 'workflow'],
8
+ ['find_steam_games', 'workflow'],
9
+ // === Workflow Tools ===
10
+ ['mod_this_game', 'workflow'],
11
+ ['find_gameplay_values', 'workflow'],
12
+ ['build_and_deploy', 'workflow'],
13
+ ['debug_mod', 'workflow'],
14
+ ['scaffold_mod', 'workflow'],
15
+ // === Native Analysis Tools (ported from binary-analyzer-ultra) ===
16
+ ['analyze_pe_full', 'native'],
17
+ ['analyze_dll_exports', 'native'],
18
+ ['analyze_dll_imports', 'native'],
19
+ ['analyze_file_format', 'native'],
20
+ ['analyze_memory_layout', 'native'],
21
+ ['hex_read', 'native'],
22
+ ['hex_write', 'native'],
23
+ ['hex_search', 'native'],
24
+ ['hex_replace', 'native'],
25
+ ['pattern_scan', 'native'],
26
+ ['pattern_scan_all', 'native'],
27
+ ['extract_strings_advanced', 'native'],
28
+ ['extract_resources_full', 'native'],
29
+ ['edit_string_table', 'native'],
30
+ ['inject_resource', 'native'],
31
+ ['compare_binaries_detailed', 'native'],
32
+ ['calculate_checksums', 'native'],
33
+ ['fix_pe_checksum', 'native'],
34
+ ['rva_to_offset', 'native'],
35
+ ['offset_to_rva', 'native'],
36
+ ['disassemble_function', 'native'],
37
+ ['create_patch', 'native'],
38
+ ['apply_patch', 'native'],
39
+ ['compress_file', 'native'],
40
+ ['decompress_file', 'native'],
41
+ ['encrypt_decrypt_file', 'native'],
42
+ ['analyze_wad', 'native'],
43
+ // IL2CPP native tools
44
+ ['unity_il2cpp_dump_metadata', 'native'],
45
+ ['unity_il2cpp_find_class', 'native'],
46
+ ['actk_scan_obscured_values', 'native'],
47
+ ['actk_decrypt_value', 'native'],
48
+ ['actk_struct_info', 'native'],
49
+ // PlayerPrefs native tools
50
+ ['unity_playerprefs_read', 'native'],
51
+ ['unity_playerprefs_write', 'native'],
52
+ // Godot native tools
53
+ ['analyze_godot_pck', 'native'],
54
+ // Game save tools
55
+ ['analyze_game_save', 'native'],
56
+ // Smart binary analyzer (ported)
57
+ ['search_binary_pattern', 'native'],
58
+ ['extract_dll_classes', 'native'],
59
+ ['extract_strings', 'native'],
60
+ ['analyze_dll_structure', 'native'],
61
+ // === Unity Mono Delegate (-> UnityDecompilerMcp.exe) ===
62
+ ['load_assembly', 'unity-decompiler'],
63
+ ['list_types', 'unity-decompiler'],
64
+ ['inspect_type', 'unity-decompiler'],
65
+ ['decompile_type', 'unity-decompiler'],
66
+ ['decompile_method', 'unity-decompiler'],
67
+ ['get_method_il', 'unity-decompiler'],
68
+ ['search_code', 'unity-decompiler'],
69
+ ['find_references', 'unity-decompiler'],
70
+ ['get_inheritance_tree', 'unity-decompiler'],
71
+ ['list_monobehaviours', 'unity-decompiler'],
72
+ ['list_scriptableobjects', 'unity-decompiler'],
73
+ ['get_serialized_fields', 'unity-decompiler'],
74
+ ['generate_harmony_patch', 'unity-decompiler'],
75
+ ['generate_plugin', 'unity-decompiler'],
76
+ ['compile_plugin', 'unity-decompiler'],
77
+ ['validate_assembly', 'unity-decompiler'],
78
+ ['validate_patch_target', 'unity-decompiler'],
79
+ ['verify_patches', 'unity-decompiler'],
80
+ ['compare_signatures', 'unity-decompiler'],
81
+ ['diff_assemblies', 'unity-decompiler'],
82
+ ['find_renamed_types', 'unity-decompiler'],
83
+ ['detect_networking', 'unity-decompiler'],
84
+ ['analyze_bepinex_log', 'unity-decompiler'],
85
+ ['analyze_save_format', 'unity-decompiler'],
86
+ ['read_playerprefs', 'unity-decompiler'],
87
+ ['read_unity_assets_info', 'unity-decompiler'],
88
+ ['list_patchable_methods', 'unity-decompiler'],
89
+ // === Unreal Delegate (-> UnrealAssetMcp.exe) ===
90
+ ['open_game', 'unreal-assets'],
91
+ ['unreal_game_status', 'unreal-assets'],
92
+ ['list_assets', 'unreal-assets'],
93
+ ['search_assets', 'unreal-assets'],
94
+ ['read_asset', 'unreal-assets'],
95
+ ['read_asset_export', 'unreal-assets'],
96
+ ['list_exports', 'unreal-assets'],
97
+ ['read_blueprint', 'unreal-assets'],
98
+ ['find_blueprints_of_type', 'unreal-assets'],
99
+ ['read_datatable', 'unreal-assets'],
100
+ ['get_class_hierarchy', 'unreal-assets'],
101
+ // === Java Delegate (-> jar-editor server.py) ===
102
+ ['jar_open', 'jar-editor'],
103
+ ['jar_close', 'jar-editor'],
104
+ ['jar_list', 'jar-editor'],
105
+ ['jar_list_sessions', 'jar-editor'],
106
+ ['jar_read_class', 'jar-editor'],
107
+ ['jar_read_file', 'jar-editor'],
108
+ ['jar_search', 'jar-editor'],
109
+ ['jar_search_bytecode', 'jar-editor'],
110
+ ['jar_search_opcodes', 'jar-editor'],
111
+ ['jar_inspect_constant_pool', 'jar-editor'],
112
+ ['jar_edit_class_constants', 'jar-editor'],
113
+ ['jar_edit_constant_pool', 'jar-editor'],
114
+ ['jar_edit_file', 'jar-editor'],
115
+ ['jar_hex_edit', 'jar-editor'],
116
+ ['jar_hex_view', 'jar-editor'],
117
+ ['jar_compile_java', 'jar-editor'],
118
+ ['jar_repack', 'jar-editor'],
119
+ ['jar_diff', 'jar-editor'],
120
+ ['jar_add_file', 'jar-editor'],
121
+ ['jar_add_file_content', 'jar-editor'],
122
+ ['jar_restore_file', 'jar-editor'],
123
+ ['jar_scaffold_mod', 'jar-editor'],
124
+ ['jar_preset_apply', 'jar-editor'],
125
+ ['jar_preset_list', 'jar-editor'],
126
+ ['jar_preset_save', 'jar-editor'],
127
+ ['jar_detect_mod_info', 'jar-editor'],
128
+ ]);
129
+ export function getToolBackend(toolName) {
130
+ return ROUTE_MAP.get(toolName);
131
+ }
132
+ export function getAllToolNames() {
133
+ return Array.from(ROUTE_MAP.keys());
134
+ }
135
+ export function getToolsByBackend(backend) {
136
+ return Array.from(ROUTE_MAP.entries())
137
+ .filter(([_, b]) => b === backend)
138
+ .map(([name]) => name);
139
+ }
140
+ export function isValidTool(toolName) {
141
+ return ROUTE_MAP.has(toolName);
142
+ }
143
+ //# sourceMappingURL=router.js.map