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,159 @@
1
+ # new-quest-stub (BG3). A
2
+ # flat (non-nested) goal: INIT sets a DB fact, KB reacts to it with a
3
+ # QuestUpdate into a fresh top-level journal quest, EXIT clears the fact.
4
+ #
5
+ # Scope note: a full quest stub would also include
6
+ # "one dialogue greeting node". A real dialogue node is a Story
7
+ # Editor-authored .lsj that ships as the binary-derived intermediate of a
8
+ # vanilla DialogsBinary .lsf (bg3.story.dialogue-source-version's own
9
+ # appliesTo comment) — there is no plain-text authoring convention for it at
10
+ # all, and producing one needs the `divine` toolchain this scaffold's
11
+ # `needs` deliberately does not require. This scaffold stops at the goal,
12
+ # the journal and a Flags/<uuid>.lsx stub; wiring an actual dialogue node is
13
+ # left to the manual checklist below, as with other creative work.
14
+ id: baldursgate3.new-quest-stub
15
+ game: baldursgate3
16
+ title: New BG3 quest stub (goal + journal)
17
+ summary: Write a flat Osiris goal (INIT/KB/EXIT) that QuestUpdates a fresh top-level journal quest, plus a Flags/<uuid>.lsx stub and loca rows.
18
+ modTypes: [quest, dialogue]
19
+ needs: { index: true }
20
+ inputs:
21
+ - type: string
22
+ name: goalName
23
+ prompt: "Goal file name, Act_Region_Situation convention (e.g. Act1_Riverside_MyQuestIntro)."
24
+ pattern: "^[A-Za-z0-9]+(_[A-Za-z0-9]+){2,}$"
25
+ - type: string
26
+ name: journalTitle
27
+ prompt: "Journal quest category display text."
28
+ - type: string
29
+ name: firstEntryText
30
+ prompt: "First journal entry display text."
31
+ ids:
32
+ - name: questId
33
+ slot: "${project.identity.folder}_${input.goalName}_Quest"
34
+ form: map-key
35
+ - name: entryId
36
+ slot: "${project.identity.folder}_${input.goalName}_Start"
37
+ form: map-key
38
+ - name: startedDb
39
+ slot: "DB_${project.identity.folder}_${input.goalName}_Started"
40
+ form: map-key
41
+ - name: flagUuid
42
+ slot: "flag:${input.goalName}"
43
+ form: uuid
44
+ - name: journalTitleHandle
45
+ slot: "journal-title:${input.goalName}"
46
+ form: bg3-handle
47
+ - name: journalEntryHandle
48
+ slot: "journal-entry:${input.goalName}"
49
+ form: bg3-handle
50
+ emits:
51
+ # Under Mods/<folder>/Story/... — a mod's Story tree ships inside its own
52
+ # module folder (like meta.lsx and ScriptExtender), not at the project
53
+ # root, and has to sit under a declared project source for `validate` to
54
+ # ever look at it at all (`listFiles()` only walks declared sources).
55
+ - op: ensure-dir
56
+ path: "Mods/${project.identity.folder}/Story/RawFiles/Goals"
57
+ - op: ensure-dir
58
+ path: "Mods/${project.identity.folder}/Story/Journals"
59
+ - op: ensure-dir
60
+ path: "Public/${project.identity.folder}/Flags"
61
+ - op: write-text
62
+ path: "Mods/${project.identity.folder}/Story/RawFiles/Goals/${input.goalName}.txt"
63
+ body: |
64
+ INIT
65
+ ${ids.startedDb}(1)
66
+
67
+ KB
68
+ IF
69
+ ${ids.startedDb}(_)
70
+ THEN
71
+ QuestUpdate("${ids.questId}","${ids.entryId}")
72
+
73
+ EXIT
74
+ SysClear(${ids.startedDb})
75
+ - op: write-text
76
+ path: "Mods/${project.identity.folder}/Story/Journals/${input.goalName}.lsx"
77
+ body: |
78
+ <?xml version="1.0" encoding="utf-8"?>
79
+ <save>
80
+ <version major="4" minor="0" revision="9" build="200" />
81
+ <region id="Journal">
82
+ <node id="JournalRoot">
83
+ <children>
84
+ <node id="Category">
85
+ <attribute id="Name" type="FixedString" value="${ids.questId}" />
86
+ <attribute id="DisplayName" type="TranslatedString" handle="${ids.journalTitleHandle}" version="1" />
87
+ <children>
88
+ <node id="Entry">
89
+ <attribute id="ID" type="FixedString" value="${ids.entryId}" />
90
+ <attribute id="Text" type="TranslatedString" handle="${ids.journalEntryHandle}" version="1" />
91
+ </node>
92
+ </children>
93
+ </node>
94
+ </children>
95
+ </node>
96
+ </region>
97
+ </save>
98
+ - op: write-text
99
+ path: "Public/${project.identity.folder}/Flags/${ids.flagUuid}.lsx"
100
+ body: |
101
+ <?xml version="1.0" encoding="utf-8"?>
102
+ <save>
103
+ <version major="4" minor="0" revision="9" build="200" />
104
+ <region id="Flag">
105
+ <node id="Flag">
106
+ <attribute id="UUID" type="FixedString" value="${ids.flagUuid}" />
107
+ </node>
108
+ </region>
109
+ </save>
110
+ - op: insert-loca-row
111
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
112
+ handle: "${ids.journalTitleHandle}"
113
+ text: "${input.journalTitle}"
114
+ - op: insert-loca-row
115
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
116
+ handle: "${ids.journalEntryHandle}"
117
+ text: "${input.firstEntryText}"
118
+ templates: []
119
+ satisfies:
120
+ - bg3.story.osiris-section-structure
121
+ - bg3.story.osiris-naming-convention
122
+ - bg3.story.osiris-symbol-defined
123
+ - bg3.story.goal-parent-completes
124
+ - bg3.story.questupdate-parent-id
125
+ - bg3.story.quest-entry-exists
126
+ - bg3.story.questadd-questclose-discouraged
127
+ # Not listed: bg3.story.dialogue-flag-guid-resolves. It needs a dialogue
128
+ # .lsj that references the flag, which this scaffold leaves to the manual
129
+ # step, so on a real project it only ever skipped and the apply reported
130
+ # unclean (observed in game 2026-09-11).
131
+ - bg3.history.handle-defined-in-loca
132
+ manual:
133
+ - title: Wire the dialogue and trigger
134
+ steps:
135
+ - "Author the actual dialogue greeting node in the Story Editor and repoint its DialogBank SourceFile per the namespaced pattern."
136
+ - "Fire ${ids.startedDb}(1) from whichever trigger (an interaction, a region trigger) should start this quest."
137
+ - "Confirm the Flags/${ids.flagUuid}.lsx UUID is referenced from the dialogue node that should set it."
138
+ expected: "The trigger sets the DB fact, the goal's KB rule fires QuestUpdate, and the journal shows the new entry."
139
+ claim:
140
+ idSuffix: fires
141
+ claim: "Triggering ${ids.startedDb} completes the ${input.goalName} goal's KB rule and unlocks the ${ids.entryId} journal entry."
142
+ testRows:
143
+ - gate: G-1
144
+ title: "Goal DB fact and journal entry"
145
+ # bg3.event.watch/bg3.osiris.health are attested kinds, but both need an
146
+ # armed observe window straddling the manual trigger step above (fire
147
+ # ${ids.startedDb} from whichever interaction/region trigger a human
148
+ # wires up) — there is no scaffold-time input to arm ahead of a human
149
+ # action that has not happened yet, so this stays a manual row: a person
150
+ # arms both probes, fires the trigger, then reads the results by hand.
151
+ expected: "A human arms bg3.event.watch/bg3.osiris.health, fires the trigger, and confirms ${ids.startedDb} fired with no Osiris degradation."
152
+ manual: true
153
+ probeKinds: [bg3.event.watch, bg3.osiris.health]
154
+ - gate: G-2
155
+ title: "Dialogue and journal review"
156
+ expected: "The authored dialogue node fires and the journal query shows the entry unlocked."
157
+ manual: true
158
+ probeKinds: []
159
+ evidence: ["ModWright research"]
@@ -0,0 +1,102 @@
1
+ # new-spell (BG3). Appends one "new entry" block to Spell_<Type>.txt after a
2
+ # dated rationale comment and two loca rows for DisplayName/Description. No SpellAnimation is
3
+ # written — the parent (via `using`) is expected to supply one, as is
4
+ # usual for a Target-type spell inheriting from a vanilla parent.
5
+ id: baldursgate3.new-spell
6
+ game: baldursgate3
7
+ title: New BG3 spell (SpellData entry)
8
+ summary: Append a SpellData entry to Spell_<Type>.txt with a vanilla `using` parent, plus DisplayName/Description loca rows.
9
+ modTypes: [dialogue]
10
+ needs: { index: true }
11
+ inputs:
12
+ - type: string
13
+ name: entryName
14
+ prompt: "Full stats entry name, e.g. MyMod_ShortCircuit."
15
+ pattern: "^[A-Za-z][A-Za-z0-9_]*$"
16
+ - type: enum
17
+ name: spellType
18
+ prompt: "SpellType (also names the Spell_<Type>.txt file)."
19
+ values: [Target, Projectile, Shout]
20
+ - type: index-ref
21
+ name: parent
22
+ prompt: "Vanilla (or project) SpellData entry to `using`."
23
+ lookup: { kind: stat, params: { name: "${input.parent}" } }
24
+ requires:
25
+ - path: type
26
+ matches: "^SpellData$"
27
+ reason: "the parent must be a SpellData entry, or `using` inherits fields from the wrong stat family."
28
+ - type: string
29
+ name: level
30
+ prompt: "Spell level (0 for cantrip)."
31
+ default: "1"
32
+ - type: string
33
+ name: displayName
34
+ prompt: "Player-facing spell name."
35
+ - type: string
36
+ name: description
37
+ prompt: "Tooltip description text."
38
+ ids:
39
+ - name: display
40
+ slot: "display:${input.entryName}"
41
+ form: bg3-handle
42
+ - name: description
43
+ slot: "description:${input.entryName}"
44
+ form: bg3-handle
45
+ emits:
46
+ - op: insert-block
47
+ path: "Public/${project.identity.folder}/Stats/Generated/Data/Spell_${input.spellType}.txt"
48
+ createIfMissing: "// ModWright-scaffolded spell file.\n"
49
+ anchor: append
50
+ body: |
51
+ // ${project.today} - ModWright scaffold: ${input.entryName}, using parent ${input.parent}.
52
+ new entry "${input.entryName}"
53
+ type "SpellData"
54
+ data "SpellType" "${input.spellType}"
55
+ using "${input.parent}"
56
+ data "Icon" "${input.entryName}_Icon"
57
+ data "Level" "${input.level}"
58
+ data "UseCosts" "ActionPoint:1;SpellSlotsGroup:1:1:${input.level}"
59
+ data "DisplayName" "${ids.display}"
60
+ data "Description" "${ids.description}"
61
+ - op: insert-loca-row
62
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
63
+ handle: "${ids.display}"
64
+ text: "${input.displayName}"
65
+ - op: insert-loca-row
66
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
67
+ handle: "${ids.description}"
68
+ text: "${input.description}"
69
+ templates: []
70
+ satisfies:
71
+ - bg3.history.spellanimation-present
72
+ - bg3.history.reference-integrity
73
+ - bg3.history.handle-form-per-field
74
+ - bg3.history.handle-defined-in-loca
75
+ - bg3.history.islinkedspellcontainer-links
76
+ - bg3.history.spellid-enumeration-drift
77
+ - bg3.history.loca-no-xml-comments
78
+ manual:
79
+ - title: Icon and progression
80
+ steps:
81
+ - "Draw the ${input.entryName}_Icon art and register it in the spell atlas."
82
+ - "Add ${input.entryName} to a SpellList or Progression's AddSpells/SelectSpells if the parent does not already grant it."
83
+ expected: "The spell shows a real icon and is grantable in character creation / level-up."
84
+ claim:
85
+ idSuffix: applies
86
+ claim: "Casting ${input.entryName} applies the effect inherited from ${input.parent} for a target."
87
+ testRows:
88
+ - gate: S-1
89
+ title: "Stat entry loads with expected fields"
90
+ expected: "bg3.stat.exists finds ${input.entryName}; bg3.stat.fields confirms SpellType/UseCosts/DisplayName/Description."
91
+ manual: false
92
+ probes:
93
+ - kind: bg3.stat.exists
94
+ params: { name: "${input.entryName}" }
95
+ - kind: bg3.stat.fields
96
+ params: { name: "${input.entryName}", fields: [SpellType, UseCosts, DisplayName, Description] }
97
+ - gate: S-2
98
+ title: "Icon and tooltip render"
99
+ expected: "The spell's card shows the drawn icon and correct tooltip text in-game."
100
+ manual: true
101
+ probeKinds: []
102
+ evidence: ["ModWright research"]
@@ -0,0 +1,119 @@
1
+ # new-status (BG3). Same
2
+ # shape as new-spell/new-passive, targeting Status_<GROUP>.txt.
3
+ #
4
+ # Observed in game (2026-09-11): a child
5
+ # status inherits its parent's StackId through `using`, so the scaffolded
6
+ # status (parent BLESS) was replaced the moment BLESS was applied; the entry
7
+ # now restates StackId as its own name. The same launch showed the old
8
+ # "DisableCombatLog" spelling ignored by the engine (the status still hit the
9
+ # combat log; working entries spell it DisableCombatlog), so the
10
+ # flags are an input with the engine's spelling, empty (visible) by default.
11
+ id: baldursgate3.new-status
12
+ game: baldursgate3
13
+ title: New BG3 status (StatusData entry)
14
+ summary: Append a StatusData entry to Status_<GROUP>.txt with a vanilla `using` parent, plus DisplayName/Description loca rows.
15
+ modTypes: [dialogue]
16
+ needs: { index: true }
17
+ inputs:
18
+ - type: string
19
+ name: entryName
20
+ prompt: "Full stats entry name, e.g. MYMOD_SHOCKED."
21
+ pattern: "^[A-Za-z][A-Za-z0-9_]*$"
22
+ - type: enum
23
+ name: group
24
+ prompt: "Status group (also names the Status_<GROUP>.txt file)."
25
+ values: [BOOST, INCAPACITATED]
26
+ - type: index-ref
27
+ name: parent
28
+ prompt: "Vanilla (or project) StatusData entry to `using`."
29
+ lookup: { kind: stat, params: { name: "${input.parent}" } }
30
+ requires:
31
+ - path: type
32
+ matches: "^StatusData$"
33
+ reason: "the parent must be a StatusData entry, or `using` inherits fields from the wrong stat family."
34
+ - type: string
35
+ name: displayName
36
+ prompt: "Player-facing status name."
37
+ - type: string
38
+ name: description
39
+ prompt: "Tooltip description text."
40
+ - type: string
41
+ name: turns
42
+ prompt: "Default duration in turns (informational; wired via the caller's own functors)."
43
+ default: "1"
44
+ - type: string
45
+ name: statusPropertyFlags
46
+ prompt: "StatusPropertyFlags, ';'-separated (engine spelling: DisableOverhead, DisableCombatlog, DisablePortraitIndicator, IgnoreResting). Empty keeps the status visible."
47
+ pattern: "^[A-Za-z;]*$"
48
+ default: ""
49
+ ids:
50
+ - name: display
51
+ slot: "display:${input.entryName}"
52
+ form: bg3-handle
53
+ - name: description
54
+ slot: "description:${input.entryName}"
55
+ form: bg3-handle
56
+ emits:
57
+ - op: insert-block
58
+ path: "Public/${project.identity.folder}/Stats/Generated/Data/Status_${input.group}.txt"
59
+ createIfMissing: "// ModWright-scaffolded status file.\n"
60
+ anchor: append
61
+ body: |
62
+ // ${project.today} - ModWright scaffold: ${input.entryName}, using parent ${input.parent}.
63
+ new entry "${input.entryName}"
64
+ type "StatusData"
65
+ using "${input.parent}"
66
+ data "Icon" "${input.entryName}_Icon"
67
+ data "DisplayName" "${ids.display}"
68
+ data "Description" "${ids.description}"
69
+ data "StackId" "${input.entryName}"
70
+ data "StatusPropertyFlags" "${input.statusPropertyFlags}"
71
+ - op: insert-loca-row
72
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
73
+ handle: "${ids.display}"
74
+ text: "${input.displayName}"
75
+ - op: insert-loca-row
76
+ path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
77
+ handle: "${ids.description}"
78
+ text: "${input.description}"
79
+ templates: []
80
+ satisfies:
81
+ - bg3.history.spellanimation-present
82
+ - bg3.history.boostcontext-initial-event
83
+ - bg3.history.context-qualifier-validity
84
+ - bg3.history.reference-integrity
85
+ - bg3.history.handle-form-per-field
86
+ - bg3.history.handle-defined-in-loca
87
+ - bg3.history.islinkedspellcontainer-links
88
+ - bg3.history.spellid-enumeration-drift
89
+ - bg3.history.loca-no-xml-comments
90
+ manual:
91
+ - title: Icon and application
92
+ steps:
93
+ - "Draw the ${input.entryName}_Icon art and register it in the spell atlas."
94
+ - "Wire ApplyStatus(${input.entryName}, ...) into whichever spell/passive applies it, with a real duration for ${input.turns} turns."
95
+ expected: "The status applies and its icon/tooltip render correctly in-game."
96
+ claim:
97
+ idSuffix: applies
98
+ claim: "ApplyStatus(${input.entryName}, ...) applies the effect inherited from ${input.parent}."
99
+ testRows:
100
+ - gate: S-1
101
+ title: "Stat entry loads with expected fields"
102
+ expected: "bg3.stat.exists finds ${input.entryName}; bg3.stat.fields confirms DisplayName/Description."
103
+ manual: false
104
+ probes:
105
+ - kind: bg3.stat.exists
106
+ params: { name: "${input.entryName}" }
107
+ - kind: bg3.stat.fields
108
+ params: { name: "${input.entryName}", fields: [DisplayName, Description] }
109
+ - gate: S-2
110
+ title: "Status apply confirmed in-game"
111
+ # bg3.entity.status is attested by the registry, but it needs a live
112
+ # entity's own guid to check against — a fact only a human picking a
113
+ # target in a real session has, never something this scaffold's own
114
+ # inputs supply — so this stays a manual row (a person runs
115
+ # bg3.entity.status by hand via bridge arm/poll after ApplyStatus).
116
+ expected: "A human confirms bg3.entity.status (run by hand, no scaffold-known guid) reports the status active on a target after ApplyStatus."
117
+ manual: true
118
+ probeKinds: [bg3.entity.status]
119
+ evidence: ["ModWright research"]
@@ -0,0 +1,50 @@
1
+ # subclass-kit (Baldur's Gate 3) — the authoring sequence for a subclass kit
2
+ # (a monk subclass with its armor and a polearm): the project, a passive and a spell, two items, and the
3
+ # injection that puts the passive and spell on the target list. The
4
+ # injection step carries the entry names the two earlier steps were given.
5
+ id: baldursgate3.subclass-kit
6
+ game: baldursgate3
7
+ title: Subclass kit (passive, spell, armor, weapon, injection)
8
+ summary: Project, a passive and a spell with loca rows, an armor and a weapon with RootTemplates, and the class injection that grants the passive and spell.
9
+ modType: subclass
10
+ inputs:
11
+ - name: modName
12
+ prompt: "Mod name, used for the project and its Mods/<name> and Public/<name> folders, e.g. MyMonkMod."
13
+ steps:
14
+ - id: project
15
+ scaffold: baldursgate3.new-project
16
+ title: The project file and source trees
17
+ skipIf: project-exists
18
+ inputs:
19
+ name: "${sequence.modName}"
20
+ - id: passive
21
+ scaffold: baldursgate3.new-passive
22
+ title: The subclass's signature passive
23
+ - id: spell
24
+ scaffold: baldursgate3.new-spell
25
+ title: The subclass's signature spell
26
+ - id: armor
27
+ scaffold: baldursgate3.new-item
28
+ title: The armor item
29
+ inputs:
30
+ entryKind: Armor
31
+ assets:
32
+ - name: look
33
+ prompt: "The armor's look: an existing VisualBank Resource ID to reuse (lookup kind guid on the vanilla index for a vanilla one, or the project's own), and the icon atlas entry. Give the VisualBank id here."
34
+ inputs: [visualBankId]
35
+ - id: weapon
36
+ scaffold: baldursgate3.new-item
37
+ title: The weapon item (a naginata is a reskinned polearm)
38
+ inputs:
39
+ entryKind: Weapon
40
+ assets:
41
+ - name: look
42
+ prompt: "The weapon's look: an existing VisualBank Resource ID to reuse (a vanilla polearm's, from lookup kind guid), and the icon atlas entry. Give the VisualBank id here."
43
+ inputs: [visualBankId]
44
+ - id: injection
45
+ scaffold: baldursgate3.new-class-injection
46
+ title: The injection that grants the passive and spell to the target list
47
+ inputs:
48
+ injectedSpells: "${steps.spell.inputs.entryName}"
49
+ injectedPassives: "${steps.passive.inputs.entryName}"
50
+ evidence: []
@@ -0,0 +1,70 @@
1
+ # edit-tweak (Cyberpunk 2077) — the target-side registration a quickhack
2
+ # needs on an existing record. Appends or sets
3
+ # flats on an EXISTING TweakDB record, in place: `RecordName: { flats }` with
4
+ # no `$base`/`$type` is TweakXL's third record form — it MODIFIES the named
5
+ # record rather than creating one. `new-tweak` cannot write it (its recordName
6
+ # collision check refuses a record that already exists — the exact opposite of
7
+ # what an edit needs), so this is a separate scaffold rather than a third
8
+ # new-tweak mode: overloading one recordName input with both "must not exist"
9
+ # (create) and "must exist" (edit) is what the two scaffolds keep apart.
10
+ #
11
+ # recordName is an `index-ref`, so the engine verifies the target actually
12
+ # resolves in the vanilla index before an edit is written to it (a typo would
13
+ # otherwise make TweakXL create a stray record). That also scopes this scaffold
14
+ # to VANILLA records — a project record just authored is not in the vanilla
15
+ # index; edit those by hand in the same file.
16
+ #
17
+ # The quickhack chain uses it to register the hack on NPC hack lists: the game
18
+ # offers a hack on an NPC only when that NPC's `objectActions` names it (matched
19
+ # by actionName), and human/mechanical NPCs inherit their list from
20
+ # Character.Interactable_NPC_Base / Character.Mechanical_NPC_Base.
21
+ id: cyberpunk2077.edit-tweak
22
+ game: cyberpunk2077
23
+ title: Edit an existing Cyberpunk 2077 TweakDB record
24
+ summary: Append or set flats on an existing vanilla TweakDB record, in place — the base-less/type-less TweakXL modify form new-tweak cannot write.
25
+ modTypes: [gameplay-tweak, quickhack, weapon, item, loot]
26
+ needs: { index: true }
27
+ inputs:
28
+ - type: path
29
+ name: file
30
+ prompt: "Destination .yaml under a project source of kind \"tweaks\" (created if it does not yet exist)."
31
+ mustExist: false
32
+ - type: index-ref
33
+ name: recordName
34
+ prompt: "The EXISTING vanilla record to edit, e.g. Character.Interactable_NPC_Base — verified to resolve in the vanilla index before the edit is written."
35
+ lookup: { kind: record, params: { name: "${input.recordName}" } }
36
+ requires: []
37
+ - type: string
38
+ name: flats
39
+ prompt: "The flats to append or set on the record, as YAML (e.g. \"objectActions:\\n - !append QuickHack.MyHack\"). Indentation is normalized to nest under the record."
40
+ default: ""
41
+ reindent: 2
42
+ ids: []
43
+ emits:
44
+ # No $base/$type line: a record block with only flats modifies the existing
45
+ # record. `${input.flats}` is normalized to 2-space indent (reindent) so it
46
+ # nests under the record name.
47
+ - op: insert-block
48
+ path: "${input.file}"
49
+ createIfMissing: ""
50
+ anchor: append
51
+ body: |
52
+ ${input.recordName}:
53
+ ${input.flats}
54
+ templates: []
55
+ satisfies:
56
+ - cp2077.tweaks.yaml-lint
57
+ - cp2077.tweaks.append-on-list-flat
58
+ - cp2077.tweaks.record-name-exists
59
+ - cp2077.tweaks.dotted-path-same-file
60
+ - cp2077.tweaks.instances-resolve
61
+ manual:
62
+ - title: Confirm the edit landed
63
+ steps:
64
+ - "Load a save with the mod active and confirm the TweakXL log shows no error for ${input.file}."
65
+ - "Inspect ${input.recordName} and confirm the appended flats are present alongside its vanilla values (an edit adds to, it does not replace, unless a flat is set outright)."
66
+ expected: "TweakXL-<timestamp>.log carries no error for this file, and ${input.recordName} reads with both its vanilla flats and the appended ones."
67
+ claim:
68
+ idSuffix: edits
69
+ claim: "${input.recordName} carries the flats this run appended, on top of its vanilla definition."
70
+ evidence: ["ModWright research"]
@@ -0,0 +1,170 @@
1
+ # mesh-export-preset (Cyberpunk 2077). Writes a parameterised Blender export
2
+ # script encoding the confirmed pipeline facts
3
+ # (`knowledge/cyberpunk2077/mesh.blender.yaml`: the 65,535-vertex-per-submesh
4
+ # cap, exactly one "UVMap" UV layer, triangulation, baked tangents) and
5
+ # appends the `blender-export` + `wolvenkit-import` step pair to
6
+ # `build.steps` as `optional: true`, the shape a working project's own
7
+ # export-then-import build takes.
8
+ #
9
+ # The generated script is a parameterised **rewrite** of the confirmed facts,
10
+ # not a copy of any particular project's export script: the knowledge base
11
+ # attests that behaviour (vertex cap, UV normalisation, triangulation,
12
+ # tangent export, the 00/01/02/03 submesh join order) rather than quoting
13
+ # literal text. This scaffold never invokes Blender or WolvenKit itself; it
14
+ # only writes the script and the two `optional: true` build steps a real run
15
+ # would exercise.
16
+ id: cyberpunk2077.mesh-export-preset
17
+ game: cyberpunk2077
18
+ title: New Cyberpunk 2077 mesh export preset
19
+ summary: Write a parameterised Blender export script (vertex cap, UV, triangulation, tangents) and append the blender-export + wolvenkit-import build steps as optional.
20
+ modTypes: [mesh, garment, weapon, vehicle]
21
+ needs: {}
22
+ inputs:
23
+ - type: path
24
+ name: blendFile
25
+ prompt: "The .blend this preset exports from."
26
+ mustExist: false
27
+ - type: path
28
+ name: exportScriptFile
29
+ prompt: "Destination for the generated export script."
30
+ mustExist: false
31
+ - type: path
32
+ name: baseMeshPath
33
+ prompt: "Existing staged .mesh WolvenKit imports the exported glb over (donor chunkMaterials/skinning)."
34
+ mustExist: false
35
+ - type: path
36
+ name: outputMeshDir
37
+ prompt: "Directory the imported .mesh should land in."
38
+ mustExist: false
39
+ - type: string
40
+ name: glbOutputPath
41
+ prompt: "Where the exported .glb should land — may use the build system's own ${stage} placeholder, e.g. \"${stage}/mymod.glb\"."
42
+ - type: string
43
+ name: uvLayerName
44
+ prompt: "Required single UV layer name (cp2077.mesh.glb-uv-layers-required)."
45
+ default: "UVMap"
46
+ - type: string
47
+ name: presetId
48
+ prompt: "Short id for this preset, used to name the two build steps, e.g. mymod."
49
+ pattern: "^[a-z][a-z0-9_-]*$"
50
+ ids: []
51
+ emits:
52
+ - op: write-text
53
+ path: "${input.exportScriptFile}"
54
+ body: |
55
+ #!/usr/bin/env python3
56
+ # ${project.today} — ModWright scaffold: parameterised Blender export
57
+ # preset "${input.presetId}", generated by cyberpunk2077.mesh-export-preset.
58
+ # Encodes the confirmed Cyberpunk 2077 mesh-export pipeline facts
59
+ # (knowledge/cyberpunk2077/mesh.blender.yaml), written as a parameterised
60
+ # rewrite of those facts. Run via:
61
+ # blender --background "${input.blendFile}" --python "${input.exportScriptFile}"
62
+ import os
63
+ import bpy
64
+
65
+ VERTEX_CAP_PER_SUBMESH = 65535 # cp2077.mesh.vertex-cap-65535
66
+ REQUIRED_UV_LAYER = "${input.uvLayerName}" # cp2077.mesh.glb-uv-layers-required
67
+ # The build step's own "out"/"glb" fields (modwright.json) are the
68
+ # authoritative destination — they may use ModWright's own ${stage}
69
+ # placeholder, which only that build system resolves, never this
70
+ # script. This script writes next to the source .blend and lets the
71
+ # wolvenkit-import step (or you) move/copy from there, the way a
72
+ # plain export invocation takes no output argument
73
+ # (knowledge/cyberpunk2077/mesh.blender.yaml).
74
+ GLB_OUTPUT_PATH = os.path.splitext(bpy.data.filepath)[0] + ".glb"
75
+
76
+ def normalize_uv_layers(mesh_obj):
77
+ # Exactly one UV layer named REQUIRED_UV_LAYER; extra layers removed,
78
+ # missing ones smart-projected (cp2077.mesh.glb-uv-layers-required).
79
+ uv_layers = mesh_obj.data.uv_layers
80
+ if REQUIRED_UV_LAYER not in uv_layers:
81
+ bpy.ops.object.mode_set(mode="EDIT")
82
+ bpy.ops.uv.smart_project(angle_limit=1.15, island_margin=0.02)
83
+ bpy.ops.object.mode_set(mode="OBJECT")
84
+ uv_layers.active.name = REQUIRED_UV_LAYER
85
+ for layer in list(uv_layers):
86
+ if layer.name != REQUIRED_UV_LAYER:
87
+ uv_layers.remove(layer)
88
+
89
+ def triangulate_and_check_cap(mesh_obj):
90
+ # cp2077.mesh.glb-triangulation-required
91
+ bpy.ops.object.mode_set(mode="EDIT")
92
+ bpy.ops.mesh.quads_convert_to_tris(quad_method="BEAUTY", ngon_method="BEAUTY")
93
+ bpy.ops.object.mode_set(mode="OBJECT")
94
+ if len(mesh_obj.data.vertices) > VERTEX_CAP_PER_SUBMESH:
95
+ raise RuntimeError(
96
+ f"{mesh_obj.name}: {len(mesh_obj.data.vertices)} vertices exceeds the "
97
+ f"{VERTEX_CAP_PER_SUBMESH}-per-submesh engine cap (cp2077.mesh.vertex-cap-65535)."
98
+ )
99
+
100
+ def export():
101
+ for obj in bpy.context.scene.objects:
102
+ if obj.type != "MESH":
103
+ continue
104
+ normalize_uv_layers(obj)
105
+ triangulate_and_check_cap(obj)
106
+ bpy.ops.export_scene.gltf(
107
+ filepath=GLB_OUTPUT_PATH,
108
+ export_tangents=True, # cp2077.mesh.glb-tangent-vectors-required
109
+ )
110
+
111
+ if __name__ == "__main__":
112
+ export()
113
+ # Against a fresh new-project output (no `build` block yet at all), a
114
+ # patch-project without `build.outDir` would leave modwright.json failing
115
+ # to reload ("build.outDir: Required"), the same gap new-sector-node's
116
+ # patch-project closes. `add.outDir` only fills a genuinely missing
117
+ # `build.outDir`, so a project that already set one (e.g. from an earlier
118
+ # scaffold's own patch-project) keeps its own value (the engine's merge).
119
+ # Both steps below share one id on purpose: a build step id names a
120
+ # *chain* for `build --only <id>` (src/core/project/types.ts, BuildStepBase),
121
+ # so a blender-export and wolvenkit-import pair given a single id run
122
+ # together under `--only <id>`. That shared id is the convention, not a
123
+ # bug.
124
+ - op: patch-project
125
+ add:
126
+ outDir: "archive-staging"
127
+ steps:
128
+ - step: blender-export
129
+ id: "mesh-export-${input.presetId}"
130
+ optional: true
131
+ blend: "${input.blendFile}"
132
+ script: "${input.exportScriptFile}"
133
+ out: "${input.glbOutputPath}"
134
+ - step: wolvenkit-import
135
+ id: "mesh-export-${input.presetId}"
136
+ optional: true
137
+ glb: "${input.glbOutputPath}"
138
+ base: "${input.baseMeshPath}"
139
+ outDir: "${input.outputMeshDir}"
140
+ templates: []
141
+ # Applied against a fresh cyberpunk2077.new-project output,
142
+ # cp2077.history.mesh-preexport always skipped "no file matched": this
143
+ # scaffold never invokes Blender or WolvenKit itself and only writes the
144
+ # script and the two optional: true build steps, so it never writes a
145
+ # .gltf/.glb for that rule to check. The rule is therefore in the manual
146
+ # checklist below, which names the real file (the exported .glb at
147
+ # ${input.glbOutputPath}) and the checks the rule performs in prose.
148
+ # cp2077.history.archive-name-sort-order/deploy-set-completeness stay: both
149
+ # are project-scoped (appliesTo: project) and genuinely run every time.
150
+ satisfies:
151
+ - cp2077.history.archive-name-sort-order
152
+ - cp2077.history.deploy-set-completeness
153
+ manual:
154
+ - title: The kitbash and export itself
155
+ steps:
156
+ - "Author/kitbash the mesh in ${input.blendFile}, joined by material in the fixed submesh order this project's own donor mesh established (cp2077.mesh.join-by-material-submesh-order)."
157
+ - "Run the generated script (blender --background \"${input.blendFile}\" --python \"${input.exportScriptFile}\") and confirm no vertex-cap or UV error."
158
+ - "Build with this step pair enabled, then confirm the imported .mesh's chunkMaterials line up with the donor (${input.baseMeshPath})."
159
+ - "Once ${input.glbOutputPath} exists on disk, run validate against it directly — cp2077.history.mesh-preexport (moved out of this scaffold's own satisfies[]: it checks a .gltf/.glb this scaffold itself never produces) confirms the vertex cap, UV layer, triangulation and tangent-vector facts encoded in the generated script actually held for the real export."
160
+ expected: "The mesh imports cleanly with correct chunkMaterials, every submesh is under the 65,535-vertex cap, and cp2077.history.mesh-preexport reports no finding against the real ${input.glbOutputPath}."
161
+ claim:
162
+ idSuffix: mesh-exports-clean
163
+ claim: "${input.blendFile} exports through ${input.exportScriptFile} and imports over ${input.baseMeshPath} with no vertex-cap or UV-layer error."
164
+ testRows:
165
+ - gate: M-1
166
+ title: "Export and import run without error"
167
+ expected: "blender-export and wolvenkit-import both report success for the ${input.presetId} preset, with no vertex-cap/UV/triangulation error."
168
+ manual: true
169
+ probeKinds: []
170
+ evidence: ["ModWright research"]