modwright 0.1.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 (455) hide show
  1. package/LICENSE +35 -0
  2. package/README.md +212 -0
  3. package/assets/claude/agents/mw-explore.md +46 -0
  4. package/assets/claude/agents/mw-fixture.md +33 -0
  5. package/assets/claude/agents/mw-rule-author.md +51 -0
  6. package/assets/claude/agents/mw-scaffold-author.md +48 -0
  7. package/assets/claude/skills/mw-author.md +59 -0
  8. package/assets/claude/skills/mw-new-item.md +51 -0
  9. package/assets/claude/skills/mw-new-spell.md +50 -0
  10. package/assets/claude/skills/mw-scaffold.md +59 -0
  11. package/assets/claude/skills/mw-ship.md +57 -0
  12. package/assets/claude/skills/mw-validate.md +51 -0
  13. package/assets/claude/skills/mw-verify.md +59 -0
  14. package/assets/nivalisnights/extract_resources.py +177 -0
  15. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Config.json +5 -0
  16. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapClient.lua +55 -0
  17. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapServer.lua +81 -0
  18. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Log.lua +96 -0
  19. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Probes.lua +1038 -0
  20. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/ProbesClient.lua +74 -0
  21. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Protocol.lua +985 -0
  22. package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Watch.lua +175 -0
  23. package/bridges/bg3-se/Mods/ModWrightBridge/meta.lsx +45 -0
  24. package/bridges/bg3-se/README.md +99 -0
  25. package/bridges/bg3-se/bridge.json +68 -0
  26. package/bridges/cp2077-cet/ModWrightBridge/init.lua +375 -0
  27. package/bridges/cp2077-cet/ModWrightBridge/probes.lua +1104 -0
  28. package/bridges/cp2077-cet/ModWrightBridge/protocol.lua +1306 -0
  29. package/bridges/cp2077-cet/README.md +165 -0
  30. package/bridges/cp2077-cet/bridge.json +53 -0
  31. package/dist/core/bridge/arm.js +175 -0
  32. package/dist/core/bridge/cet-console.js +26 -0
  33. package/dist/core/bridge/cet-log.js +362 -0
  34. package/dist/core/bridge/index.js +11 -0
  35. package/dist/core/bridge/locate.js +35 -0
  36. package/dist/core/bridge/paths.js +34 -0
  37. package/dist/core/bridge/pending.js +89 -0
  38. package/dist/core/bridge/poll.js +155 -0
  39. package/dist/core/bridge/stage.js +100 -0
  40. package/dist/core/bridge/status.js +97 -0
  41. package/dist/core/bridge/types.js +145 -0
  42. package/dist/core/bridge/validate.js +107 -0
  43. package/dist/core/build/index.js +6 -0
  44. package/dist/core/build/manifest.js +47 -0
  45. package/dist/core/build/paths.js +32 -0
  46. package/dist/core/build/run.js +342 -0
  47. package/dist/core/build/stage.js +265 -0
  48. package/dist/core/build/steps/bg3.js +129 -0
  49. package/dist/core/build/steps/core.js +195 -0
  50. package/dist/core/build/steps/cyberpunk.js +95 -0
  51. package/dist/core/build/steps/listing.js +35 -0
  52. package/dist/core/build/types.js +13 -0
  53. package/dist/core/build/zip.js +148 -0
  54. package/dist/core/compat/check.js +113 -0
  55. package/dist/core/compat/pe.js +220 -0
  56. package/dist/core/compat/types.js +1 -0
  57. package/dist/core/compat/version.js +70 -0
  58. package/dist/core/deploy/guards.js +292 -0
  59. package/dist/core/deploy/index.js +5 -0
  60. package/dist/core/deploy/plan.js +696 -0
  61. package/dist/core/deploy/reload-apply.js +361 -0
  62. package/dist/core/deploy/reload.js +358 -0
  63. package/dist/core/deploy/sources.js +169 -0
  64. package/dist/core/deploy/types.js +1 -0
  65. package/dist/core/epic.js +54 -0
  66. package/dist/core/fsutil.js +191 -0
  67. package/dist/core/home.js +70 -0
  68. package/dist/core/knowledge/facts.js +229 -0
  69. package/dist/core/knowledge/index.js +4 -0
  70. package/dist/core/knowledge/search.js +112 -0
  71. package/dist/core/knowledge/store.js +123 -0
  72. package/dist/core/knowledge/types.js +1 -0
  73. package/dist/core/ledger/check.js +42 -0
  74. package/dist/core/ledger/hooks.js +80 -0
  75. package/dist/core/ledger/index.js +7 -0
  76. package/dist/core/ledger/query.js +17 -0
  77. package/dist/core/ledger/record.js +84 -0
  78. package/dist/core/ledger/status.js +53 -0
  79. package/dist/core/ledger/store.js +98 -0
  80. package/dist/core/ledger/types.js +108 -0
  81. package/dist/core/logs/index.js +4 -0
  82. package/dist/core/logs/registry.js +50 -0
  83. package/dist/core/logs/scan.js +195 -0
  84. package/dist/core/logs/triage.js +160 -0
  85. package/dist/core/logs/types.js +1 -0
  86. package/dist/core/lsx.js +10 -0
  87. package/dist/core/lz4.js +66 -0
  88. package/dist/core/mods.js +229 -0
  89. package/dist/core/process.js +49 -0
  90. package/dist/core/project/build-steps.js +83 -0
  91. package/dist/core/project/describe.js +74 -0
  92. package/dist/core/project/index.js +5 -0
  93. package/dist/core/project/load.js +146 -0
  94. package/dist/core/project/schema.js +264 -0
  95. package/dist/core/project/types.js +3 -0
  96. package/dist/core/prompts.js +72 -0
  97. package/dist/core/registry.js +35 -0
  98. package/dist/core/safety/backup.js +206 -0
  99. package/dist/core/safety/execute.js +188 -0
  100. package/dist/core/safety/index.js +5 -0
  101. package/dist/core/safety/plan.js +122 -0
  102. package/dist/core/safety/restore.js +172 -0
  103. package/dist/core/safety/types.js +1 -0
  104. package/dist/core/scaffold/bootstrap.js +7 -0
  105. package/dist/core/scaffold/catalog.js +28 -0
  106. package/dist/core/scaffold/claude-assets.js +271 -0
  107. package/dist/core/scaffold/collisions.js +64 -0
  108. package/dist/core/scaffold/emit.js +356 -0
  109. package/dist/core/scaffold/engine.js +680 -0
  110. package/dist/core/scaffold/ids.js +78 -0
  111. package/dist/core/scaffold/index.js +10 -0
  112. package/dist/core/scaffold/jsonpath.js +121 -0
  113. package/dist/core/scaffold/load.js +81 -0
  114. package/dist/core/scaffold/render.js +85 -0
  115. package/dist/core/scaffold/sequence.js +396 -0
  116. package/dist/core/scaffold/types.js +309 -0
  117. package/dist/core/steam.js +63 -0
  118. package/dist/core/surfaceutil.js +36 -0
  119. package/dist/core/testplan/check.js +67 -0
  120. package/dist/core/testplan/index.js +5 -0
  121. package/dist/core/testplan/load.js +100 -0
  122. package/dist/core/testplan/registry.js +317 -0
  123. package/dist/core/testplan/run.js +389 -0
  124. package/dist/core/testplan/types.js +82 -0
  125. package/dist/core/text/converters/bg3.js +50 -0
  126. package/dist/core/text/converters/cyberpunk.js +36 -0
  127. package/dist/core/text/converters/index.js +261 -0
  128. package/dist/core/text/diff/cr2w.js +180 -0
  129. package/dist/core/text/diff/index.js +16 -0
  130. package/dist/core/text/diff/loca.js +43 -0
  131. package/dist/core/text/diff/lsx.js +126 -0
  132. package/dist/core/text/handles.js +86 -0
  133. package/dist/core/text/index.js +6 -0
  134. package/dist/core/text/json.js +46 -0
  135. package/dist/core/text/templates/cache.js +71 -0
  136. package/dist/core/text/templates/index.js +3 -0
  137. package/dist/core/text/templates/library.js +245 -0
  138. package/dist/core/text/templates/types.js +51 -0
  139. package/dist/core/text/toolchain.js +16 -0
  140. package/dist/core/text/types.js +1 -0
  141. package/dist/core/text/validate.js +149 -0
  142. package/dist/core/text/xml.js +58 -0
  143. package/dist/core/toolchain/datafetch.js +151 -0
  144. package/dist/core/toolchain/env.js +63 -0
  145. package/dist/core/toolchain/features.js +170 -0
  146. package/dist/core/toolchain/index.js +8 -0
  147. package/dist/core/toolchain/install.js +191 -0
  148. package/dist/core/toolchain/locate.js +275 -0
  149. package/dist/core/toolchain/remember.js +84 -0
  150. package/dist/core/toolchain/run.js +318 -0
  151. package/dist/core/toolchain/specs.js +351 -0
  152. package/dist/core/toolchain/types.js +1 -0
  153. package/dist/core/types.js +1 -0
  154. package/dist/core/userconfig.js +66 -0
  155. package/dist/core/validate/context.js +139 -0
  156. package/dist/core/validate/index.js +5 -0
  157. package/dist/core/validate/registry.js +58 -0
  158. package/dist/core/validate/run.js +131 -0
  159. package/dist/core/validate/suppressions.js +91 -0
  160. package/dist/core/validate/types.js +2 -0
  161. package/dist/core/yamledit.js +51 -0
  162. package/dist/index.js +389 -0
  163. package/dist/server.js +1914 -0
  164. package/dist/surfaces/baldursgate3/compat.js +164 -0
  165. package/dist/surfaces/baldursgate3/identity.js +110 -0
  166. package/dist/surfaces/baldursgate3/index/build.js +331 -0
  167. package/dist/surfaces/baldursgate3/index/index.js +17 -0
  168. package/dist/surfaces/baldursgate3/index/info.js +40 -0
  169. package/dist/surfaces/baldursgate3/index/parsers/loca.js +41 -0
  170. package/dist/surfaces/baldursgate3/index/parsers/lsx.js +137 -0
  171. package/dist/surfaces/baldursgate3/index/parsers/stats.js +45 -0
  172. package/dist/surfaces/baldursgate3/index/parsers/treasuretable.js +57 -0
  173. package/dist/surfaces/baldursgate3/index/parsers/xmlutil.js +142 -0
  174. package/dist/surfaces/baldursgate3/index/queries.js +327 -0
  175. package/dist/surfaces/baldursgate3/index/schema.js +62 -0
  176. package/dist/surfaces/baldursgate3/index.js +3 -0
  177. package/dist/surfaces/baldursgate3/logs.js +278 -0
  178. package/dist/surfaces/baldursgate3/modsettings.js +115 -0
  179. package/dist/surfaces/baldursgate3/pak.js +153 -0
  180. package/dist/surfaces/baldursgate3/settings.js +49 -0
  181. package/dist/surfaces/baldursgate3/surface.js +232 -0
  182. package/dist/surfaces/baldursgate3/validators/bridge.js +7 -0
  183. package/dist/surfaces/baldursgate3/validators/files.js +476 -0
  184. package/dist/surfaces/baldursgate3/validators/items.js +1001 -0
  185. package/dist/surfaces/baldursgate3/validators/progression.js +734 -0
  186. package/dist/surfaces/baldursgate3/validators/stats.js +1076 -0
  187. package/dist/surfaces/baldursgate3/validators/story.js +790 -0
  188. package/dist/surfaces/baldursgate3/validators/templates.js +7 -0
  189. package/dist/surfaces/cyberpunk2077/compat.js +223 -0
  190. package/dist/surfaces/cyberpunk2077/index/build.js +231 -0
  191. package/dist/surfaces/cyberpunk2077/index/index.js +17 -0
  192. package/dist/surfaces/cyberpunk2077/index/info.js +51 -0
  193. package/dist/surfaces/cyberpunk2077/index/model.js +52 -0
  194. package/dist/surfaces/cyberpunk2077/index/parsers/tweak.js +483 -0
  195. package/dist/surfaces/cyberpunk2077/index/parsers/tweakxl-yaml.js +183 -0
  196. package/dist/surfaces/cyberpunk2077/index/queries.js +504 -0
  197. package/dist/surfaces/cyberpunk2077/index/resource.js +135 -0
  198. package/dist/surfaces/cyberpunk2077/index/schema.js +90 -0
  199. package/dist/surfaces/cyberpunk2077/index.js +3 -0
  200. package/dist/surfaces/cyberpunk2077/logs.js +742 -0
  201. package/dist/surfaces/cyberpunk2077/paths.js +12 -0
  202. package/dist/surfaces/cyberpunk2077/surface.js +218 -0
  203. package/dist/surfaces/cyberpunk2077/validators/bridge.js +7 -0
  204. package/dist/surfaces/cyberpunk2077/validators/cr2w.js +349 -0
  205. package/dist/surfaces/cyberpunk2077/validators/garments.js +1181 -0
  206. package/dist/surfaces/cyberpunk2077/validators/mesh.js +338 -0
  207. package/dist/surfaces/cyberpunk2077/validators/modsettings.js +120 -0
  208. package/dist/surfaces/cyberpunk2077/validators/packaging.js +463 -0
  209. package/dist/surfaces/cyberpunk2077/validators/red4ext.js +318 -0
  210. package/dist/surfaces/cyberpunk2077/validators/redscript.js +193 -0
  211. package/dist/surfaces/cyberpunk2077/validators/templates.js +7 -0
  212. package/dist/surfaces/cyberpunk2077/validators/tweaks.js +768 -0
  213. package/dist/surfaces/cyberpunk2077/validators/vehicles.js +531 -0
  214. package/dist/surfaces/cyberpunk2077/validators/xl.js +308 -0
  215. package/dist/surfaces/eldenring/binders.js +111 -0
  216. package/dist/surfaces/eldenring/compat.js +166 -0
  217. package/dist/surfaces/eldenring/dcx.js +49 -0
  218. package/dist/surfaces/eldenring/index.js +13 -0
  219. package/dist/surfaces/eldenring/loaders.js +132 -0
  220. package/dist/surfaces/eldenring/logs.js +67 -0
  221. package/dist/surfaces/eldenring/paramdef.js +256 -0
  222. package/dist/surfaces/eldenring/params.js +129 -0
  223. package/dist/surfaces/eldenring/surface.js +121 -0
  224. package/dist/surfaces/eldenring/tools.js +52 -0
  225. package/dist/surfaces/eldenring/validators/binders.js +193 -0
  226. package/dist/surfaces/eldenring/validators/packages.js +159 -0
  227. package/dist/surfaces/eldenring/validators/params.js +334 -0
  228. package/dist/surfaces/eldenring/validators/profiles.js +287 -0
  229. package/dist/surfaces/index.js +34 -0
  230. package/dist/surfaces/nivalisnights/compat.js +229 -0
  231. package/dist/surfaces/nivalisnights/index/build.js +310 -0
  232. package/dist/surfaces/nivalisnights/index/index.js +5 -0
  233. package/dist/surfaces/nivalisnights/index/queries.js +231 -0
  234. package/dist/surfaces/nivalisnights/index.js +4 -0
  235. package/dist/surfaces/nivalisnights/logs.js +473 -0
  236. package/dist/surfaces/nivalisnights/surface.js +195 -0
  237. package/dist/surfaces/skyrimse/archives.js +229 -0
  238. package/dist/surfaces/skyrimse/compat.js +163 -0
  239. package/dist/surfaces/skyrimse/index.js +12 -0
  240. package/dist/surfaces/skyrimse/loadorder.js +174 -0
  241. package/dist/surfaces/skyrimse/logs.js +241 -0
  242. package/dist/surfaces/skyrimse/plugins.js +149 -0
  243. package/dist/surfaces/skyrimse/records.js +94 -0
  244. package/dist/surfaces/skyrimse/surface.js +240 -0
  245. package/dist/surfaces/skyrimse/validators/archive-records.js +165 -0
  246. package/dist/surfaces/skyrimse/validators/archives.js +110 -0
  247. package/dist/surfaces/skyrimse/validators/plugins.js +374 -0
  248. package/dist/surfaces/skyrimse/validators/records.js +117 -0
  249. package/dist/surfaces/stardewvalley/compat.js +190 -0
  250. package/dist/surfaces/stardewvalley/config.js +42 -0
  251. package/dist/surfaces/stardewvalley/contentpatcher.js +203 -0
  252. package/dist/surfaces/stardewvalley/index/index.js +229 -0
  253. package/dist/surfaces/stardewvalley/index/wiki.js +190 -0
  254. package/dist/surfaces/stardewvalley/index.js +12 -0
  255. package/dist/surfaces/stardewvalley/logs.js +307 -0
  256. package/dist/surfaces/stardewvalley/mods.js +182 -0
  257. package/dist/surfaces/stardewvalley/surface.js +244 -0
  258. package/dist/surfaces/stardewvalley/validators/content.js +321 -0
  259. package/dist/surfaces/stardewvalley/validators/fields.js +147 -0
  260. package/dist/surfaces/stardewvalley/validators/loadorder.js +69 -0
  261. package/dist/surfaces/stardewvalley/validators/manifest.js +221 -0
  262. package/dist/surfaces/subnautica2/compat.js +138 -0
  263. package/dist/surfaces/subnautica2/index.js +5 -0
  264. package/dist/surfaces/subnautica2/logs.js +129 -0
  265. package/dist/surfaces/subnautica2/paks.js +173 -0
  266. package/dist/surfaces/subnautica2/surface.js +151 -0
  267. package/dist/surfaces/subnautica2/validators/packaging.js +298 -0
  268. package/dist/surfaces/valheim/compat.js +171 -0
  269. package/dist/surfaces/valheim/index/index.js +301 -0
  270. package/dist/surfaces/valheim/index/tables.js +103 -0
  271. package/dist/surfaces/valheim/index.js +11 -0
  272. package/dist/surfaces/valheim/logs.js +197 -0
  273. package/dist/surfaces/valheim/packaging.js +131 -0
  274. package/dist/surfaces/valheim/plugins.js +270 -0
  275. package/dist/surfaces/valheim/references.js +121 -0
  276. package/dist/surfaces/valheim/surface.js +223 -0
  277. package/dist/surfaces/valheim/validators/packaging.js +218 -0
  278. package/dist/surfaces/valheim/validators/plugins.js +287 -0
  279. package/dist/surfaces/valheim/validators/references.js +169 -0
  280. package/knowledge/baldursgate3/animations.gr2.yaml +166 -0
  281. package/knowledge/baldursgate3/audio.voice.yaml +182 -0
  282. package/knowledge/baldursgate3/audio.wwise.yaml +104 -0
  283. package/knowledge/baldursgate3/charactercreation.heads-hair.yaml +193 -0
  284. package/knowledge/baldursgate3/communitylibrary.shared-content.yaml +129 -0
  285. package/knowledge/baldursgate3/compatibilityframework.api.yaml +176 -0
  286. package/knowledge/baldursgate3/crash.causes.yaml +90 -0
  287. package/knowledge/baldursgate3/dialogue.dialogbank.yaml +120 -0
  288. package/knowledge/baldursgate3/dialogue.files.yaml +236 -0
  289. package/knowledge/baldursgate3/dialogue.osiris-goals.yaml +386 -0
  290. package/knowledge/baldursgate3/dialogue.yaml +122 -0
  291. package/knowledge/baldursgate3/feats.classes.yaml +164 -0
  292. package/knowledge/baldursgate3/items.cloth-physics.yaml +167 -0
  293. package/knowledge/baldursgate3/items.roottemplates.yaml +320 -0
  294. package/knowledge/baldursgate3/items.visualbank.yaml +628 -0
  295. package/knowledge/baldursgate3/journal.quests.yaml +214 -0
  296. package/knowledge/baldursgate3/loadorder.modsettings.yaml +128 -0
  297. package/knowledge/baldursgate3/localization.handles.yaml +92 -0
  298. package/knowledge/baldursgate3/misc.encoding-and-practice.yaml +111 -0
  299. package/knowledge/baldursgate3/origins.companions.yaml +144 -0
  300. package/knowledge/baldursgate3/osiris.signatures.yaml +211 -0
  301. package/knowledge/baldursgate3/packaging.meta.yaml +155 -0
  302. package/knowledge/baldursgate3/packaging.paks.yaml +79 -0
  303. package/knowledge/baldursgate3/process.launch.yaml +34 -0
  304. package/knowledge/baldursgate3/progressions.yaml +92 -0
  305. package/knowledge/baldursgate3/publishing.modio-nexus.yaml +170 -0
  306. package/knowledge/baldursgate3/publishing.toolkit-modio.yaml +135 -0
  307. package/knowledge/baldursgate3/races.progression.yaml +228 -0
  308. package/knowledge/baldursgate3/scriptextender.console.yaml +257 -0
  309. package/knowledge/baldursgate3/scriptextender.yaml +252 -0
  310. package/knowledge/baldursgate3/stats.boosts.yaml +293 -0
  311. package/knowledge/baldursgate3/stats.equipment-kits.yaml +69 -0
  312. package/knowledge/baldursgate3/stats.interrupts.yaml +45 -0
  313. package/knowledge/baldursgate3/stats.itemcombos.yaml +65 -0
  314. package/knowledge/baldursgate3/stats.spells.yaml +293 -0
  315. package/knowledge/baldursgate3/stats.weapons.yaml +210 -0
  316. package/knowledge/baldursgate3/toolchain.divine.yaml +179 -0
  317. package/knowledge/baldursgate3/toolchain.lslib-formats.yaml +242 -0
  318. package/knowledge/baldursgate3/toolkit.levels.yaml +177 -0
  319. package/knowledge/baldursgate3/ui.icons-atlas.yaml +78 -0
  320. package/knowledge/baldursgate3/ui.icons.yaml +412 -0
  321. package/knowledge/baldursgate3/ui.mcm.yaml +161 -0
  322. package/knowledge/baldursgate3/vfx.materials.yaml +174 -0
  323. package/knowledge/baldursgate3/visuals.characterfix.yaml +73 -0
  324. package/knowledge/cyberpunk2077/animations.anims.yaml +118 -0
  325. package/knowledge/cyberpunk2077/anims.archivexl.yaml +163 -0
  326. package/knowledge/cyberpunk2077/anims.authoring.yaml +579 -0
  327. package/knowledge/cyberpunk2077/anims.encoder.yaml +156 -0
  328. package/knowledge/cyberpunk2077/anims.graph.yaml +629 -0
  329. package/knowledge/cyberpunk2077/anims.method.yaml +360 -0
  330. package/knowledge/cyberpunk2077/anims.pipeline.yaml +352 -0
  331. package/knowledge/cyberpunk2077/anims.roundtrip.yaml +222 -0
  332. package/knowledge/cyberpunk2077/anims.sets.yaml +176 -0
  333. package/knowledge/cyberpunk2077/archivexl.bodytypes.yaml +149 -0
  334. package/knowledge/cyberpunk2077/archivexl.dynamic-appearances.yaml +218 -0
  335. package/knowledge/cyberpunk2077/archivexl.manifest.yaml +214 -0
  336. package/knowledge/cyberpunk2077/audio.events.yaml +168 -0
  337. package/knowledge/cyberpunk2077/audio.sounds.yaml +164 -0
  338. package/knowledge/cyberpunk2077/audio.voicesets.yaml +146 -0
  339. package/knowledge/cyberpunk2077/cet.sandbox.yaml +219 -0
  340. package/knowledge/cyberpunk2077/clothing.garments.yaml +283 -0
  341. package/knowledge/cyberpunk2077/clothing.refits.yaml +215 -0
  342. package/knowledge/cyberpunk2077/codeware.overview.yaml +111 -0
  343. package/knowledge/cyberpunk2077/codeware.systems.yaml +192 -0
  344. package/knowledge/cyberpunk2077/drones.combat.yaml +416 -0
  345. package/knowledge/cyberpunk2077/drones.control.yaml +552 -0
  346. package/knowledge/cyberpunk2077/entities.appearance.yaml +166 -0
  347. package/knowledge/cyberpunk2077/equipmentex.slots.yaml +151 -0
  348. package/knowledge/cyberpunk2077/fx.effects.yaml +246 -0
  349. package/knowledge/cyberpunk2077/fx.lights.yaml +171 -0
  350. package/knowledge/cyberpunk2077/hair.modding.yaml +145 -0
  351. package/knowledge/cyberpunk2077/items.wiring.yaml +246 -0
  352. package/knowledge/cyberpunk2077/loadorder.archives.yaml +71 -0
  353. package/knowledge/cyberpunk2077/mesh.blender.yaml +209 -0
  354. package/knowledge/cyberpunk2077/nativedb.dump.yaml +98 -0
  355. package/knowledge/cyberpunk2077/npc.appearance.yaml +275 -0
  356. package/knowledge/cyberpunk2077/npc.behaviour.yaml +128 -0
  357. package/knowledge/cyberpunk2077/npc.locomotion.yaml +490 -0
  358. package/knowledge/cyberpunk2077/packaging.deploy.yaml +175 -0
  359. package/knowledge/cyberpunk2077/packaging.variants.yaml +176 -0
  360. package/knowledge/cyberpunk2077/player.control.yaml +918 -0
  361. package/knowledge/cyberpunk2077/process.assetbuild.yaml +154 -0
  362. package/knowledge/cyberpunk2077/process.lessons.yaml +276 -0
  363. package/knowledge/cyberpunk2077/quests.minor.yaml +46 -0
  364. package/knowledge/cyberpunk2077/quests.scenes.yaml +282 -0
  365. package/knowledge/cyberpunk2077/quickhacks.tiers.yaml +41 -0
  366. package/knowledge/cyberpunk2077/red4ext.api.yaml +645 -0
  367. package/knowledge/cyberpunk2077/red4ext.plugins.yaml +124 -0
  368. package/knowledge/cyberpunk2077/redhottools.hotreload.yaml +245 -0
  369. package/knowledge/cyberpunk2077/redscript.compile-log.yaml +76 -0
  370. package/knowledge/cyberpunk2077/redscript.modules.yaml +118 -0
  371. package/knowledge/cyberpunk2077/toolchain.wolvenkit.yaml +163 -0
  372. package/knowledge/cyberpunk2077/tweakdb.loot-recipes.yaml +184 -0
  373. package/knowledge/cyberpunk2077/tweakdb.melee.yaml +352 -0
  374. package/knowledge/cyberpunk2077/tweakdb.weapons.yaml +325 -0
  375. package/knowledge/cyberpunk2077/tweakxl.hotreload.yaml +151 -0
  376. package/knowledge/cyberpunk2077/tweakxl.yaml-syntax.yaml +208 -0
  377. package/knowledge/cyberpunk2077/ui.icons.yaml +259 -0
  378. package/knowledge/cyberpunk2077/ui.inkatlas.yaml +81 -0
  379. package/knowledge/cyberpunk2077/ui.modsettings.yaml +204 -0
  380. package/knowledge/cyberpunk2077/vehicles.control.yaml +475 -0
  381. package/knowledge/cyberpunk2077/vehicles.dashboard-ui.yaml +203 -0
  382. package/knowledge/cyberpunk2077/vehicles.entities.yaml +195 -0
  383. package/knowledge/cyberpunk2077/vehicles.wiring.yaml +137 -0
  384. package/knowledge/cyberpunk2077/wolvenkit.cli.yaml +167 -0
  385. package/knowledge/cyberpunk2077/workspot.system.yaml +55 -0
  386. package/knowledge/cyberpunk2077/world.interactions.yaml +41 -0
  387. package/knowledge/cyberpunk2077/world.loot-container.yaml +167 -0
  388. package/knowledge/cyberpunk2077/world.sectors.yaml +233 -0
  389. package/knowledge/eldenring/formats.binders.yaml +237 -0
  390. package/knowledge/eldenring/launcher.me3.yaml +230 -0
  391. package/knowledge/eldenring/launcher.modengine2.yaml +119 -0
  392. package/knowledge/eldenring/params.paramdef.yaml +149 -0
  393. package/knowledge/eldenring/params.regulation.yaml +142 -0
  394. package/knowledge/eldenring/saves.online.yaml +118 -0
  395. package/knowledge/eldenring/toolchain.cli.yaml +256 -0
  396. package/knowledge/nivalisnights/modding.runtime.yaml +157 -0
  397. package/knowledge/skyrimse/archives.bsa.yaml +212 -0
  398. package/knowledge/skyrimse/install.detection.yaml +41 -0
  399. package/knowledge/skyrimse/loadorder.files.yaml +242 -0
  400. package/knowledge/skyrimse/plugins.esl.yaml +189 -0
  401. package/knowledge/skyrimse/plugins.format.yaml +224 -0
  402. package/knowledge/skyrimse/skse.runtime.yaml +283 -0
  403. package/knowledge/skyrimse/toolchain.xedit-spriggit.yaml +336 -0
  404. package/knowledge/stardewvalley/contentpatcher.format.yaml +338 -0
  405. package/knowledge/stardewvalley/distribution.channels.yaml +236 -0
  406. package/knowledge/stardewvalley/game.versions.yaml +202 -0
  407. package/knowledge/stardewvalley/install.layout.yaml +277 -0
  408. package/knowledge/stardewvalley/smapi.loader.yaml +284 -0
  409. package/knowledge/stardewvalley/smapi.logs.yaml +329 -0
  410. package/knowledge/stardewvalley/smapi.manifest.yaml +293 -0
  411. package/knowledge/stardewvalley/toolchain.build.yaml +261 -0
  412. package/knowledge/stardewvalley/wiki.dataformat.yaml +130 -0
  413. package/knowledge/subnautica2/game.build.yaml +331 -0
  414. package/knowledge/subnautica2/modding.state.yaml +210 -0
  415. package/knowledge/subnautica2/ue5.containers.yaml +72 -0
  416. package/knowledge/subnautica2/ue5.paks.yaml +203 -0
  417. package/knowledge/subnautica2/ue5.tooling.yaml +175 -0
  418. package/knowledge/subnautica2/ue5.ue4ss.yaml +203 -0
  419. package/knowledge/valheim/bepinex.loader.yaml +247 -0
  420. package/knowledge/valheim/bepinex.plugins.yaml +251 -0
  421. package/knowledge/valheim/game.versions.yaml +321 -0
  422. package/knowledge/valheim/install.layout.yaml +216 -0
  423. package/knowledge/valheim/jotunn.library.yaml +334 -0
  424. package/knowledge/valheim/thunderstore.packaging.yaml +217 -0
  425. package/knowledge/valheim/toolchain.build.yaml +111 -0
  426. package/package.json +29 -0
  427. package/scaffolds/baldursgate3/new-class-injection.yaml +148 -0
  428. package/scaffolds/baldursgate3/new-item.yaml +264 -0
  429. package/scaffolds/baldursgate3/new-mod.yaml +174 -0
  430. package/scaffolds/baldursgate3/new-passive.yaml +100 -0
  431. package/scaffolds/baldursgate3/new-project.yaml +118 -0
  432. package/scaffolds/baldursgate3/new-quest-stub.yaml +159 -0
  433. package/scaffolds/baldursgate3/new-spell.yaml +102 -0
  434. package/scaffolds/baldursgate3/new-status.yaml +119 -0
  435. package/scaffolds/baldursgate3/sequences/subclass-kit.yaml +50 -0
  436. package/scaffolds/cyberpunk2077/edit-tweak.yaml +70 -0
  437. package/scaffolds/cyberpunk2077/mesh-export-preset.yaml +170 -0
  438. package/scaffolds/cyberpunk2077/new-entity-patch.yaml +255 -0
  439. package/scaffolds/cyberpunk2077/new-garment-refit.yaml +279 -0
  440. package/scaffolds/cyberpunk2077/new-item-chain.yaml +548 -0
  441. package/scaffolds/cyberpunk2077/new-localization.yaml +130 -0
  442. package/scaffolds/cyberpunk2077/new-mod-settings.yaml +133 -0
  443. package/scaffolds/cyberpunk2077/new-player-replacer.yaml +1003 -0
  444. package/scaffolds/cyberpunk2077/new-project.yaml +157 -0
  445. package/scaffolds/cyberpunk2077/new-sector-node.yaml +156 -0
  446. package/scaffolds/cyberpunk2077/new-tweak.yaml +121 -0
  447. package/scaffolds/cyberpunk2077/new-vehicle-livery.yaml +148 -0
  448. package/scaffolds/cyberpunk2077/new-workspot-entity.yaml +177 -0
  449. package/scaffolds/cyberpunk2077/sequences/iconic-weapon.yaml +72 -0
  450. package/scaffolds/cyberpunk2077/sequences/quickhack-takeover.yaml +213 -0
  451. package/scaffolds/stardewvalley/new-cp-patch.yaml +106 -0
  452. package/scaffolds/stardewvalley/new-csharp-mod.yaml +195 -0
  453. package/scaffolds/stardewvalley/new-project.yaml +184 -0
  454. package/scaffolds/stardewvalley/sequences/content-pack.yaml +31 -0
  455. package/scripts/mw-tool.mjs +184 -0
