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,197 @@
1
+ const CHAINLOADER = "https://github.com/BepInEx/BepInEx/blob/v5-lts/BepInEx/Bootstrap/Chainloader.cs";
2
+ const PRELOADER = "https://github.com/BepInEx/BepInEx/blob/v5-lts/BepInEx.Preloader/Preloader.cs";
3
+ const PRE = String.raw `^\[(?<level>Fatal|Error|Warning|Message|Info|Debug)\s*:\s*(?<source>.+?)\] `;
4
+ function re(body) {
5
+ return new RegExp(PRE + body);
6
+ }
7
+ export const SIGNATURES = [
8
+ {
9
+ id: "valheim.bepinex.version-banner",
10
+ game: "valheim",
11
+ sources: ["bepinex"],
12
+ severity: "info",
13
+ category: "version",
14
+ pattern: re(String.raw `BepInEx (?<version>\d[\w.\-]*) - (?<process>\S+)`),
15
+ explain: "BepInEx started and named its version and the process it attached to; the anchor for the run.",
16
+ seenIn: [PRELOADER],
17
+ extract: ["version", "process"],
18
+ },
19
+ {
20
+ id: "valheim.bepinex.unity-banner",
21
+ game: "valheim",
22
+ sources: ["bepinex"],
23
+ severity: "info",
24
+ category: "version",
25
+ pattern: re(String.raw `Running under Unity v(?<unity>[\w.]+)`),
26
+ explain: "The Unity engine version the game runs on; asset bundles and some plugins are bound to it.",
27
+ seenIn: [PRELOADER],
28
+ extract: ["unity"],
29
+ },
30
+ {
31
+ id: "valheim.bepinex.plugin-count",
32
+ game: "valheim",
33
+ sources: ["bepinex"],
34
+ severity: "info",
35
+ category: "load",
36
+ pattern: re(String.raw `(?<count>\d+) plugin\(s\) to load`),
37
+ explain: "How many plugins the chainloader found to load this run.",
38
+ seenIn: [CHAINLOADER],
39
+ extract: ["count"],
40
+ },
41
+ {
42
+ id: "valheim.bepinex.plugin-loaded",
43
+ game: "valheim",
44
+ sources: ["bepinex"],
45
+ severity: "info",
46
+ category: "load",
47
+ pattern: re(String.raw `Loading \[(?<plugin>.+?) (?<version>[\w.\-+]+)\]`),
48
+ explain: "One per plugin the chainloader loads, in dependency order; the roll-call of what is live.",
49
+ seenIn: [CHAINLOADER],
50
+ extract: ["plugin", "version"],
51
+ },
52
+ {
53
+ id: "valheim.bepinex.chainloader-complete",
54
+ game: "valheim",
55
+ sources: ["bepinex"],
56
+ severity: "info",
57
+ category: "success",
58
+ pattern: re(String.raw `Chainloader startup complete`),
59
+ explain: "Every plugin that was going to load has loaded. Unity exceptions from those plugins are not in this file by default; see Player.log.",
60
+ seenIn: [CHAINLOADER],
61
+ },
62
+ {
63
+ id: "valheim.bepinex.missing-dependency",
64
+ game: "valheim",
65
+ sources: ["bepinex"],
66
+ severity: "error",
67
+ category: "order",
68
+ pattern: re(String.raw `Could not load \[(?<plugin>.+?)\] because it has missing dependencies: (?<missing>.+)$`),
69
+ explain: "A plugin declared a hard dependency that is not installed; the plugin is skipped.",
70
+ hint: "Install the named dependency (its GUID is what is listed) or remove the plugin.",
71
+ seenIn: [CHAINLOADER],
72
+ extract: ["plugin", "missing"],
73
+ },
74
+ {
75
+ id: "valheim.bepinex.dependency-cascade",
76
+ game: "valheim",
77
+ sources: ["bepinex"],
78
+ severity: "warn",
79
+ category: "order",
80
+ pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because it has a dependency that was not loaded`),
81
+ explain: "A plugin was skipped because one it depends on failed earlier; fix the first failure and this one clears.",
82
+ seenIn: [CHAINLOADER],
83
+ extract: ["plugin"],
84
+ },
85
+ {
86
+ id: "valheim.bepinex.incompatible",
87
+ game: "valheim",
88
+ sources: ["bepinex"],
89
+ severity: "error",
90
+ category: "order",
91
+ pattern: re(String.raw `Could not load \[(?<plugin>.+?)\] because it is incompatible with: (?<with>.+)$`),
92
+ explain: "A plugin declared another as incompatible and both are installed; the declaring plugin is skipped.",
93
+ seenIn: [CHAINLOADER],
94
+ extract: ["plugin", "with"],
95
+ },
96
+ {
97
+ id: "valheim.bepinex.wrong-bepinex-version",
98
+ game: "valheim",
99
+ sources: ["bepinex"],
100
+ severity: "warn",
101
+ category: "version",
102
+ pattern: re(String.raw `Plugin \[(?<plugin>.+?)\] targets a wrong version of BepInEx \((?<targeted>[\w.]+)\) and might not work until you update`),
103
+ explain: "The plugin was built against a different BepInEx version; it still loads, and may or may not work.",
104
+ seenIn: [CHAINLOADER],
105
+ extract: ["plugin", "targeted"],
106
+ },
107
+ {
108
+ id: "valheim.bepinex.duplicate-guid",
109
+ game: "valheim",
110
+ sources: ["bepinex"],
111
+ severity: "warn",
112
+ category: "order",
113
+ pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because a newer version exists \((?<newer>.+?)\)`),
114
+ explain: "Two plugins share a GUID; the older one is dropped silently apart from this line. Real collisions here are on GUID, not on file path.",
115
+ seenIn: [CHAINLOADER],
116
+ extract: ["plugin", "newer"],
117
+ },
118
+ {
119
+ id: "valheim.bepinex.process-filtered",
120
+ game: "valheim",
121
+ sources: ["bepinex"],
122
+ severity: "info",
123
+ category: "load",
124
+ pattern: re(String.raw `Skipping \[(?<plugin>.+?)\] because of process filters \((?<filters>.+?)\)`),
125
+ explain: "The plugin declares it runs only in another process (the dedicated server, say) and was skipped on purpose.",
126
+ seenIn: [CHAINLOADER],
127
+ extract: ["plugin", "filters"],
128
+ },
129
+ {
130
+ id: "valheim.bepinex.plugin-load-error",
131
+ game: "valheim",
132
+ sources: ["bepinex"],
133
+ severity: "error",
134
+ category: "load",
135
+ pattern: re(String.raw `Error loading \[(?<plugin>.+?)\] :`),
136
+ explain: "The plugin threw while loading; the exception follows on the next lines. After a game update this is usually a missing method or type.",
137
+ seenIn: [CHAINLOADER],
138
+ extract: ["plugin"],
139
+ },
140
+ {
141
+ id: "valheim.bepinex.metadata-rejected",
142
+ game: "valheim",
143
+ sources: ["bepinex"],
144
+ severity: "warn",
145
+ category: "load",
146
+ pattern: re(String.raw `Skipping (?:over )?type \[(?<type>.+?)\] (?:as no metadata attribute is specified|because its (?<field>GUID|version|name))`),
147
+ explain: "A plugin class's [BepInPlugin] attribute is missing or malformed (an invalid GUID, version or name), so the class is not a plugin to BepInEx.",
148
+ seenIn: [CHAINLOADER],
149
+ extract: ["type", "field"],
150
+ },
151
+ {
152
+ id: "valheim.bepinex.fatal",
153
+ game: "valheim",
154
+ sources: ["bepinex"],
155
+ severity: "error",
156
+ category: "crash",
157
+ pattern: re(String.raw `Error occurred starting the game`),
158
+ explain: "The chainloader itself failed; nothing loaded.",
159
+ seenIn: [CHAINLOADER],
160
+ },
161
+ {
162
+ id: "valheim.harmony.target-not-found",
163
+ game: "valheim",
164
+ sources: ["bepinex"],
165
+ severity: "warn",
166
+ category: "resource",
167
+ pattern: re(String.raw `AccessTools\.\w+: Could not find (?<kind>method|field|property|type) (?<target>.+)$`),
168
+ explain: "A plugin's patch reached for a game member that no longer exists, usually after a game update; the plugin's patch silently does nothing.",
169
+ hint: "The plugin needs an update for the current game version.",
170
+ seenIn: ["HarmonyX AccessTools"],
171
+ extract: ["kind", "target"],
172
+ systemImpact: false,
173
+ },
174
+ {
175
+ id: "valheim.harmony.undefined-target-method",
176
+ game: "valheim",
177
+ sources: ["bepinex"],
178
+ severity: "error",
179
+ category: "resource",
180
+ pattern: re(String.raw `(?:[\w.]*Exception: )?Undefined target method for patch method (?<patch>.+)$`),
181
+ explain: "A Harmony patch declares a target the game no longer has; the patch is not applied and the plugin's feature is missing.",
182
+ hint: "The plugin needs an update for the current game version.",
183
+ seenIn: ["HarmonyX PatchClassProcessor"],
184
+ extract: ["patch"],
185
+ systemImpact: false,
186
+ },
187
+ {
188
+ id: "valheim.harmony.unpatchall",
189
+ game: "valheim",
190
+ sources: ["bepinex"],
191
+ severity: "warn",
192
+ category: "script",
193
+ pattern: re(String.raw `UnpatchAll has been called`),
194
+ explain: "A plugin called Harmony's UnpatchAll without an id, which removes every plugin's patches, not just its own.",
195
+ seenIn: ["HarmonyX"],
196
+ },
197
+ ];
@@ -0,0 +1,131 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { parse as parseToml } from "smol-toml";
3
+ export const MANIFEST_NAME_RE = /^[A-Za-z0-9_]{1,128}$/;
4
+ export const MANIFEST_VERSION_RE = /^\d+\.\d+\.\d+$/;
5
+ export const DEPENDENCY_STRING_RE = /^([A-Za-z0-9_]+)-([A-Za-z0-9_]+)-(\d+\.\d+\.\d+)$/;
6
+ export const MANIFEST_DESCRIPTION_MAX = 250;
7
+ export const PACKAGE_ROOT_FILES = ["manifest.json", "icon.png", "README.md"];
8
+ export const PACKAGE_OPTIONAL_ROOT_FILES = ["CHANGELOG.md"];
9
+ export const ICON_SIZE = 256;
10
+ export const PACKAGE_ROUTES = ["plugins", "core", "patchers", "monomod", "config", "SlimVML"];
11
+ export function parseDependencyString(s) {
12
+ const m = DEPENDENCY_STRING_RE.exec(s);
13
+ return m ? { team: m[1], name: m[2], version: m[3] } : undefined;
14
+ }
15
+ export function parseThunderstoreManifest(text) {
16
+ const raw = JSON.parse(text.replace(/^/, ""));
17
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
18
+ throw new Error("manifest.json is not a JSON object");
19
+ const record = raw;
20
+ const problems = [];
21
+ const manifest = { raw: record };
22
+ if (typeof record.name !== "string")
23
+ problems.push({ field: "name", message: "name is missing or not a string" });
24
+ else {
25
+ manifest.name = record.name;
26
+ if (!MANIFEST_NAME_RE.test(record.name))
27
+ problems.push({ field: "name", message: `name "${record.name}" must be 1-128 characters of a-z A-Z 0-9 _ with no spaces` });
28
+ }
29
+ if (typeof record.description !== "string")
30
+ problems.push({ field: "description", message: "description is missing or not a string" });
31
+ else {
32
+ manifest.description = record.description;
33
+ if (record.description.length > MANIFEST_DESCRIPTION_MAX)
34
+ problems.push({ field: "description", message: `description is ${record.description.length} characters; the limit is ${MANIFEST_DESCRIPTION_MAX}` });
35
+ }
36
+ if (typeof record.version_number !== "string")
37
+ problems.push({ field: "version_number", message: "version_number is missing or not a string" });
38
+ else {
39
+ manifest.versionNumber = record.version_number;
40
+ if (!MANIFEST_VERSION_RE.test(record.version_number))
41
+ problems.push({ field: "version_number", message: `version_number "${record.version_number}" must be three integers Major.Minor.Patch with no suffix` });
42
+ }
43
+ if (!("website_url" in record))
44
+ problems.push({ field: "website_url", message: "website_url is absent; it is optional in meaning but must be present, an empty string if there is none" });
45
+ else if (typeof record.website_url !== "string")
46
+ problems.push({ field: "website_url", message: "website_url is not a string" });
47
+ else
48
+ manifest.websiteUrl = record.website_url;
49
+ if (!Array.isArray(record.dependencies))
50
+ problems.push({ field: "dependencies", message: "dependencies is missing or not a list (an empty list is fine)" });
51
+ else {
52
+ const deps = [];
53
+ record.dependencies.forEach((d, i) => {
54
+ if (typeof d !== "string") {
55
+ problems.push({ field: `dependencies[${i}]`, message: "a dependency must be a string" });
56
+ return;
57
+ }
58
+ deps.push(d);
59
+ if (!parseDependencyString(d))
60
+ problems.push({ field: `dependencies[${i}]`, message: `"${d}" is not {team}-{package}-{Major.Minor.Patch}` });
61
+ });
62
+ manifest.dependencies = deps;
63
+ }
64
+ return { manifest, problems };
65
+ }
66
+ const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
67
+ export async function readPngDimensions(file) {
68
+ const handle = await fs.open(file, "r");
69
+ try {
70
+ const buf = new Uint8Array(24);
71
+ const { bytesRead } = await handle.read(buf, 0, 24, 0);
72
+ if (bytesRead < 24)
73
+ return undefined;
74
+ if (PNG_SIGNATURE.some((b, i) => buf[i] !== b))
75
+ return undefined;
76
+ if (String.fromCharCode(buf[12], buf[13], buf[14], buf[15]) !== "IHDR")
77
+ return undefined;
78
+ const view = new DataView(buf.buffer);
79
+ return { width: view.getUint32(16, false), height: view.getUint32(20, false) };
80
+ }
81
+ finally {
82
+ await handle.close();
83
+ }
84
+ }
85
+ export function routeOf(relativePath) {
86
+ const segments = relativePath.split(/[\\/]+/).filter((s) => s.length > 0);
87
+ if (segments.length < 2)
88
+ return undefined;
89
+ const prefixed = segments[0].toLowerCase() === "bepinex";
90
+ const candidate = prefixed ? segments[1] : segments[0];
91
+ if (prefixed && segments.length < 3)
92
+ return undefined;
93
+ const route = PACKAGE_ROUTES.find((r) => r.toLowerCase() === candidate.toLowerCase());
94
+ return route ? { route, prefixed } : undefined;
95
+ }
96
+ export function checkThunderstoreToml(text) {
97
+ const out = { dependencies: {}, problems: [] };
98
+ let doc;
99
+ try {
100
+ doc = parseToml(text);
101
+ }
102
+ catch (err) {
103
+ out.problems.push(`not valid TOML: ${err.message.split("\n")[0]}`);
104
+ return out;
105
+ }
106
+ const pkg = doc.package;
107
+ if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
108
+ out.problems.push("no [package] table");
109
+ return out;
110
+ }
111
+ const deps = pkg.dependencies;
112
+ if (deps === undefined)
113
+ return out;
114
+ if (Array.isArray(deps)) {
115
+ out.problems.push("[package] dependencies is a list; thunderstore.toml wants a [package.dependencies] table of \"Team-Name\" = \"version\" (the list form is manifest.json's shape)");
116
+ return out;
117
+ }
118
+ if (typeof deps !== "object") {
119
+ out.problems.push("[package.dependencies] is not a table");
120
+ return out;
121
+ }
122
+ for (const [key, value] of Object.entries(deps)) {
123
+ if (!/^[A-Za-z0-9_]+-[A-Za-z0-9_]+$/.test(key))
124
+ out.problems.push(`dependency key "${key}" is not Team-Name`);
125
+ if (typeof value !== "string" || !MANIFEST_VERSION_RE.test(value))
126
+ out.problems.push(`dependency "${key}" has version ${JSON.stringify(value)}, not Major.Minor.Patch`);
127
+ else
128
+ out.dependencies[key] = value;
129
+ }
130
+ return out;
131
+ }
@@ -0,0 +1,270 @@
1
+ export const BEPINPLUGIN_GUID_RE = /^[a-zA-Z0-9._-]+$/;
2
+ export const SYSTEM_VERSION_RE = /^\d+\.\d+(?:\.\d+){0,2}$/;
3
+ export const SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
4
+ export const COMPATIBILITY_LEVELS = ["NotEnforced", "VersionCheckOnly", "EveryoneMustHaveMod", "ClientMustHaveMod", "ServerMustHaveMod"];
5
+ export const VERSION_STRICTNESS = ["None", "Major", "Minor", "Patch"];
6
+ function stripComments(text) {
7
+ const out = text.split("");
8
+ const blank = (from, to) => {
9
+ for (let i = from; i < to; i++)
10
+ if (out[i] !== "\n")
11
+ out[i] = " ";
12
+ };
13
+ const skipQuoted = (start, quote) => {
14
+ let i = start + 1;
15
+ while (i < text.length && text[i] !== "\n") {
16
+ if (text[i] === "\\" && text[i + 1] !== "\n")
17
+ i += 2;
18
+ else if (text[i] === quote)
19
+ return i + 1;
20
+ else
21
+ i++;
22
+ }
23
+ return i;
24
+ };
25
+ const skipVerbatim = (start) => {
26
+ let i = start + 1;
27
+ while (i < text.length) {
28
+ if (text[i] !== '"')
29
+ i++;
30
+ else if (text[i + 1] === '"')
31
+ i += 2;
32
+ else
33
+ return i + 1;
34
+ }
35
+ return i;
36
+ };
37
+ let i = 0;
38
+ while (i < text.length) {
39
+ const c = text[i];
40
+ const next = text[i + 1];
41
+ if (c === "/" && next === "/") {
42
+ const eol = text.indexOf("\n", i);
43
+ const end = eol < 0 ? text.length : eol;
44
+ blank(i, end);
45
+ i = end;
46
+ }
47
+ else if (c === "/" && next === "*") {
48
+ const close = text.indexOf("*/", i + 2);
49
+ const end = close < 0 ? text.length : close + 2;
50
+ blank(i, end);
51
+ i = end;
52
+ }
53
+ else if (c === '"')
54
+ i = text[i - 1] === "@" ? skipVerbatim(i) : skipQuoted(i, '"');
55
+ else if (c === "'")
56
+ i = skipQuoted(i, "'");
57
+ else
58
+ i++;
59
+ }
60
+ return out.join("");
61
+ }
62
+ function lineAt(text, index) {
63
+ let line = 1;
64
+ for (let i = 0; i < index && i < text.length; i++)
65
+ if (text.charCodeAt(i) === 10)
66
+ line++;
67
+ return line;
68
+ }
69
+ function constants(text) {
70
+ const out = new Map();
71
+ const re = /\bconst\s+string\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"([^"\n]*)"\s*;/g;
72
+ let m;
73
+ while ((m = re.exec(text)))
74
+ out.set(m[1], m[2]);
75
+ return out;
76
+ }
77
+ function splitArgs(args) {
78
+ const out = [];
79
+ let depth = 0;
80
+ let inString = false;
81
+ let current = "";
82
+ for (let i = 0; i < args.length; i++) {
83
+ const c = args[i];
84
+ if (inString) {
85
+ current += c;
86
+ if (c === "\\") {
87
+ current += args[i + 1] ?? "";
88
+ i++;
89
+ }
90
+ else if (c === '"')
91
+ inString = false;
92
+ continue;
93
+ }
94
+ if (c === '"') {
95
+ inString = true;
96
+ current += c;
97
+ }
98
+ else if (c === "(") {
99
+ depth++;
100
+ current += c;
101
+ }
102
+ else if (c === ")") {
103
+ depth--;
104
+ current += c;
105
+ }
106
+ else if (c === "," && depth === 0) {
107
+ out.push(current.trim());
108
+ current = "";
109
+ }
110
+ else
111
+ current += c;
112
+ }
113
+ if (current.trim().length > 0)
114
+ out.push(current.trim());
115
+ return out;
116
+ }
117
+ function resolveString(expr, consts) {
118
+ const literal = /^@?"([^"\n]*)"$/.exec(expr);
119
+ if (literal)
120
+ return literal[1];
121
+ const ident = /^(?:[A-Za-z_][A-Za-z0-9_]*\.)*([A-Za-z_][A-Za-z0-9_]*)$/.exec(expr);
122
+ if (ident && consts.has(ident[1]))
123
+ return consts.get(ident[1]);
124
+ return undefined;
125
+ }
126
+ function attributes(text, name) {
127
+ const out = [];
128
+ const re = new RegExp(`\\[\\s*(?:[A-Za-z_][A-Za-z0-9_]*\\.)*${name}(?:Attribute)?\\s*(?:\\(([^\\]]*?)\\))?\\s*\\]`, "g");
129
+ let m;
130
+ while ((m = re.exec(text)))
131
+ out.push({ args: m[1] ?? "", index: m.index });
132
+ return out;
133
+ }
134
+ export function scanPluginSource(source) {
135
+ const text = stripComments(source);
136
+ const consts = constants(text);
137
+ const scan = {
138
+ plugins: [],
139
+ dependencies: [],
140
+ baseUnityPluginClasses: [],
141
+ unpatchAllWithoutId: [],
142
+ patchAllParameterless: [],
143
+ networkCompatibility: [],
144
+ bepInProcesses: [],
145
+ };
146
+ for (const a of attributes(text, "BepInPlugin")) {
147
+ const args = splitArgs(a.args);
148
+ const entry = { line: lineAt(text, a.index), unresolved: [] };
149
+ const [guid, name, version] = args;
150
+ const take = (expr) => {
151
+ if (expr === undefined)
152
+ return undefined;
153
+ const v = resolveString(expr, consts);
154
+ if (v === undefined)
155
+ entry.unresolved.push(expr);
156
+ return v;
157
+ };
158
+ const g = take(guid);
159
+ if (g !== undefined)
160
+ entry.guid = g;
161
+ const n = take(name);
162
+ if (n !== undefined)
163
+ entry.name = n;
164
+ const v = take(version);
165
+ if (v !== undefined)
166
+ entry.version = v;
167
+ scan.plugins.push(entry);
168
+ }
169
+ for (const a of attributes(text, "BepInDependency")) {
170
+ const args = splitArgs(a.args);
171
+ const entry = { line: lineAt(text, a.index), unresolved: [] };
172
+ const guid = args[0] !== undefined ? resolveString(args[0], consts) : undefined;
173
+ if (guid !== undefined)
174
+ entry.guid = guid;
175
+ else if (args[0] !== undefined)
176
+ entry.unresolved.push(args[0]);
177
+ if (args.length === 1)
178
+ entry.kind = "hard";
179
+ else if (args[1] !== undefined) {
180
+ const second = args[1];
181
+ if (/SoftDependency\b/.test(second))
182
+ entry.kind = "soft";
183
+ else if (/HardDependency\b/.test(second))
184
+ entry.kind = "hard";
185
+ else {
186
+ const min = resolveString(second, consts);
187
+ if (min !== undefined) {
188
+ entry.kind = "hard";
189
+ entry.minimumVersion = min;
190
+ }
191
+ else
192
+ entry.unresolved.push(second);
193
+ }
194
+ }
195
+ scan.dependencies.push(entry);
196
+ }
197
+ const classRe = /\bclass\s+([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]*>)?\s*:\s*([^{]+)\{/g;
198
+ let m;
199
+ while ((m = classRe.exec(text))) {
200
+ const bases = m[2].split(",").map((b) => b.trim().replace(/^(?:[A-Za-z_][A-Za-z0-9_]*\.)*/, ""));
201
+ if (bases.includes("BaseUnityPlugin"))
202
+ scan.baseUnityPluginClasses.push({ name: m[1], line: lineAt(text, m.index) });
203
+ }
204
+ const unpatchRe = /\.UnpatchAll\s*\(\s*(null)?\s*\)/g;
205
+ while ((m = unpatchRe.exec(text)))
206
+ scan.unpatchAllWithoutId.push({ line: lineAt(text, m.index) });
207
+ const patchAllRe = /\.PatchAll\s*\(\s*\)/g;
208
+ while ((m = patchAllRe.exec(text)))
209
+ scan.patchAllParameterless.push({ line: lineAt(text, m.index) });
210
+ for (const a of attributes(text, "NetworkCompatibility")) {
211
+ const args = splitArgs(a.args);
212
+ const entry = { line: lineAt(text, a.index) };
213
+ const level = args[0]?.match(/(?:CompatibilityLevel\.)?([A-Za-z]+)$/)?.[1];
214
+ if (level)
215
+ entry.level = level;
216
+ const strictness = args[1]?.match(/(?:VersionStrictness\.)?([A-Za-z]+)$/)?.[1];
217
+ if (strictness)
218
+ entry.strictness = strictness;
219
+ scan.networkCompatibility.push(entry);
220
+ }
221
+ for (const a of attributes(text, "BepInProcess")) {
222
+ const args = splitArgs(a.args);
223
+ const name = args[0] !== undefined ? resolveString(args[0], consts) : undefined;
224
+ scan.bepInProcesses.push({ line: lineAt(text, a.index), ...(name !== undefined ? { name } : {}) });
225
+ }
226
+ return scan;
227
+ }
228
+ export function packageNameMatchesGuid(packageName, guid) {
229
+ const norm = (s) => s.toLowerCase().replace(/[_-]/g, "");
230
+ const p = norm(packageName);
231
+ if (p.length === 0)
232
+ return false;
233
+ const g = guid.toLowerCase();
234
+ if (norm(g) === p)
235
+ return true;
236
+ return g.split(".").some((segment) => norm(segment) === p);
237
+ }
238
+ export function scanCfg(text) {
239
+ const scan = { sections: [], entries: [], malformed: [], duplicates: [] };
240
+ let section = "";
241
+ const seen = new Map();
242
+ text.split(/\r?\n/).forEach((raw, i) => {
243
+ const line = i + 1;
244
+ const trimmed = raw.trim();
245
+ if (trimmed.length === 0 || trimmed.startsWith("#"))
246
+ return;
247
+ const sec = /^\[(.+)\]$/.exec(trimmed);
248
+ if (sec) {
249
+ section = sec[1].trim();
250
+ scan.sections.push({ name: section, line });
251
+ return;
252
+ }
253
+ const kv = /^([^=\s][^=]*?)\s*=\s*(.*)$/.exec(trimmed);
254
+ if (!kv) {
255
+ scan.malformed.push({ line, text: trimmed });
256
+ return;
257
+ }
258
+ const key = kv[1];
259
+ scan.entries.push({ section, key, value: kv[2], line });
260
+ const id = `${section}\u0000${key}`;
261
+ seen.set(id, [...(seen.get(id) ?? []), line]);
262
+ });
263
+ for (const [id, lines] of seen) {
264
+ if (lines.length < 2)
265
+ continue;
266
+ const [section, key] = id.split("\u0000");
267
+ scan.duplicates.push({ section, key, lines });
268
+ }
269
+ return scan;
270
+ }