rpgmaker-mz-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 (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +425 -0
  3. package/dist/events/commandBuilders.d.ts +405 -0
  4. package/dist/events/commandBuilders.d.ts.map +1 -0
  5. package/dist/events/commandBuilders.js +554 -0
  6. package/dist/events/commandBuilders.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +105 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/registry.d.ts +81 -0
  12. package/dist/registry.d.ts.map +1 -0
  13. package/dist/registry.js +49 -0
  14. package/dist/registry.js.map +1 -0
  15. package/dist/tiles/autotile.d.ts +65 -0
  16. package/dist/tiles/autotile.d.ts.map +1 -0
  17. package/dist/tiles/autotile.js +201 -0
  18. package/dist/tiles/autotile.js.map +1 -0
  19. package/dist/tiles/catalog/dungeon.d.ts +16 -0
  20. package/dist/tiles/catalog/dungeon.d.ts.map +1 -0
  21. package/dist/tiles/catalog/dungeon.js +765 -0
  22. package/dist/tiles/catalog/dungeon.js.map +1 -0
  23. package/dist/tiles/catalog/index.d.ts +78 -0
  24. package/dist/tiles/catalog/index.d.ts.map +1 -0
  25. package/dist/tiles/catalog/index.js +115 -0
  26. package/dist/tiles/catalog/index.js.map +1 -0
  27. package/dist/tiles/catalog/inside.d.ts +16 -0
  28. package/dist/tiles/catalog/inside.d.ts.map +1 -0
  29. package/dist/tiles/catalog/inside.js +765 -0
  30. package/dist/tiles/catalog/inside.js.map +1 -0
  31. package/dist/tiles/catalog/outside.d.ts +16 -0
  32. package/dist/tiles/catalog/outside.d.ts.map +1 -0
  33. package/dist/tiles/catalog/outside.js +799 -0
  34. package/dist/tiles/catalog/outside.js.map +1 -0
  35. package/dist/tiles/catalog/overworld.d.ts +16 -0
  36. package/dist/tiles/catalog/overworld.d.ts.map +1 -0
  37. package/dist/tiles/catalog/overworld.js +585 -0
  38. package/dist/tiles/catalog/overworld.js.map +1 -0
  39. package/dist/tiles/catalog/sf.d.ts +16 -0
  40. package/dist/tiles/catalog/sf.d.ts.map +1 -0
  41. package/dist/tiles/catalog/sf.js +1313 -0
  42. package/dist/tiles/catalog/sf.js.map +1 -0
  43. package/dist/tiles/paint.d.ts +20 -0
  44. package/dist/tiles/paint.d.ts.map +1 -0
  45. package/dist/tiles/paint.js +65 -0
  46. package/dist/tiles/paint.js.map +1 -0
  47. package/dist/tiles/png.d.ts +11 -0
  48. package/dist/tiles/png.d.ts.map +1 -0
  49. package/dist/tiles/png.js +180 -0
  50. package/dist/tiles/png.js.map +1 -0
  51. package/dist/tiles/tileCodec.d.ts +95 -0
  52. package/dist/tiles/tileCodec.d.ts.map +1 -0
  53. package/dist/tiles/tileCodec.js +186 -0
  54. package/dist/tiles/tileCodec.js.map +1 -0
  55. package/dist/tiles/tileFlags.d.ts +98 -0
  56. package/dist/tiles/tileFlags.d.ts.map +1 -0
  57. package/dist/tiles/tileFlags.js +129 -0
  58. package/dist/tiles/tileFlags.js.map +1 -0
  59. package/dist/tiles/tilegeom.d.ts +29 -0
  60. package/dist/tiles/tilegeom.d.ts.map +1 -0
  61. package/dist/tiles/tilegeom.js +111 -0
  62. package/dist/tiles/tilegeom.js.map +1 -0
  63. package/dist/tiles/transparency.d.ts +22 -0
  64. package/dist/tiles/transparency.d.ts.map +1 -0
  65. package/dist/tiles/transparency.js +59 -0
  66. package/dist/tiles/transparency.js.map +1 -0
  67. package/dist/tools/actorTools.d.ts +48 -0
  68. package/dist/tools/actorTools.d.ts.map +1 -0
  69. package/dist/tools/actorTools.js +154 -0
  70. package/dist/tools/actorTools.js.map +1 -0
  71. package/dist/tools/allTools.d.ts +8 -0
  72. package/dist/tools/allTools.d.ts.map +1 -0
  73. package/dist/tools/allTools.js +56 -0
  74. package/dist/tools/allTools.js.map +1 -0
  75. package/dist/tools/assetTools.d.ts +113 -0
  76. package/dist/tools/assetTools.d.ts.map +1 -0
  77. package/dist/tools/assetTools.js +97 -0
  78. package/dist/tools/assetTools.js.map +1 -0
  79. package/dist/tools/batchTools.d.ts +3 -0
  80. package/dist/tools/batchTools.d.ts.map +1 -0
  81. package/dist/tools/batchTools.js +138 -0
  82. package/dist/tools/batchTools.js.map +1 -0
  83. package/dist/tools/battleTools.d.ts +72 -0
  84. package/dist/tools/battleTools.d.ts.map +1 -0
  85. package/dist/tools/battleTools.js +322 -0
  86. package/dist/tools/battleTools.js.map +1 -0
  87. package/dist/tools/catalogTools.d.ts +3 -0
  88. package/dist/tools/catalogTools.d.ts.map +1 -0
  89. package/dist/tools/catalogTools.js +134 -0
  90. package/dist/tools/catalogTools.js.map +1 -0
  91. package/dist/tools/classTools.d.ts +85 -0
  92. package/dist/tools/classTools.d.ts.map +1 -0
  93. package/dist/tools/classTools.js +279 -0
  94. package/dist/tools/classTools.js.map +1 -0
  95. package/dist/tools/commonEventTools.d.ts +32 -0
  96. package/dist/tools/commonEventTools.d.ts.map +1 -0
  97. package/dist/tools/commonEventTools.js +150 -0
  98. package/dist/tools/commonEventTools.js.map +1 -0
  99. package/dist/tools/eventCommandTools.d.ts +37 -0
  100. package/dist/tools/eventCommandTools.d.ts.map +1 -0
  101. package/dist/tools/eventCommandTools.js +893 -0
  102. package/dist/tools/eventCommandTools.js.map +1 -0
  103. package/dist/tools/eventPageTools.d.ts +112 -0
  104. package/dist/tools/eventPageTools.d.ts.map +1 -0
  105. package/dist/tools/eventPageTools.js +597 -0
  106. package/dist/tools/eventPageTools.js.map +1 -0
  107. package/dist/tools/itemTools.d.ts +82 -0
  108. package/dist/tools/itemTools.d.ts.map +1 -0
  109. package/dist/tools/itemTools.js +380 -0
  110. package/dist/tools/itemTools.js.map +1 -0
  111. package/dist/tools/listTools.d.ts +58 -0
  112. package/dist/tools/listTools.d.ts.map +1 -0
  113. package/dist/tools/listTools.js +99 -0
  114. package/dist/tools/listTools.js.map +1 -0
  115. package/dist/tools/mapTools.d.ts +270 -0
  116. package/dist/tools/mapTools.d.ts.map +1 -0
  117. package/dist/tools/mapTools.js +1066 -0
  118. package/dist/tools/mapTools.js.map +1 -0
  119. package/dist/tools/moveTools.d.ts +43 -0
  120. package/dist/tools/moveTools.d.ts.map +1 -0
  121. package/dist/tools/moveTools.js +240 -0
  122. package/dist/tools/moveTools.js.map +1 -0
  123. package/dist/tools/objectTools.d.ts +12 -0
  124. package/dist/tools/objectTools.d.ts.map +1 -0
  125. package/dist/tools/objectTools.js +221 -0
  126. package/dist/tools/objectTools.js.map +1 -0
  127. package/dist/tools/paintTools.d.ts +3 -0
  128. package/dist/tools/paintTools.d.ts.map +1 -0
  129. package/dist/tools/paintTools.js +134 -0
  130. package/dist/tools/paintTools.js.map +1 -0
  131. package/dist/tools/pluginScanTools.d.ts +22 -0
  132. package/dist/tools/pluginScanTools.d.ts.map +1 -0
  133. package/dist/tools/pluginScanTools.js +119 -0
  134. package/dist/tools/pluginScanTools.js.map +1 -0
  135. package/dist/tools/pluginTools.d.ts +11 -0
  136. package/dist/tools/pluginTools.d.ts.map +1 -0
  137. package/dist/tools/pluginTools.js +63 -0
  138. package/dist/tools/pluginTools.js.map +1 -0
  139. package/dist/tools/projectTools.d.ts +11 -0
  140. package/dist/tools/projectTools.d.ts.map +1 -0
  141. package/dist/tools/projectTools.js +74 -0
  142. package/dist/tools/projectTools.js.map +1 -0
  143. package/dist/tools/skillTools.d.ts +83 -0
  144. package/dist/tools/skillTools.d.ts.map +1 -0
  145. package/dist/tools/skillTools.js +369 -0
  146. package/dist/tools/skillTools.js.map +1 -0
  147. package/dist/tools/stateTools.d.ts +28 -0
  148. package/dist/tools/stateTools.d.ts.map +1 -0
  149. package/dist/tools/stateTools.js +161 -0
  150. package/dist/tools/stateTools.js.map +1 -0
  151. package/dist/tools/systemTools.d.ts +86 -0
  152. package/dist/tools/systemTools.d.ts.map +1 -0
  153. package/dist/tools/systemTools.js +342 -0
  154. package/dist/tools/systemTools.js.map +1 -0
  155. package/dist/tools/tileTools.d.ts +9 -0
  156. package/dist/tools/tileTools.d.ts.map +1 -0
  157. package/dist/tools/tileTools.js +34 -0
  158. package/dist/tools/tileTools.js.map +1 -0
  159. package/dist/tools/tileTransparency.d.ts +40 -0
  160. package/dist/tools/tileTransparency.d.ts.map +1 -0
  161. package/dist/tools/tileTransparency.js +156 -0
  162. package/dist/tools/tileTransparency.js.map +1 -0
  163. package/dist/tools/tilesetTools.d.ts +23 -0
  164. package/dist/tools/tilesetTools.d.ts.map +1 -0
  165. package/dist/tools/tilesetTools.js +209 -0
  166. package/dist/tools/tilesetTools.js.map +1 -0
  167. package/dist/tools/validationTools.d.ts +50 -0
  168. package/dist/tools/validationTools.d.ts.map +1 -0
  169. package/dist/tools/validationTools.js +229 -0
  170. package/dist/tools/validationTools.js.map +1 -0
  171. package/dist/utils/commit.d.ts +62 -0
  172. package/dist/utils/commit.d.ts.map +1 -0
  173. package/dist/utils/commit.js +119 -0
  174. package/dist/utils/commit.js.map +1 -0
  175. package/dist/utils/fileHandler.d.ts +49 -0
  176. package/dist/utils/fileHandler.d.ts.map +1 -0
  177. package/dist/utils/fileHandler.js +137 -0
  178. package/dist/utils/fileHandler.js.map +1 -0
  179. package/dist/utils/records.d.ts +8 -0
  180. package/dist/utils/records.d.ts.map +1 -0
  181. package/dist/utils/records.js +10 -0
  182. package/dist/utils/records.js.map +1 -0
  183. package/dist/utils/types.d.ts +465 -0
  184. package/dist/utils/types.d.ts.map +1 -0
  185. package/dist/utils/types.js +5 -0
  186. package/dist/utils/types.js.map +1 -0
  187. package/dist/validation/assets.d.ts +53 -0
  188. package/dist/validation/assets.d.ts.map +1 -0
  189. package/dist/validation/assets.js +198 -0
  190. package/dist/validation/assets.js.map +1 -0
  191. package/dist/validation/createRefs.d.ts +37 -0
  192. package/dist/validation/createRefs.d.ts.map +1 -0
  193. package/dist/validation/createRefs.js +89 -0
  194. package/dist/validation/createRefs.js.map +1 -0
  195. package/dist/validation/eventCommands.d.ts +70 -0
  196. package/dist/validation/eventCommands.d.ts.map +1 -0
  197. package/dist/validation/eventCommands.js +273 -0
  198. package/dist/validation/eventCommands.js.map +1 -0
  199. package/dist/validation/gate.d.ts +56 -0
  200. package/dist/validation/gate.d.ts.map +1 -0
  201. package/dist/validation/gate.js +50 -0
  202. package/dist/validation/gate.js.map +1 -0
  203. package/dist/validation/moveCommands.d.ts +31 -0
  204. package/dist/validation/moveCommands.d.ts.map +1 -0
  205. package/dist/validation/moveCommands.js +123 -0
  206. package/dist/validation/moveCommands.js.map +1 -0
  207. package/dist/validation/pluginCommands.d.ts +83 -0
  208. package/dist/validation/pluginCommands.d.ts.map +1 -0
  209. package/dist/validation/pluginCommands.js +134 -0
  210. package/dist/validation/pluginCommands.js.map +1 -0
  211. package/dist/validation/pluginManifest.d.ts +67 -0
  212. package/dist/validation/pluginManifest.d.ts.map +1 -0
  213. package/dist/validation/pluginManifest.js +199 -0
  214. package/dist/validation/pluginManifest.js.map +1 -0
  215. package/dist/validation/references.d.ts +57 -0
  216. package/dist/validation/references.d.ts.map +1 -0
  217. package/dist/validation/references.js +314 -0
  218. package/dist/validation/references.js.map +1 -0
  219. package/package.json +67 -0
@@ -0,0 +1,229 @@
1
+ import { z } from 'zod';
2
+ import { getMap, getMapInfos, getMapEvent } from './mapTools.js';
3
+ import { validateEvent, validateEvents } from '../validation/eventCommands.js';
4
+ import { readJsonFile, readJsonArraySoft, getDataPath } from '../utils/fileHandler.js';
5
+ import { checkReferences } from '../validation/references.js';
6
+ import { checkAssets, } from '../validation/assets.js';
7
+ import { listAssets } from './assetTools.js';
8
+ /**
9
+ * Validate a single event's command lists against the known-command table.
10
+ * Warn-by-default: this reports problems, it never modifies anything.
11
+ */
12
+ export async function validateEventTool(projectPath, mapId, eventId) {
13
+ const event = await getMapEvent(projectPath, mapId, eventId);
14
+ if (!event) {
15
+ throw new Error(`Event ${eventId} not found on map ${mapId}`);
16
+ }
17
+ const report = validateEvent(event);
18
+ return { mapId, eventId, ...report };
19
+ }
20
+ /**
21
+ * Validate the event command lists of every map in the project. Aggregates each
22
+ * map's warnings, tagging them with the map ID so callers can locate them.
23
+ */
24
+ export async function validateProjectTool(projectPath) {
25
+ const infos = (await getMapInfos(projectPath));
26
+ const mapIds = infos.filter((info) => info != null).map((info) => info.id);
27
+ const warnings = [];
28
+ let mapsChecked = 0;
29
+ for (const mapId of mapIds) {
30
+ let map;
31
+ try {
32
+ map = await getMap(projectPath, mapId);
33
+ }
34
+ catch {
35
+ // A map listed in MapInfos may not have a MapNNN.json file yet; skip it.
36
+ continue;
37
+ }
38
+ mapsChecked++;
39
+ const report = validateEvents(map.events);
40
+ for (const warning of report.warnings) {
41
+ warnings.push({ mapId, ...warning });
42
+ }
43
+ }
44
+ return { ok: warnings.length === 0, mapsChecked, warnings };
45
+ }
46
+ /**
47
+ * Read a 1-indexed database array by filename, failing soft to `[]` if the file is
48
+ * absent. Thin (projectPath, file) convenience over the shared {@link readJsonArraySoft}.
49
+ */
50
+ async function loadArray(projectPath, file) {
51
+ return readJsonArraySoft(getDataPath(projectPath, file));
52
+ }
53
+ /**
54
+ * Load the whole project snapshot the reference linter needs. Every read fails
55
+ * soft: a missing/unreadable file yields an empty array (or `null` for
56
+ * `Animations.json`/`System.json`), so the audit degrades to fewer checks rather
57
+ * than throwing.
58
+ */
59
+ async function loadProjectData(projectPath) {
60
+ const mapInfos = await loadArray(projectPath, 'MapInfos.json');
61
+ const maps = [];
62
+ for (const info of mapInfos) {
63
+ if (!info)
64
+ continue;
65
+ try {
66
+ const map = await getMap(projectPath, info.id);
67
+ maps.push({ id: info.id, events: map.events });
68
+ }
69
+ catch {
70
+ // A map listed in MapInfos may not have a MapNNN.json file yet; skip it.
71
+ }
72
+ }
73
+ let animations = null;
74
+ try {
75
+ animations = await readJsonFile(getDataPath(projectPath, 'Animations.json'));
76
+ }
77
+ catch {
78
+ animations = null; // absent -> skip animation-id checks rather than flag everything
79
+ }
80
+ let system = null;
81
+ try {
82
+ system = await readJsonFile(getDataPath(projectPath, 'System.json'));
83
+ }
84
+ catch {
85
+ system = null;
86
+ }
87
+ return {
88
+ mapInfos,
89
+ maps,
90
+ actors: await loadArray(projectPath, 'Actors.json'),
91
+ classes: await loadArray(projectPath, 'Classes.json'),
92
+ skills: await loadArray(projectPath, 'Skills.json'),
93
+ items: await loadArray(projectPath, 'Items.json'),
94
+ weapons: await loadArray(projectPath, 'Weapons.json'),
95
+ armors: await loadArray(projectPath, 'Armors.json'),
96
+ enemies: await loadArray(projectPath, 'Enemies.json'),
97
+ troops: await loadArray(projectPath, 'Troops.json'),
98
+ states: await loadArray(projectPath, 'States.json'),
99
+ commonEvents: await loadArray(projectPath, 'CommonEvents.json'),
100
+ animations,
101
+ system,
102
+ };
103
+ }
104
+ /**
105
+ * Cross-file reference-integrity audit for the whole project. Read-only and
106
+ * warn-by-default: reports dangling/cyclic references (a Transfer Player to a
107
+ * missing map, a skill effect adding a non-existent state, a troop member for a
108
+ * deleted enemy, a cyclic map tree, …) without changing anything. Complements
109
+ * `validate_project`, which only checks event-command *shape*.
110
+ */
111
+ export async function validateReferencesTool(projectPath) {
112
+ const data = await loadProjectData(projectPath);
113
+ const warnings = checkReferences(data);
114
+ return { ok: warnings.length === 0, warnings };
115
+ }
116
+ /** The asset types the filename audit scans (a subset of list_assets' kinds). */
117
+ const AUDITED_ASSET_TYPES = [
118
+ 'characters',
119
+ 'faces',
120
+ 'sv_actors',
121
+ 'enemies',
122
+ 'tilesets',
123
+ 'titles1',
124
+ 'titles2',
125
+ 'battlebacks1',
126
+ 'battlebacks2',
127
+ 'parallaxes',
128
+ 'pictures',
129
+ 'bgm',
130
+ 'bgs',
131
+ 'me',
132
+ 'se',
133
+ ];
134
+ /**
135
+ * Enumerate the available basenames for every audited asset type into a lookup
136
+ * the pure checker can test against. `listAssets` fails soft (a missing dir →
137
+ * `[]`), so an unused asset kind maps to an empty set and its references are
138
+ * skipped rather than flagged.
139
+ */
140
+ async function buildAvailableAssets(projectPath) {
141
+ const assets = {};
142
+ for (const type of AUDITED_ASSET_TYPES) {
143
+ const { names } = await listAssets(projectPath, type);
144
+ assets[type] = new Set(names);
145
+ }
146
+ return assets;
147
+ }
148
+ /**
149
+ * Load the project records that carry asset-filename fields (the maps in full,
150
+ * for their map-level audio/images and event lists). Every read fails soft to an
151
+ * empty array (or `null` for `System.json`), so a missing file degrades the audit
152
+ * rather than throwing.
153
+ */
154
+ async function loadAssetData(projectPath) {
155
+ const mapInfos = await loadArray(projectPath, 'MapInfos.json');
156
+ const maps = [];
157
+ for (const info of mapInfos) {
158
+ if (!info)
159
+ continue;
160
+ try {
161
+ maps.push({ id: info.id, map: (await getMap(projectPath, info.id)) });
162
+ }
163
+ catch {
164
+ // A map listed in MapInfos may not have a MapNNN.json file yet; skip it.
165
+ }
166
+ }
167
+ let system = null;
168
+ try {
169
+ system = await readJsonFile(getDataPath(projectPath, 'System.json'));
170
+ }
171
+ catch {
172
+ system = null;
173
+ }
174
+ return {
175
+ actors: await loadArray(projectPath, 'Actors.json'),
176
+ enemies: await loadArray(projectPath, 'Enemies.json'),
177
+ tilesets: await loadArray(projectPath, 'Tilesets.json'),
178
+ maps,
179
+ troops: await loadArray(projectPath, 'Troops.json'),
180
+ commonEvents: await loadArray(projectPath, 'CommonEvents.json'),
181
+ system,
182
+ };
183
+ }
184
+ /**
185
+ * Project-wide asset-*filename* audit (read-only, warn-by-default). Scans every
186
+ * asset-name field across the database, maps, and system against the files that
187
+ * actually exist on disk, reporting each dangling reference — the systematic
188
+ * complement to the per-record create-time warnings (a `battlerName` typo would
189
+ * otherwise only surface as a runtime "Failed to load …" error). The *id*-
190
+ * integrity sibling is `validate_references`.
191
+ */
192
+ export async function validateAssetsTool(projectPath) {
193
+ const [data, assets] = await Promise.all([
194
+ loadAssetData(projectPath),
195
+ buildAvailableAssets(projectPath),
196
+ ]);
197
+ const warnings = checkAssets(data, assets);
198
+ return { ok: warnings.length === 0, warnings };
199
+ }
200
+ export const validationToolDefinitions = [
201
+ {
202
+ name: 'validate_event',
203
+ description: "Validate a single event's command lists against the known RPG Maker MZ command table. Read-only: reports parameter/structure warnings without changing anything.",
204
+ inputSchema: {
205
+ mapId: z.number().int().positive().describe('The ID of the map'),
206
+ eventId: z.number().int().positive().describe('The ID of the event to validate'),
207
+ },
208
+ handler: (ctx, args) => validateEventTool(ctx.projectPath, args.mapId, args.eventId),
209
+ },
210
+ {
211
+ name: 'validate_project',
212
+ description: 'Validate the event command lists of every map in the project. Read-only: returns aggregated, map-tagged warnings for auditing before or after a batch of edits.',
213
+ inputSchema: {},
214
+ handler: (ctx) => validateProjectTool(ctx.projectPath),
215
+ },
216
+ {
217
+ name: 'validate_references',
218
+ description: 'Audit cross-file reference integrity across the whole project (read-only, warn-by-default): Transfer Player targets and starting position point at existing maps; starting party, actor classes, class/enemy skills, troop members, enemy drops, and skill/item effects (states, learned skills, common events, animations) all resolve; and the map tree has no dangling or cyclic parentId. Complements validate_project (which checks command shape). Returns { ok, warnings[] }.',
219
+ inputSchema: {},
220
+ handler: (ctx) => validateReferencesTool(ctx.projectPath),
221
+ },
222
+ {
223
+ name: 'validate_assets',
224
+ description: 'Audit asset-filename integrity across the whole project (read-only, warn-by-default): every image/audio name field — actor characterName/faceName/battlerName, enemy battlerName, tileset sheets, map bgm/bgs/parallax/battlebacks, event page graphics, event Play BGM/BGS/ME/SE / Show Picture / Show Text face / Change Actor Images, and system titles/battlebacks/default audio/vehicle graphics — is checked against the files present under img/ and audio/. Catches a wrong filename (e.g. a battlerName with no matching img/enemies/*.png) before it becomes a runtime "Failed to load" error. An asset kind whose directory is empty/missing is skipped (not flagged). Complements validate_references (which checks id integrity). Returns { ok, warnings[] }.',
225
+ inputSchema: {},
226
+ handler: (ctx) => validateAssetsTool(ctx.projectPath),
227
+ },
228
+ ];
229
+ //# sourceMappingURL=validationTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validationTools.js","sourceRoot":"","sources":["../../src/tools/validationTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ /**
3
+ * A single leaf-level difference between the old and new file contents.
4
+ * `from` absent means the value was added; `to` absent means it was removed.
5
+ */
6
+ export interface ChangeRecord {
7
+ path: string;
8
+ from?: unknown;
9
+ to?: unknown;
10
+ }
11
+ export interface JsonDiff {
12
+ changes: ChangeRecord[];
13
+ /** True if the change list was capped (see MAX_CHANGES). */
14
+ truncated: boolean;
15
+ }
16
+ export interface CommitResult {
17
+ path: string;
18
+ changed: boolean;
19
+ dryRun: boolean;
20
+ diff: JsonDiff;
21
+ /** True when this commit deletes the file rather than writing it. */
22
+ deleted?: boolean;
23
+ }
24
+ /**
25
+ * Per-request commit context. `commitChange` reads it via AsyncLocalStorage so
26
+ * dry-run stays a cross-cutting concern: tool functions don't need a `dryRun`
27
+ * parameter threaded through their signatures. When `dryRun` is set, writes are
28
+ * skipped and every attempted change is collected in `commits` for the caller
29
+ * to report back as a preview.
30
+ */
31
+ export interface CommitContext {
32
+ dryRun: boolean;
33
+ commits: CommitResult[];
34
+ }
35
+ export declare const commitStore: AsyncLocalStorage<CommitContext>;
36
+ /**
37
+ * Structural diff between two JSON-serializable values. Recurses through arrays
38
+ * and plain objects, recording only the leaves that actually differ. Equal
39
+ * subtrees produce no records.
40
+ */
41
+ export declare function diffJson(oldValue: unknown, newValue: unknown): JsonDiff;
42
+ /**
43
+ * The single write choke point for all tool mutations. Computes the diff against
44
+ * the file's current contents, then:
45
+ * - in dry-run mode, records the diff and skips the write;
46
+ * - otherwise, writes only if something actually changed.
47
+ *
48
+ * Either way the result is pushed onto the active CommitContext (if any) so the
49
+ * dispatcher can surface a preview.
50
+ */
51
+ export declare function commitChange(filePath: string, newData: unknown): Promise<CommitResult>;
52
+ /**
53
+ * The deletion arm of the write choke point. Mirrors `commitChange` so that
54
+ * file removals participate in the same dry-run/preview machinery: in dry-run
55
+ * the deletion is recorded but not performed, otherwise the file is unlinked
56
+ * (only if it currently exists — a missing file is reported as `changed: false`
57
+ * and left alone). `changed` reflects whether the file existed to begin with,
58
+ * so a preview reads "this file would be deleted" rather than dumping the file's
59
+ * entire contents through `diffJson`.
60
+ */
61
+ export declare function commitDelete(filePath: string): Promise<CommitResult>;
62
+ //# sourceMappingURL=commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/utils/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIhD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,WAAW,kCAAyC,CAAC;AAUlE;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAoCvE;AAcD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAmB5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmB1E"}
@@ -0,0 +1,119 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ import { readFile } from 'fs/promises';
3
+ import { writeJsonFile, deleteFile, fileExists } from './fileHandler.js';
4
+ export const commitStore = new AsyncLocalStorage();
5
+ // Cap on reported leaf changes, so a wholesale rewrite (e.g. an entire repainted
6
+ // tile array) can't produce an enormous diff payload.
7
+ const MAX_CHANGES = 200;
8
+ function isPlainObject(value) {
9
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
10
+ }
11
+ /**
12
+ * Structural diff between two JSON-serializable values. Recurses through arrays
13
+ * and plain objects, recording only the leaves that actually differ. Equal
14
+ * subtrees produce no records.
15
+ */
16
+ export function diffJson(oldValue, newValue) {
17
+ const changes = [];
18
+ let truncated = false;
19
+ const record = (path, from, to) => {
20
+ if (changes.length >= MAX_CHANGES) {
21
+ truncated = true;
22
+ return;
23
+ }
24
+ const entry = { path };
25
+ if (from !== undefined)
26
+ entry.from = from;
27
+ if (to !== undefined)
28
+ entry.to = to;
29
+ changes.push(entry);
30
+ };
31
+ const walk = (path, oldVal, newVal) => {
32
+ if (oldVal === newVal)
33
+ return;
34
+ if (truncated)
35
+ return;
36
+ if (Array.isArray(oldVal) && Array.isArray(newVal)) {
37
+ const len = Math.max(oldVal.length, newVal.length);
38
+ for (let i = 0; i < len; i++) {
39
+ walk(`${path}[${i}]`, oldVal[i], newVal[i]);
40
+ }
41
+ }
42
+ else if (isPlainObject(oldVal) && isPlainObject(newVal)) {
43
+ const keys = new Set([...Object.keys(oldVal), ...Object.keys(newVal)]);
44
+ for (const key of keys) {
45
+ walk(path ? `${path}.${key}` : key, oldVal[key], newVal[key]);
46
+ }
47
+ }
48
+ else {
49
+ record(path, oldVal, newVal);
50
+ }
51
+ };
52
+ walk('', oldValue, newValue);
53
+ return { changes, truncated };
54
+ }
55
+ /** Read and parse the existing file, treating a missing file as no prior data. */
56
+ async function readOld(filePath) {
57
+ try {
58
+ return JSON.parse(await readFile(filePath, 'utf-8'));
59
+ }
60
+ catch (error) {
61
+ if (error.code === 'ENOENT') {
62
+ return undefined;
63
+ }
64
+ throw error;
65
+ }
66
+ }
67
+ /**
68
+ * The single write choke point for all tool mutations. Computes the diff against
69
+ * the file's current contents, then:
70
+ * - in dry-run mode, records the diff and skips the write;
71
+ * - otherwise, writes only if something actually changed.
72
+ *
73
+ * Either way the result is pushed onto the active CommitContext (if any) so the
74
+ * dispatcher can surface a preview.
75
+ */
76
+ export async function commitChange(filePath, newData) {
77
+ const context = commitStore.getStore();
78
+ const dryRun = context?.dryRun ?? false;
79
+ const oldData = await readOld(filePath);
80
+ const diff = diffJson(oldData, newData);
81
+ const result = {
82
+ path: filePath,
83
+ changed: diff.changes.length > 0,
84
+ dryRun,
85
+ diff,
86
+ };
87
+ if (!dryRun && result.changed) {
88
+ await writeJsonFile(filePath, newData);
89
+ }
90
+ context?.commits.push(result);
91
+ return result;
92
+ }
93
+ /**
94
+ * The deletion arm of the write choke point. Mirrors `commitChange` so that
95
+ * file removals participate in the same dry-run/preview machinery: in dry-run
96
+ * the deletion is recorded but not performed, otherwise the file is unlinked
97
+ * (only if it currently exists — a missing file is reported as `changed: false`
98
+ * and left alone). `changed` reflects whether the file existed to begin with,
99
+ * so a preview reads "this file would be deleted" rather than dumping the file's
100
+ * entire contents through `diffJson`.
101
+ */
102
+ export async function commitDelete(filePath) {
103
+ const context = commitStore.getStore();
104
+ const dryRun = context?.dryRun ?? false;
105
+ const existed = await fileExists(filePath);
106
+ const result = {
107
+ path: filePath,
108
+ changed: existed,
109
+ dryRun,
110
+ diff: { changes: [], truncated: false },
111
+ deleted: true,
112
+ };
113
+ if (!dryRun && existed) {
114
+ await deleteFile(filePath);
115
+ }
116
+ context?.commits.push(result);
117
+ return result;
118
+ }
119
+ //# sourceMappingURL=commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/utils/commit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Read and parse a JSON file from RPG Maker MZ project
3
+ */
4
+ export declare function readJsonFile<T>(filePath: string): Promise<T>;
5
+ /**
6
+ * Write JSON data to a file.
7
+ *
8
+ * RPG Maker MZ's editor saves its `data/*.json` files as compact, single-line
9
+ * JSON (no indentation). We match that format so that:
10
+ * - map tile arrays don't explode into thousands of lines, and
11
+ * - diffs stay minimal and consistent with what the editor itself writes,
12
+ * which keeps the per-session git-checkpoint workflow readable.
13
+ */
14
+ export declare function writeJsonFile(filePath: string, data: any): Promise<void>;
15
+ /**
16
+ * Read a 1-indexed database array file, failing soft only on a *missing* file
17
+ * (ENOENT → `[]`). Used by create-time reference checks that must degrade to
18
+ * "can't verify" (skip) instead of breaking on a project (or test fixture) that
19
+ * lacks the target file.
20
+ *
21
+ * A *corrupted* (present but malformed) file is a real error and throws — swallowing
22
+ * it would silently skip reference/troop validation on a broken project instead of
23
+ * surfacing the corruption. A parsed non-array value still yields `[]` (a wrong-typed
24
+ * file is treated as "no records" rather than crashing callers that expect an array).
25
+ */
26
+ export declare function readJsonArraySoft<T>(filePath: string): Promise<(T | null)[]>;
27
+ /**
28
+ * List all files in a directory with a specific extension
29
+ */
30
+ export declare function listFiles(dirPath: string, extension: string): Promise<string[]>;
31
+ /**
32
+ * Whether a file (or directory) exists at the given path.
33
+ */
34
+ export declare function fileExists(filePath: string): Promise<boolean>;
35
+ /**
36
+ * Delete a file. A missing file is treated as a no-op (the desired end state —
37
+ * the file being gone — already holds), so deletions stay idempotent.
38
+ */
39
+ export declare function deleteFile(filePath: string): Promise<void>;
40
+ /**
41
+ * Get the full path to a data file in RPG Maker MZ project
42
+ */
43
+ export declare function getDataPath(projectPath: string, fileName: string): string;
44
+ /**
45
+ * Get the full path to a map file in RPG Maker MZ project
46
+ */
47
+ export declare function getMapPath(projectPath: string, mapId: number): string;
48
+ export declare function validateProjectPath(projectPath: string): Promise<boolean>;
49
+ //# sourceMappingURL=fileHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileHandler.d.ts","sourceRoot":"","sources":["../../src/utils/fileHandler.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CASlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAYlF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOrF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrE;AAaD,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc/E"}
@@ -0,0 +1,137 @@
1
+ import { readFile, writeFile, readdir, access, unlink } from 'fs/promises';
2
+ import { join, extname } from 'path';
3
+ /**
4
+ * Read and parse a JSON file from RPG Maker MZ project
5
+ */
6
+ export async function readJsonFile(filePath) {
7
+ try {
8
+ const content = await readFile(filePath, 'utf-8');
9
+ return JSON.parse(content);
10
+ }
11
+ catch (error) {
12
+ // Unwrap the underlying Error's message so we don't nest `Error: …: Error: …`.
13
+ const detail = error instanceof Error ? error.message : String(error);
14
+ throw new Error(`Failed to read JSON file ${filePath}: ${detail}`);
15
+ }
16
+ }
17
+ /**
18
+ * Write JSON data to a file.
19
+ *
20
+ * RPG Maker MZ's editor saves its `data/*.json` files as compact, single-line
21
+ * JSON (no indentation). We match that format so that:
22
+ * - map tile arrays don't explode into thousands of lines, and
23
+ * - diffs stay minimal and consistent with what the editor itself writes,
24
+ * which keeps the per-session git-checkpoint workflow readable.
25
+ */
26
+ export async function writeJsonFile(filePath, data) {
27
+ try {
28
+ const jsonString = JSON.stringify(data);
29
+ await writeFile(filePath, jsonString, 'utf-8');
30
+ }
31
+ catch (error) {
32
+ throw new Error(`Failed to write JSON file ${filePath}: ${error}`);
33
+ }
34
+ }
35
+ /**
36
+ * Read a 1-indexed database array file, failing soft only on a *missing* file
37
+ * (ENOENT → `[]`). Used by create-time reference checks that must degrade to
38
+ * "can't verify" (skip) instead of breaking on a project (or test fixture) that
39
+ * lacks the target file.
40
+ *
41
+ * A *corrupted* (present but malformed) file is a real error and throws — swallowing
42
+ * it would silently skip reference/troop validation on a broken project instead of
43
+ * surfacing the corruption. A parsed non-array value still yields `[]` (a wrong-typed
44
+ * file is treated as "no records" rather than crashing callers that expect an array).
45
+ */
46
+ export async function readJsonArraySoft(filePath) {
47
+ let content;
48
+ try {
49
+ content = await readFile(filePath, 'utf-8');
50
+ }
51
+ catch (error) {
52
+ if (error.code === 'ENOENT') {
53
+ return [];
54
+ }
55
+ throw error;
56
+ }
57
+ const parsed = JSON.parse(content);
58
+ return Array.isArray(parsed) ? parsed : [];
59
+ }
60
+ /**
61
+ * List all files in a directory with a specific extension
62
+ */
63
+ export async function listFiles(dirPath, extension) {
64
+ try {
65
+ const files = await readdir(dirPath);
66
+ return files.filter((file) => extname(file) === extension);
67
+ }
68
+ catch (error) {
69
+ throw new Error(`Failed to list files in ${dirPath}: ${error}`);
70
+ }
71
+ }
72
+ /**
73
+ * Whether a file (or directory) exists at the given path.
74
+ */
75
+ export async function fileExists(filePath) {
76
+ try {
77
+ await access(filePath);
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ /**
85
+ * Delete a file. A missing file is treated as a no-op (the desired end state —
86
+ * the file being gone — already holds), so deletions stay idempotent.
87
+ */
88
+ export async function deleteFile(filePath) {
89
+ try {
90
+ await unlink(filePath);
91
+ }
92
+ catch (error) {
93
+ if (error.code === 'ENOENT')
94
+ return;
95
+ throw new Error(`Failed to delete file ${filePath}: ${error}`);
96
+ }
97
+ }
98
+ /**
99
+ * Get the full path to a data file in RPG Maker MZ project
100
+ */
101
+ export function getDataPath(projectPath, fileName) {
102
+ return join(projectPath, 'data', fileName);
103
+ }
104
+ /**
105
+ * Get the full path to a map file in RPG Maker MZ project
106
+ */
107
+ export function getMapPath(projectPath, mapId) {
108
+ const fileName = `Map${String(mapId).padStart(3, '0')}.json`;
109
+ return getDataPath(projectPath, fileName);
110
+ }
111
+ /**
112
+ * Validate RPG Maker MZ project path
113
+ */
114
+ /**
115
+ * Paths that have already validated successfully. A directory doesn't stop being
116
+ * an RPG Maker project mid-session, so the check is memoized after the first pass
117
+ * — every tool call would otherwise re-run it. Only successes are cached (a path
118
+ * that isn't yet a project might become one).
119
+ */
120
+ const validatedProjectPaths = new Set();
121
+ export async function validateProjectPath(projectPath) {
122
+ if (validatedProjectPaths.has(projectPath)) {
123
+ return true;
124
+ }
125
+ try {
126
+ // Check the essential files exist (access(), not a full read — we only need
127
+ // presence, not contents).
128
+ await access(join(projectPath, 'game.rmmzproject'));
129
+ await access(getDataPath(projectPath, 'System.json'));
130
+ validatedProjectPaths.add(projectPath);
131
+ return true;
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ }
137
+ //# sourceMappingURL=fileHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileHandler.js","sourceRoot":"","sources":["../../src/utils/fileHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Drop keys whose value is `undefined` so a caller's omitted optional field can't
3
+ * clobber a template default when spread over it. Used by every `create_*` tool
4
+ * that merges caller overrides onto a `default*()` template (`{ ...template,
5
+ * ...definedOnly(overrides), id }`).
6
+ */
7
+ export declare function definedOnly<T extends object>(obj: T): Partial<T>;
8
+ //# sourceMappingURL=records.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../src/utils/records.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhE"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Drop keys whose value is `undefined` so a caller's omitted optional field can't
3
+ * clobber a template default when spread over it. Used by every `create_*` tool
4
+ * that merges caller overrides onto a `default*()` template (`{ ...template,
5
+ * ...definedOnly(overrides), id }`).
6
+ */
7
+ export function definedOnly(obj) {
8
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
9
+ }
10
+ //# sourceMappingURL=records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/utils/records.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAmB,GAAM;IAClD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAe,CAAC;AAClG,CAAC"}