@@ -0,0 +1,195 @@
1
+ # new-csharp-mod (Stardew Valley). Adds a SMAPI C# mod project to an existing Stardew Valley ModWright
2
+ # project: a `src/<name>/` folder holding the `.csproj` the wiki's IDE
3
+ # reference gives (Microsoft.NET.Sdk, net6.0, the Pathoschild.Stardew.ModBuildConfig
4
+ # package reference), the Get Started guide's ModEntry.cs and manifest.json
5
+ # (with the literal version rather than `%ProjectVersion%`, see below), and the
6
+ # project source and dependencies that make the manifest visible to the
7
+ # surface's rules.
8
+ #
9
+ # Two things this scaffold decides for the author:
10
+ # `<EnableModDeploy>false</EnableModDeploy>` and `<EnableModZip>false</EnableModZip>`
11
+ # are set, so the build package does not copy the mod into the game's Mods
12
+ # folder on every build and ModWright's own safety-backed deploy is the one
13
+ # path that writes there. Note the cost: with both off,
14
+ # the package's deploy task returns before it reads the manifest, so it never
15
+ # substitutes `%ProjectVersion%` and never assembles a mod folder — the build
16
+ # output is the DLL alone. The manual checklist carries what that leaves the
17
+ # author to do until a Stardew deploy target exists.
18
+ # Building needs the game installed (the package
19
+ # refuses without `Stardew Valley.dll` and `StardewModdingAPI.dll` beside the
20
+ # game), so the DLL the manifest names is a build output
21
+ # and never sits beside the source manifest; the surface's entrydll-exists
22
+ # rule reports that as an info for a manifest with a .csproj beside it, not
23
+ # as the block a deployed manifest without its DLL gets.
24
+ id: stardewvalley.new-csharp-mod
25
+ game: stardewvalley
26
+ title: New SMAPI C# mod project
27
+ summary: Add a SMAPI C# mod under src/<name>/ — the wiki's .csproj (net6.0, ModBuildConfig, deploy and zip handed to ModWright), the Get Started ModEntry.cs and manifest.json — and register it as a project source with the dotnet and SMAPI dependencies.
28
+ modTypes: [plugin, packaging]
29
+ needs: {}
30
+ inputs:
31
+ - type: string
32
+ name: name
33
+ prompt: Project name (also the assembly, root namespace, folder and EntryDll name; a C# identifier).
34
+ pattern: "^[A-Za-z][A-Za-z0-9_]*$"
35
+ - type: string
36
+ name: uniqueId
37
+ prompt: The manifest UniqueID, YourName.YourModName (letters, numbers, underscores, periods, hyphens; never changed once published).
38
+ pattern: "^[a-zA-Z0-9_.-]+$"
39
+ - type: string
40
+ name: author
41
+ prompt: Author name (no quotes or backslashes; it is written into JSON).
42
+ default: "Unknown"
43
+ pattern: '^[^"\\\x00-\x1f]+$'
44
+ - type: string
45
+ name: version
46
+ prompt: Initial version (major.minor.patch); written to both the .csproj and the manifest, which are bumped together.
47
+ default: "1.0.0"
48
+ pattern: "^(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)(?:\\.(?:0|[1-9][0-9]*))?(?:-(?:[a-zA-Z0-9]+[-.]?)+)?$"
49
+ - type: string
50
+ name: description
51
+ prompt: One or two sentences about the mod (no quotes or backslashes; it is written into JSON).
52
+ default: "One or two sentences about the mod."
53
+ pattern: '^[^"\\\x00-\x1f]+$'
54
+ ids: []
55
+ emits:
56
+ - op: ensure-dir
57
+ path: "src/${input.name}"
58
+ # The .csproj: the IDE reference's example (Sdk, AssemblyName, RootNamespace,
59
+ # Version, TargetFramework net6.0, the package reference) with the package
60
+ # at its current version and the two deploy/zip toggles.
61
+ - op: write-text
62
+ path: "src/${input.name}/${input.name}.csproj"
63
+ body: |
64
+ <Project Sdk="Microsoft.NET.Sdk">
65
+ <PropertyGroup>
66
+ <AssemblyName>${input.name}</AssemblyName>
67
+ <RootNamespace>${input.name}</RootNamespace>
68
+ <Version>${input.version}</Version>
69
+ <TargetFramework>net6.0</TargetFramework>
70
+ <!-- ModWright owns deploy and zip: the package would otherwise copy into Mods/ on every build. -->
71
+ <EnableModDeploy>false</EnableModDeploy>
72
+ <EnableModZip>false</EnableModZip>
73
+ </PropertyGroup>
74
+
75
+ <ItemGroup>
76
+ <PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.4.0" />
77
+ </ItemGroup>
78
+ </Project>
79
+ # ModEntry.cs: the Get Started guide's first mod, with the project name as
80
+ # its namespace.
81
+ - op: write-text
82
+ path: "src/${input.name}/ModEntry.cs"
83
+ body: |
84
+ using System;
85
+ using Microsoft.Xna.Framework;
86
+ using StardewModdingAPI;
87
+ using StardewModdingAPI.Events;
88
+ using StardewModdingAPI.Utilities;
89
+ using StardewValley;
90
+
91
+ namespace ${input.name}
92
+ {
93
+ /// <summary>The mod entry point.</summary>
94
+ internal sealed class ModEntry : Mod
95
+ {
96
+ /*********
97
+ ** Public methods
98
+ *********/
99
+ /// <summary>The mod entry point, called after the mod is first loaded.</summary>
100
+ /// <param name="helper">Provides simplified APIs for writing mods.</param>
101
+ public override void Entry(IModHelper helper)
102
+ {
103
+ helper.Events.Input.ButtonPressed += this.OnButtonPressed;
104
+ }
105
+
106
+
107
+ /*********
108
+ ** Private methods
109
+ *********/
110
+ /// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary>
111
+ /// <param name="sender">The event sender.</param>
112
+ /// <param name="e">The event data.</param>
113
+ private void OnButtonPressed(object? sender, ButtonPressedEventArgs e)
114
+ {
115
+ // ignore if player hasn't loaded a save yet
116
+ if (!Context.IsWorldReady)
117
+ return;
118
+
119
+ // print button presses to the console window
120
+ this.Monitor.Log($"{Game1.player.Name} pressed {e.Button}.", LogLevel.Debug);
121
+ }
122
+ }
123
+ }
124
+ # manifest.json: the Get Started guide's manifest, field for field, with
125
+ # the literal version the guide itself uses. The mod-package doc's
126
+ # %ProjectVersion% token is substituted only when the package deploys or
127
+ # zips, and with both toggles off (header comment) it never does, so the
128
+ # token would reach SMAPI unreplaced and the mod would be refused.
129
+ - op: write-text
130
+ path: "src/${input.name}/manifest.json"
131
+ body: |
132
+ {
133
+ "Name": "${input.name}",
134
+ "Author": "${input.author}",
135
+ "Version": "${input.version}",
136
+ "Description": "${input.description}",
137
+ "UniqueID": "${input.uniqueId}",
138
+ "EntryDll": "${input.name}.dll",
139
+ "MinimumApiVersion": "4.0.0",
140
+ "UpdateKeys": []
141
+ }
142
+ - op: patch-project
143
+ add:
144
+ sources:
145
+ - id: "src-${input.name}"
146
+ path: "src/${input.name}"
147
+ kind: source
148
+ dependencies:
149
+ - id: dotnet
150
+ kind: tool
151
+ minVersion: "6.0"
152
+ url: "https://dotnet.microsoft.com/download"
153
+ notes: "`dotnet build -c Release` in src/<name>; the build package needs the game and SMAPI installed to resolve Stardew Valley.dll and StardewModdingAPI.dll."
154
+ - id: smapi
155
+ kind: loader
156
+ minVersion: "4.0.0"
157
+ url: "https://smapi.io"
158
+ notes: "MinimumApiVersion in the manifest; the mod loads only through StardewModdingAPI."
159
+ templates: []
160
+ # The manifest rules the source manifest must pass. entrydll-exists is not
161
+ # listed: for a manifest with a .csproj beside it the rule reports the
162
+ # missing DLL as an info (it is a build output), which is expected here.
163
+ satisfies:
164
+ - stardewvalley.manifest.parses
165
+ - stardewvalley.manifest.required-fields
166
+ - stardewvalley.manifest.entry-or-content-pack
167
+ - stardewvalley.manifest.uniqueid
168
+ - stardewvalley.manifest.version
169
+ - stardewvalley.manifest.minimum-versions
170
+ - stardewvalley.manifest.extra-fields
171
+ manual:
172
+ - title: Build against the installed game
173
+ steps:
174
+ - "With the game and SMAPI installed, run `dotnet build -c Release` in src/<name>; the package finds the game folder itself (or set GamePath, see https://smapi.io/package/custom-game-path)."
175
+ - "The build output is bin/Release/net6.0/<name>.dll and nothing else: with EnableModDeploy and EnableModZip both false the package's deploy task returns before it reads the manifest, so there is no deployed folder, no release zip, and no %ProjectVersion% substitution anywhere."
176
+ expected: "The build succeeds with no 'Any CPU' warning; bin/Release/net6.0 holds <name>.dll (manifest.json is not copied there)."
177
+ - title: Check in game
178
+ steps:
179
+ - "Assemble Mods/<name> by hand, since no deploy target is configured on this game yet: the built <name>.dll plus this project's manifest.json as it is (its Version is the literal the .csproj carries; bump both together). Alternatively set <EnableModZip>true</EnableModZip> for one build and unzip the '<name> <version>.zip' the package then writes into bin/Release/net6.0, which still never writes into Mods/."
180
+ - "Launch StardewModdingAPI.exe and press any key in game: the SMAPI console shows '<player> pressed <button>' at Debug level (the Get Started example's behaviour)."
181
+ expected: "SMAPI's log lists the mod in its 'Loaded N mods' block with no skipped-mods entry."
182
+ claim:
183
+ idSuffix: csharp-mod
184
+ claim: "${input.name} is a SMAPI C# mod project under src/${input.name} (UniqueID ${input.uniqueId}, net6.0, ModBuildConfig 4.4.0 with deploy and zip handed to ModWright)."
185
+ testRows:
186
+ - gate: S-0
187
+ title: "Mod builds and loads"
188
+ expected: "dotnet build succeeds against the installed game; SMAPI's log lists the mod with no skipped-mods entry and the button-press line appears at Debug."
189
+ manual: true
190
+ probeKinds: []
191
+ evidence:
192
+ - "stardewvalley.toolchain.build.modbuildconfig-package"
193
+ - "stardewvalley.toolchain.build.deploy-and-zip-properties"
194
+ - "stardewvalley.toolchain.build.requires-the-game-installed"
195
+ - "stardewvalley.smapi.manifest.project-version-token"
@@ -0,0 +1,184 @@
1
+ # new-project (Stardew Valley). A `new-content-pack`, carried under the `new-project` id because the
2
+ # `scaffold` tool bootstraps a project only for an id ending in
3
+ # `.new-project` (src/server.ts), and a Content Patcher pack is the first
4
+ # project on this game: it needs no toolchain, no compiler and no game
5
+ # to author. Writes the pack the Content Patcher author
6
+ # guide's quick-start describes — a `[CP] <name>` folder with
7
+ # `manifest.json`, `content.json` and an `assets/` folder — plus the
8
+ # ModWright project around it. tests/authored.yaml and ledger/claims.yaml
9
+ # come from the engine's own per-apply steps, not an emit here.
10
+ #
11
+ # The pack is not empty: Content Patcher rejects a pack whose `Changes`
12
+ # and `CustomLocations` are both empty ("content pack must specify the
13
+ # Changes or CustomLocations fields"), so the quick-
14
+ # start's `"Changes": [ // your changes will go here ]` would be refused
15
+ # at load. The one starter patch is the wiki's own Mail data example
16
+ # shape: an EditData on `Data/mail` adding a `{{ModId}}_`-prefixed letter,
17
+ # which the 1.6 unique-string-ID convention asks for and which reaches no
18
+ # player until something sends it ("This letter will have to be sent in a
19
+ # separate patch", Modding:Mail data). Replacing it is the first manual
20
+ # step.
21
+ id: stardewvalley.new-project
22
+ game: stardewvalley
23
+ title: New Stardew Valley content pack project
24
+ summary: Scaffold a fresh ModWright project holding one Content Patcher content pack — modwright.json (schemaVersion 2), the [CP] <name> folder with manifest.json, content.json (Format 2.9.0, one starter Data/mail patch) and assets/, .gitignore, and ledger/decisions.yaml.
25
+ modTypes: [content-pack, packaging]
26
+ needs: {}
27
+ inputs:
28
+ - type: string
29
+ name: name
30
+ prompt: Mod name (the pack folder is "[CP] <name>", the author guide's convention).
31
+ pattern: "^[A-Za-z][A-Za-z0-9_-]*$"
32
+ - type: string
33
+ name: uniqueId
34
+ prompt: The manifest UniqueID, YourName.YourModName (letters, numbers, underscores, periods, hyphens; never changed once published).
35
+ pattern: "^[a-zA-Z0-9_.-]+$"
36
+ # author and description are the only free-text inputs that land inside a
37
+ # JSON string literal in a hand-written `write-text` body (every other one
38
+ # is already pattern-guarded). A `"` or `\` in either would emit a
39
+ # manifest.json that is not JSON at all — SMAPI then reports the mod as
40
+ # "parsing its manifest failed" and loads nothing — so they are refused up
41
+ # front rather than written and reported afterwards. Control characters go
42
+ # with them: a raw tab or newline inside a JSON string is invalid too.
43
+ - type: string
44
+ name: author
45
+ prompt: Author name (no double quotes or backslashes — it is written into manifest.json as-is).
46
+ default: "Unknown"
47
+ pattern: '^[^"\\\x00-\x1f]+$'
48
+ - type: string
49
+ name: version
50
+ prompt: Initial version (major.minor.patch, as SMAPI parses it).
51
+ default: "1.0.0"
52
+ pattern: "^(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)(?:\\.(?:0|[1-9][0-9]*))?(?:-(?:[a-zA-Z0-9]+[-.]?)+)?$"
53
+ - type: string
54
+ name: description
55
+ prompt: One or two sentences about the mod (the manifest Description; no double quotes or backslashes).
56
+ default: "One or two sentences about the mod."
57
+ pattern: '^[^"\\\x00-\x1f]+$'
58
+ ids: []
59
+ emits:
60
+ - op: ensure-dir
61
+ path: "[CP] ${input.name}/assets"
62
+ - op: write-text
63
+ path: ".gitignore"
64
+ ifExists: skip
65
+ # The same shape as the other two new-project scaffolds: suppressions.json
66
+ # and templates/manifest.json stay tracked so a reviewer reads them in a
67
+ # clean checkout, and the build manifest a later build step writes is
68
+ # ignored wherever outDir points.
69
+ body: |
70
+ .modwright/*
71
+ !.modwright/suppressions.json
72
+ !.modwright/templates/
73
+ .modwright/templates/*
74
+ !.modwright/templates/manifest.json
75
+ build/
76
+ .modwright-build-manifest.json
77
+ - op: write-text
78
+ path: "ledger/decisions.yaml"
79
+ body: |
80
+ decisions: []
81
+ # The project: one source of kind "content-pack" covering the pack
82
+ # folder, so every manifest and content rule sees the two files (the
83
+ # lesson cyberpunk2077/new-project.yaml records: a file outside every
84
+ # declared source is invisible to file-scoped rules). No build and no
85
+ # deploy yet: a Stardew deploy target is not built, and a content pack has
86
+ # nothing to compile — the pack folder is what gets copied into Mods/.
87
+ - op: write-text
88
+ path: "modwright.json"
89
+ body: |
90
+ {
91
+ "schemaVersion": 2,
92
+ "name": "${input.name}",
93
+ "game": "stardewvalley",
94
+ "version": "${input.version}",
95
+ "authors": ["${input.author}"],
96
+ "sources": [
97
+ { "id": "pack", "path": "[CP] ${input.name}", "kind": "content-pack" }
98
+ ]
99
+ }
100
+ # manifest.json: the author guide's quick-start manifest, field for
101
+ # field (Name, Author, Version, Description, UniqueID, UpdateKeys,
102
+ # ContentPackFor). UpdateKeys stays empty until the mod has a page; the
103
+ # guide's own comment on that line points at the update-checks wiki page.
104
+ - op: write-text
105
+ path: "[CP] ${input.name}/manifest.json"
106
+ body: |
107
+ {
108
+ "Name": "${input.name}",
109
+ "Author": "${input.author}",
110
+ "Version": "${input.version}",
111
+ "Description": "${input.description}",
112
+ "UniqueID": "${input.uniqueId}",
113
+ "UpdateKeys": [],
114
+ "ContentPackFor": {
115
+ "UniqueID": "Pathoschild.ContentPatcher"
116
+ }
117
+ }
118
+ # content.json: the quick-start's Format, the schema line the
119
+ # troubleshooting guide recommends for editors, and the one starter patch
120
+ # (see the header comment). `^` is a line break and `@` the player's name
121
+ # in mail text; `[#]` ends the body and names the letter.
122
+ - op: write-text
123
+ path: "[CP] ${input.name}/content.json"
124
+ body: |
125
+ {
126
+ "$schema": "https://smapi.io/schemas/content-patcher.json",
127
+ "Format": "2.9.0",
128
+ "Changes": [
129
+ {
130
+ "LogName": "Welcome letter",
131
+ "Action": "EditData",
132
+ "Target": "Data/mail",
133
+ "Entries": {
134
+ "{{ModId}}_Welcome": "Hi @,^^This letter was added by the ${input.name} content pack. Replace this patch with your first real change.^^ -${input.author}[#]Welcome from ${input.name}"
135
+ }
136
+ }
137
+ ]
138
+ }
139
+ templates: []
140
+ # Every rule below runs against the two files this scaffold writes and must
141
+ # come back with zero findings: the manifest family and the content family. manifest.update-keys
142
+ # is deliberately not listed — an empty UpdateKeys is its documented info,
143
+ # not a failure, and a scaffolded mod has no page yet.
144
+ satisfies:
145
+ - stardewvalley.manifest.parses
146
+ - stardewvalley.manifest.required-fields
147
+ - stardewvalley.manifest.entry-or-content-pack
148
+ - stardewvalley.manifest.uniqueid
149
+ - stardewvalley.manifest.version
150
+ - stardewvalley.manifest.extra-fields
151
+ - stardewvalley.content.parses
152
+ - stardewvalley.content.format
153
+ - stardewvalley.content.changes-present
154
+ - stardewvalley.content.patch-action
155
+ - stardewvalley.content.patch-target
156
+ - stardewvalley.content.patch-fields
157
+ - stardewvalley.content.fromfile-exists
158
+ - stardewvalley.content.patch-enabled
159
+ - stardewvalley.content.when-tokens
160
+ manual:
161
+ - title: Replace the starter patch
162
+ steps:
163
+ - "Edit [CP] <name>/content.json: replace the Welcome letter patch with the first real change (the author guide's first example is a Load of Portraits/Abigail from assets/abigail.png), or run the new-cp-patch scaffold to append one."
164
+ - "Put any file a FromFile names under assets/; validate reports a FromFile that does not exist as a block."
165
+ - "Check both files at https://smapi.io/json (Manifest and Content Patcher formats) before shipping."
166
+ expected: "validate is clean; with the game installed, SMAPI's log lists the mod and Content Patcher's `patch summary` shows every patch loaded."
167
+ - title: Install and check in game
168
+ steps:
169
+ - "Copy the [CP] <name> folder into the game's Mods/ folder (deploy is not configured on this game yet) and launch StardewModdingAPI.exe."
170
+ - "In the SMAPI console run `patch summary` and find the pack's patches in the loaded | conditions | applied table."
171
+ expected: "The pack appears in the log's own 'Loaded N content packs:' list (not the 'Loaded N mods' list, which is C# mods only) under its manifest Name, followed by '| for Content Patcher', and nowhere in the 'Skipped mods' list."
172
+ claim:
173
+ idSuffix: scaffolded
174
+ claim: "${input.name} is scaffolded as a ModWright project holding the Content Patcher pack [CP] ${input.name} (UniqueID ${input.uniqueId}, Format 2.9.0) with one starter Data/mail patch."
175
+ testRows:
176
+ - gate: S-0
177
+ title: "Pack loads under SMAPI"
178
+ expected: "SMAPI's log lists the pack by its manifest Name in the 'Loaded N content packs:' list, '| for Content Patcher', with no 'Skipped mods' entry, and `patch summary` shows the Welcome letter patch as loaded."
179
+ manual: true
180
+ probeKinds: []
181
+ evidence:
182
+ - "stardewvalley.contentpatcher.format.what-a-pack-is"
183
+ - "stardewvalley.contentpatcher.format.whole-pack-rejection-messages"
184
+ - "stardewvalley.game.versions.unique-string-ids-convention"
@@ -0,0 +1,31 @@
1
+ # content-pack (Stardew Valley) — the smallest sequence: a Content Patcher
2
+ # pack and its first real patch. A C# mod cannot compile without the game,
3
+ # so the first Stardew project is always a content pack.
4
+ id: stardewvalley.content-pack
5
+ game: stardewvalley
6
+ title: Content Patcher pack with one patch
7
+ summary: A Content Patcher pack (manifest, content.json, assets/) and its first Load or EditImage patch over an asset the modder supplies.
8
+ modType: content-pack
9
+ inputs:
10
+ - name: modName
11
+ prompt: "Mod name; the pack folder is \"[CP] <name>\"."
12
+ - name: uniqueId
13
+ prompt: "The manifest UniqueID, YourName.YourModName (never changed once published)."
14
+ steps:
15
+ - id: project
16
+ scaffold: stardewvalley.new-project
17
+ title: The pack and its project file
18
+ skipIf: project-exists
19
+ inputs:
20
+ name: "${sequence.modName}"
21
+ uniqueId: "${sequence.uniqueId}"
22
+ - id: patch
23
+ scaffold: stardewvalley.new-cp-patch
24
+ title: The first patch over a game asset
25
+ inputs:
26
+ folder: "[CP] ${sequence.modName}"
27
+ assets:
28
+ - name: file
29
+ prompt: "The file the patch loads or edits with (a PNG for an image target, a data file otherwise), placed under the pack's assets/ folder. Path relative to the pack folder, e.g. assets/portrait.png."
30
+ inputs: [fromFile]
31
+ evidence: []
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Call any ModWright tool from a shell, through a fresh server process, with
4
+ * no MCP client in the way.
5
+ *
6
+ * npm run tool -- list [--schemas]
7
+ * npm run tool -- call <tool> [key=value ...] [--json '<object>'] [--args-file <file>] [--out <file>]
8
+ * npm run tool -- prompts
9
+ * npm run tool -- prompt <name> [path=<project>] [--out <file>]
10
+ *
11
+ * Why: an MCP client's tool list is fixed at its handshake, so a server
12
+ * rebuilt after the session started is invisible to it. Every invocation
13
+ * here spawns the server that is on disk right now, so a rebuilt ModWright is usable from the next shell command,
14
+ * whatever the surrounding client believes its tools are.
15
+ *
16
+ * Argument values given as key=value are parsed as JSON when they parse
17
+ * (true, 3, ["a"], {"k":1}) and taken as strings otherwise, so
18
+ * `mode=apply` and `force=true` both do what they look like. `--json` and
19
+ * `--args-file` take a whole object; later sources override earlier ones,
20
+ * in the order file, --json, key=value. `--out` writes the result text to a
21
+ * file instead of stdout. MODWRIGHT_* environment variables are forwarded.
22
+ * Long tools (build_index) are given a generous request timeout; there is
23
+ * no 60 s ceiling here. Exit code 1 when the tool reports an error.
24
+ */
25
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
26
+ import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
27
+ import { promises as fs } from "node:fs";
28
+ import * as path from "node:path";
29
+ import { fileURLToPath } from "node:url";
30
+
31
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
32
+ const REQUEST_TIMEOUT_MS = 6 * 60 * 60 * 1000;
33
+
34
+ const argv = process.argv.slice(2);
35
+ const command = argv.shift();
36
+ if (command !== "list" && command !== "call" && command !== "prompts" && command !== "prompt") {
37
+ usage();
38
+ process.exit(command === undefined || command === "--help" || command === "-h" ? 0 : 2);
39
+ }
40
+
41
+ function usage() {
42
+ process.stdout.write(
43
+ [
44
+ "usage:",
45
+ " mw-tool list [--schemas]",
46
+ " mw-tool call <tool> [key=value ...] [--json '<object>'] [--args-file <file>] [--out <file>]",
47
+ " mw-tool prompts list the workflow prompts the server serves",
48
+ " mw-tool prompt <name> [path=<dir>] render one workflow prompt for a project",
49
+ "",
50
+ "Every call spawns a fresh ModWright server from dist/, so it always reflects the current build.",
51
+ "",
52
+ ].join("\n"),
53
+ );
54
+ }
55
+
56
+ function takeFlag(flag) {
57
+ const i = argv.indexOf(flag);
58
+ if (i === -1) return undefined;
59
+ const value = argv[i + 1];
60
+ argv.splice(i, 2);
61
+ return value;
62
+ }
63
+
64
+ function takeSwitch(flag) {
65
+ const i = argv.indexOf(flag);
66
+ if (i === -1) return false;
67
+ argv.splice(i, 1);
68
+ return true;
69
+ }
70
+
71
+ const entry = process.env.MODWRIGHT_ENTRY ?? path.join(repoRoot, "dist", "index.js");
72
+ const env = { ...getDefaultEnvironment(), MODWRIGHT_NO_HOT_RELOAD: "1" };
73
+ for (const [key, value] of Object.entries(process.env)) {
74
+ if (key.startsWith("MODWRIGHT_") && value !== undefined) env[key] = value;
75
+ }
76
+
77
+ const client = new Client({ name: "modwright-tool-cli", version: "1.0.0" });
78
+ const transport = new StdioClientTransport({ command: process.execPath, args: [entry], env, stderr: "inherit" });
79
+
80
+ try {
81
+ await client.connect(transport);
82
+ if (command === "list") {
83
+ const withSchemas = takeSwitch("--schemas");
84
+ const { tools } = await client.listTools();
85
+ tools.sort((a, b) => a.name.localeCompare(b.name));
86
+ if (withSchemas) {
87
+ process.stdout.write(`${JSON.stringify(tools, null, 2)}\n`);
88
+ } else {
89
+ for (const t of tools) {
90
+ const params = Object.keys(t.inputSchema?.properties ?? {}).join(", ");
91
+ process.stdout.write(`${t.name}${params ? ` (${params})` : ""}\n`);
92
+ }
93
+ }
94
+ } else if (command === "prompts") {
95
+ const { prompts } = await client.listPrompts();
96
+ for (const p of prompts) process.stdout.write(`${p.name} ${p.description ?? ""}\n`);
97
+ } else if (command === "prompt") {
98
+ const outFile = takeFlag("--out");
99
+ const name = argv.shift();
100
+ if (!name) {
101
+ usage();
102
+ process.exit(2);
103
+ }
104
+ const promptArgs = {};
105
+ for (const pair of argv) {
106
+ const eq = pair.indexOf("=");
107
+ if (eq <= 0) {
108
+ process.stderr.write(`mw-tool: expected key=value, got "${pair}"\n`);
109
+ process.exit(2);
110
+ }
111
+ promptArgs[pair.slice(0, eq)] = pair.slice(eq + 1);
112
+ }
113
+ const result = await client.getPrompt({ name, arguments: promptArgs });
114
+ const text = (result.messages ?? [])
115
+ .map((m) => (m.content?.type === "text" ? m.content.text : `[${m.content?.type} content]`))
116
+ .join("\n\n");
117
+ if (outFile) {
118
+ await fs.writeFile(outFile, `${text}\n`, "utf8");
119
+ process.stderr.write(`mw-tool: wrote ${outFile}\n`);
120
+ } else {
121
+ process.stdout.write(`${text}\n`);
122
+ }
123
+ } else {
124
+ const outFile = takeFlag("--out");
125
+ const argsFile = takeFlag("--args-file");
126
+ const jsonArgs = takeFlag("--json");
127
+ const tool = argv.shift();
128
+ if (!tool) {
129
+ usage();
130
+ process.exit(2);
131
+ }
132
+ let args = {};
133
+ if (argsFile) Object.assign(args, JSON.parse(await fs.readFile(argsFile, "utf8")));
134
+ if (jsonArgs) Object.assign(args, JSON.parse(jsonArgs));
135
+ for (const pair of argv) {
136
+ const eq = pair.indexOf("=");
137
+ if (eq <= 0) {
138
+ process.stderr.write(`mw-tool: expected key=value, got "${pair}"\n`);
139
+ process.exit(2);
140
+ }
141
+ const key = pair.slice(0, eq);
142
+ const raw = pair.slice(eq + 1);
143
+ args[key] = parseValue(raw);
144
+ }
145
+ const result = await client.callTool({ name: tool, arguments: args }, undefined, { timeout: REQUEST_TIMEOUT_MS, resetTimeoutOnProgress: true });
146
+ const text = (result.content ?? [])
147
+ .map((c) => (c.type === "text" ? c.text : `[${c.type} content]`))
148
+ .join("\n");
149
+ const pretty = prettify(text);
150
+ if (outFile) {
151
+ await fs.writeFile(outFile, `${pretty}\n`, "utf8");
152
+ process.stderr.write(`mw-tool: wrote ${outFile}\n`);
153
+ } else {
154
+ process.stdout.write(`${pretty}\n`);
155
+ }
156
+ if (result.isError) process.exitCode = 1;
157
+ }
158
+ } catch (error) {
159
+ process.stderr.write(`mw-tool: ${error?.message ?? error}\n`);
160
+ process.exitCode = 1;
161
+ } finally {
162
+ await client.close().catch(() => {});
163
+ }
164
+
165
+ function parseValue(raw) {
166
+ if (raw === "") return "";
167
+ const first = raw[0];
168
+ if (first === "{" || first === "[" || first === '"' || raw === "true" || raw === "false" || raw === "null" || /^-?\d+(\.\d+)?$/.test(raw)) {
169
+ try {
170
+ return JSON.parse(raw);
171
+ } catch {
172
+ return raw;
173
+ }
174
+ }
175
+ return raw;
176
+ }
177
+
178
+ function prettify(text) {
179
+ try {
180
+ return JSON.stringify(JSON.parse(text), null, 2);
181
+ } catch {
182
+ return text;
183
+ }
184
+ }