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,361 @@
1
+ import * as path from "node:path";
2
+ import { executePlan, planCopy, planFile, planMkdir } from "../safety/index.js";
3
+ import { armBridge, bridgeCandidateDirs, bridgeStatus, cetLogCandidates, grantAllowsMutation, pollCyberpunk } from "../bridge/index.js";
4
+ import { REAL_FS_FOR_APPLY, redHotToolsDir } from "./reload.js";
5
+ function toPosix(p) {
6
+ return p.split(path.sep).join("/");
7
+ }
8
+ const SCRIPT_RE = /(^|\/)r6\/scripts\//;
9
+ const TWEAK_RE = /(^|\/)r6\/tweaks\//;
10
+ const ARCHIVE_RE = /(^|\/)archive\/pc\/mod\/.+\.archive$/;
11
+ const XL_RE = /(^|\/)archive\/pc\/mod\/.+\.archive\.xl$/;
12
+ function triggerFor(dest) {
13
+ const posix = toPosix(dest);
14
+ if (SCRIPT_RE.test(posix))
15
+ return "scripts";
16
+ if (TWEAK_RE.test(posix))
17
+ return "tweaks";
18
+ if (XL_RE.test(posix))
19
+ return "xl";
20
+ if (ARCHIVE_RE.test(posix))
21
+ return "archives";
22
+ return undefined;
23
+ }
24
+ export function planReloadApply(input) {
25
+ if (input.game !== "cyberpunk2077") {
26
+ return {
27
+ refused: { reason: "wrong-game", message: `deploy --reload apply is Cyberpunk 2077 only; this project is ${input.game}.` },
28
+ operations: [],
29
+ triggers: [],
30
+ skipped: [],
31
+ };
32
+ }
33
+ if (!grantAllowsMutation(input.grant, input.allowMutate)) {
34
+ return {
35
+ refused: {
36
+ reason: "session-grant-required",
37
+ message: "deploy --reload apply writes Red Hot Tools' file triggers into the running game, a session-tier action. " +
38
+ 'Grant it via bridge.policy mode: workbench, grant: ["session"], or the retired allowMutate.',
39
+ },
40
+ operations: [],
41
+ triggers: [],
42
+ skipped: [],
43
+ };
44
+ }
45
+ const dir = redHotToolsDir(input.install);
46
+ const hotDir = path.join(input.install.root, "archive", "pc", "hot");
47
+ const mesh = new Set((input.meshArchives ?? []).map((m) => path.basename(toPosix(m))));
48
+ const scriptDests = [];
49
+ const tweakDests = [];
50
+ const archives = [];
51
+ const xls = [];
52
+ const skipped = [];
53
+ for (const t of input.targets) {
54
+ switch (triggerFor(t.to)) {
55
+ case "scripts":
56
+ scriptDests.push(t.to);
57
+ break;
58
+ case "tweaks":
59
+ tweakDests.push(t.to);
60
+ break;
61
+ case "xl":
62
+ xls.push(t);
63
+ break;
64
+ case "archives":
65
+ if (mesh.has(path.basename(toPosix(t.to)))) {
66
+ skipped.push({ path: t.to, reason: "archive carries a mounted mesh; the hot folder is banned for whole-mesh archives (fact cp2077.process.assetbuild.rht-hot-folder-banned-for-whole-mesh-archives) — restart" });
67
+ }
68
+ else {
69
+ archives.push(t);
70
+ }
71
+ break;
72
+ default:
73
+ break;
74
+ }
75
+ }
76
+ const operations = [];
77
+ const triggers = [];
78
+ const stamp = (input.now ?? (() => new Date()))().toISOString();
79
+ if (archives.length > 0) {
80
+ operations.push(planMkdir(hotDir));
81
+ const hotPaths = [];
82
+ for (const a of archives) {
83
+ const dest = path.join(hotDir, path.basename(toPosix(a.from)));
84
+ operations.push(planCopy(a.from, dest));
85
+ hotPaths.push(dest);
86
+ }
87
+ for (const xl of xls) {
88
+ const dest = path.join(hotDir, path.basename(toPosix(xl.from)));
89
+ operations.push(planCopy(xl.from, dest));
90
+ hotPaths.push(dest);
91
+ }
92
+ triggers.push({ kind: "archives", triggerPath: hotDir, watchPaths: hotPaths, sourcePaths: [...archives.map((a) => a.from), ...xls.map((x) => x.from)] });
93
+ }
94
+ else if (xls.length > 0) {
95
+ for (const xl of xls)
96
+ skipped.push({ path: xl.to, reason: "an .xl with no .archive alongside reloads via ArchiveXL.Reload() through cp2077.lua.eval, not the hot folder" });
97
+ }
98
+ if (tweakDests.length > 0) {
99
+ const hotTweaks = path.join(dir, ".hot-tweaks");
100
+ operations.push(planFile(hotTweaks, `modwright reload ${stamp}\n`));
101
+ triggers.push({ kind: "tweaks", triggerPath: hotTweaks, watchPaths: [hotTweaks], sourcePaths: tweakDests });
102
+ }
103
+ if (scriptDests.length > 0) {
104
+ const hotScripts = path.join(dir, ".hot-scripts");
105
+ operations.push(planFile(hotScripts, ""));
106
+ triggers.push({ kind: "scripts", triggerPath: hotScripts, watchPaths: [hotScripts], sourcePaths: scriptDests });
107
+ }
108
+ return { operations, triggers, skipped };
109
+ }
110
+ const DEFAULT_DEPS = REAL_FS_FOR_APPLY;
111
+ const DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
112
+ async function bridgeTweakReload(ctx) {
113
+ const method = "TweakXL.Reload() via cp2077.lua.eval";
114
+ const sleep = ctx.sleep ?? DEFAULT_SLEEP;
115
+ let status = await bridgeStatus("cyberpunk2077", ctx.install, ctx.surface, { now: ctx.now });
116
+ const deadline = Date.now() + 6000;
117
+ while ((!status.found || status.freshness !== "fresh") && Date.now() < deadline) {
118
+ await sleep(500);
119
+ status = await bridgeStatus("cyberpunk2077", ctx.install, ctx.surface, { now: ctx.now });
120
+ }
121
+ if (!status.found || status.freshness !== "fresh") {
122
+ return {
123
+ method,
124
+ verdict: "absent",
125
+ detail: `the bridge is not live (no fresh heartbeat after 6s; last ${status.freshness}), so tweaks could not be reloaded through it. ` +
126
+ "The .hot-tweaks sentinel was written as a fallback but does not drive a reload in RHT 1.3.0.33690 " +
127
+ "(fact hot-tweaks-consumed-without-reload-1.3.0) — launch with the withBridge bridge, then it reloads automatically.",
128
+ };
129
+ }
130
+ const probe = { id: "tweakxl-reload", kind: "cp2077.lua.eval", context: "cet", effect: "mutate", params: { code: 'TweakXL.Reload(); return "reloaded"' } };
131
+ const armed = await armBridge({
132
+ game: "cyberpunk2077",
133
+ install: ctx.install,
134
+ surface: ctx.surface,
135
+ probes: [probe],
136
+ grant: ctx.grant,
137
+ allowMutate: ctx.allowMutate,
138
+ projectRoot: ctx.projectRoot,
139
+ mode: "apply",
140
+ now: ctx.now,
141
+ });
142
+ if (armed.refused)
143
+ return { method, verdict: "error", detail: `could not arm TweakXL.Reload(): ${armed.refused.message}` };
144
+ if (!armed.request)
145
+ return { method, verdict: "error", detail: "arming TweakXL.Reload() produced no request" };
146
+ const outcome = await pollCyberpunk({
147
+ files: await cetLogCandidates(ctx.install, ctx.surface),
148
+ dirs: bridgeCandidateDirs("cyberpunk2077", ctx.install, ctx.surface),
149
+ id: armed.request.id,
150
+ nonce: armed.request.nonce,
151
+ probeCount: 1,
152
+ armedAt: ctx.now ? ctx.now() : new Date(),
153
+ now: ctx.now,
154
+ sleep: ctx.sleep,
155
+ });
156
+ if (outcome.status !== "complete") {
157
+ return { method, verdict: "absent", detail: `TweakXL.Reload() was armed but no result came back: ${outcome.message}` };
158
+ }
159
+ const result = outcome.result.probes[0];
160
+ if (result && result.status === "pass") {
161
+ return { method, verdict: "confirmed", detail: `TweakXL.Reload() ran through the bridge (${outcome.transport} transport); re-read the changed flat with a cp2077.tweakdb.flat probe to see the new value` };
162
+ }
163
+ return { method, verdict: "error", detail: `TweakXL.Reload() eval did not pass: ${result ? `${result.status}${result.error ? ` — ${result.error}` : ""}` : "no probe result"}` };
164
+ }
165
+ async function newestRhtLog(dir, deps) {
166
+ return newestLog(dir, /^RedHotTools.*\.log$/i, deps);
167
+ }
168
+ async function newestTweakXlLog(dir, deps) {
169
+ return newestLog(dir, /^TweakXL.*\.log$/i, deps);
170
+ }
171
+ export function tweakXlErrorsFor(text, deployedPaths, installRoot) {
172
+ const tweaksRoot = path.join(installRoot, "r6", "tweaks");
173
+ const norm = (p) => p.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
174
+ const deployed = deployedPaths.map((p) => norm(path.relative(tweaksRoot, p)));
175
+ const isDeployed = (file) => deployed.some((d) => file === d || file.startsWith(`${d}/`));
176
+ const errors = [];
177
+ let current;
178
+ for (const line of text.split(/\r?\n/)) {
179
+ const reading = /Reading "([^"]+)"/.exec(line);
180
+ if (reading) {
181
+ current = norm(reading[1]);
182
+ continue;
183
+ }
184
+ if (/\[error\]/i.test(line) && current !== undefined && isDeployed(current))
185
+ errors.push(line.trim());
186
+ }
187
+ return errors;
188
+ }
189
+ async function newestLog(dir, pattern, deps) {
190
+ let logPath;
191
+ let newest = -1;
192
+ try {
193
+ for (const name of (await deps.readDir(dir)).filter((n) => pattern.test(n))) {
194
+ const full = path.join(dir, name);
195
+ const m = await deps.mtimeMs(full).catch(() => -1);
196
+ if (m > newest) {
197
+ newest = m;
198
+ logPath = full;
199
+ }
200
+ }
201
+ }
202
+ catch {
203
+ }
204
+ return logPath;
205
+ }
206
+ async function waitConsumed(paths, timeoutMs, intervalMs, deps, sleep) {
207
+ const deadline = Date.now() + timeoutMs;
208
+ for (;;) {
209
+ let allGone = true;
210
+ for (const p of paths) {
211
+ if (await deps.pathExists(p)) {
212
+ allGone = false;
213
+ break;
214
+ }
215
+ }
216
+ if (allGone)
217
+ return true;
218
+ if (Date.now() >= deadline)
219
+ return false;
220
+ await sleep(intervalMs);
221
+ }
222
+ }
223
+ async function logCorroboration(logPath, needle, triggerMs, method, deps, baseline) {
224
+ if (!logPath || !(await deps.pathExists(logPath)))
225
+ return { ok: false, detail: `${method} not found` };
226
+ const whole = await deps.readFile(logPath).catch(() => "");
227
+ const before = baseline.get(logPath) ?? 0;
228
+ const text = whole.length >= before ? whole.slice(before) : whole;
229
+ if (!text.includes(needle))
230
+ return { ok: false, detail: `"${needle}" not in ${path.basename(logPath)} since the trigger yet` };
231
+ const mtime = await deps.mtimeMs(logPath).catch(() => -1);
232
+ return mtime >= triggerMs
233
+ ? { ok: true, detail: `"${needle}" in ${path.basename(logPath)} after the trigger` }
234
+ : { ok: false, detail: `"${needle}" in ${path.basename(logPath)} but it predates the trigger` };
235
+ }
236
+ export async function runReloadApply(input) {
237
+ const deps = input.deps ?? DEFAULT_DEPS;
238
+ const sleep = input.sleep ?? DEFAULT_SLEEP;
239
+ const mode = input.mode ?? "dry-run";
240
+ const timeoutMs = input.readBackTimeoutMs ?? 8000;
241
+ const intervalMs = input.readBackIntervalMs ?? 400;
242
+ const { refused, operations, triggers, skipped } = planReloadApply(input);
243
+ if (refused) {
244
+ return { game: "cyberpunk2077", applied: false, refused, triggers: [], skipped };
245
+ }
246
+ const coldSkip = mode === "apply" && input.hotAvailable === false;
247
+ const confidence = {
248
+ level: "medium",
249
+ assumptions: [
250
+ "A hot reload is confirmed by RHT consuming the trigger (deleting the sentinel / moving the hot archive), then the game log — not assumed.",
251
+ ...(skipped.length > 0 ? [`${skipped.length} path(s) were left cold (mesh archive or non-hot-folder .xl); they still need a restart.`] : []),
252
+ ...(coldSkip ? ["Red Hot Tools is not watching this launch, so no trigger was written; deploy the change cold and restart."] : []),
253
+ ],
254
+ verifiedBy: [],
255
+ };
256
+ const triggerMs = (input.now ?? (() => new Date()))().getTime();
257
+ const dir = redHotToolsDir(input.install);
258
+ const tweakXlDir = path.join(input.install.root, "red4ext", "plugins", "TweakXL");
259
+ const tweakXlLog = (await newestTweakXlLog(tweakXlDir, deps)) ?? path.join(tweakXlDir, "TweakXL.log");
260
+ const logBaseline = new Map();
261
+ if (mode === "apply" && !coldSkip) {
262
+ for (const log of [await newestRhtLog(dir, deps), tweakXlLog]) {
263
+ if (log && (await deps.pathExists(log)))
264
+ logBaseline.set(log, (await deps.readFile(log).catch(() => "")).length);
265
+ }
266
+ }
267
+ const write = !coldSkip && operations.length > 0
268
+ ? await executePlan({
269
+ purpose: "deploy --reload apply: fire Red Hot Tools triggers",
270
+ operations,
271
+ ...(input.projectRoot ? { backupRoot: path.join(input.projectRoot, ".modwright", "backups") } : {}),
272
+ }, { mode, now: input.now, confidence })
273
+ : undefined;
274
+ const tweakLogReadBack = async (ran, deployed) => {
275
+ if (!(await deps.pathExists(tweakXlLog)))
276
+ return ran;
277
+ const appended = async () => {
278
+ const whole = await deps.readFile(tweakXlLog).catch(() => "");
279
+ const before = logBaseline.get(tweakXlLog) ?? 0;
280
+ return whole.length >= before ? whole.slice(before) : whole;
281
+ };
282
+ const deadline = Date.now() + timeoutMs;
283
+ let text = await appended();
284
+ while (!text.includes("Import completed.") && Date.now() < deadline) {
285
+ await sleep(intervalMs);
286
+ text = await appended();
287
+ }
288
+ const errors = tweakXlErrorsFor(text, deployed, input.install.root);
289
+ if (errors.length > 0) {
290
+ return {
291
+ method: `${ran.method} + ${path.basename(tweakXlLog)}`,
292
+ verdict: "error",
293
+ detail: `TweakXL reloaded but could not read the deployed tweak file(s), so the edit is NOT live: ${errors.slice(0, 3).join(" | ")}${errors.length > 3 ? ` (+${errors.length - 3} more)` : ""}`,
294
+ };
295
+ }
296
+ if (!text.includes("Import completed.")) {
297
+ return { ...ran, verdict: "triggered", detail: `${ran.detail}; but no "Import completed." in ${path.basename(tweakXlLog)} since the trigger yet` };
298
+ }
299
+ return { ...ran, method: `${ran.method} + ${path.basename(tweakXlLog)}`, detail: `${ran.detail}; ${path.basename(tweakXlLog)} shows the import with no error for the deployed file(s)` };
300
+ };
301
+ const canDriveBridge = Boolean(input.surface && input.projectRoot);
302
+ const driveTweaks = input.reloadTweaksViaBridge ?? bridgeTweakReload;
303
+ const outTriggers = [];
304
+ for (const t of triggers) {
305
+ let readBack;
306
+ if (mode === "dry-run") {
307
+ readBack = { method: "dry-run", verdict: "pending", detail: "dry-run: nothing was written, so there is no reload to read back — re-run with mode: apply" };
308
+ }
309
+ else if (coldSkip) {
310
+ readBack = { method: "presence", verdict: "absent", detail: "Red Hot Tools is not present/watching this launch; no trigger was written — deploy cold and restart" };
311
+ }
312
+ else if (t.kind === "tweaks" && canDriveBridge) {
313
+ readBack = await driveTweaks({
314
+ install: input.install,
315
+ surface: input.surface,
316
+ projectRoot: input.projectRoot,
317
+ grant: input.grant,
318
+ allowMutate: input.allowMutate,
319
+ now: input.now,
320
+ sleep: input.sleep,
321
+ });
322
+ if (readBack.verdict === "confirmed")
323
+ readBack = await tweakLogReadBack(readBack, t.sourcePaths);
324
+ }
325
+ else {
326
+ const consumed = await waitConsumed(t.watchPaths, timeoutMs, intervalMs, deps, sleep);
327
+ if (!consumed) {
328
+ readBack = {
329
+ method: t.kind === "archives" ? "archive/pc/hot moved" : `${path.basename(t.triggerPath)} deleted`,
330
+ verdict: "absent",
331
+ detail: `RHT did not consume the trigger within ${Math.round(timeoutMs / 1000)}s — is it watching, and is the game at a loaded save and unpaused? (the overlay/console being open can stall the tick)`,
332
+ };
333
+ }
334
+ else if (t.kind === "archives") {
335
+ const c = await logCorroboration(await newestRhtLog(dir, deps), "Archives reload completed", triggerMs, "RedHotTools.log", deps, logBaseline);
336
+ readBack = { method: "archive/pc/hot moved + RedHotTools.log", verdict: c.ok ? "confirmed" : "triggered", detail: `RHT moved the archive out of the hot folder; ${c.detail}` };
337
+ }
338
+ else if (t.kind === "tweaks") {
339
+ const c = await logCorroboration(tweakXlLog, "Import completed.", triggerMs, "TweakXL.log", deps, logBaseline);
340
+ readBack = c.ok
341
+ ? await tweakLogReadBack({ method: ".hot-tweaks deleted + TweakXL.log", verdict: "confirmed", detail: `TweakXL re-imported after the trigger (${c.detail})` }, t.sourcePaths)
342
+ : {
343
+ method: ".hot-tweaks deleted + TweakXL.log",
344
+ verdict: "triggered",
345
+ detail: "RHT deleted .hot-tweaks, but no TweakXL import followed — in RHT 1.3.0.33690 the .hot-tweaks sentinel does not drive a reload " +
346
+ "(fact hot-tweaks-consumed-without-reload-1.3.0), so the edit is NOT live. Reload it with TweakXL.Reload() via cp2077.lua.eval, then re-read the flat.",
347
+ };
348
+ }
349
+ else {
350
+ const fn = input.devModule ? `${input.devModule}.BuildStamp()` : "<Mod>Dev.BuildStamp()";
351
+ readBack = {
352
+ method: `.hot-scripts deleted; cp2077.lua.eval ${fn}`,
353
+ verdict: "triggered",
354
+ detail: `RHT deleted .hot-scripts, so the script reload ran; the definitive read-back is a cp2077.lua.eval of ${fn} (from the mod's dev module). A compile error surfaces as an RHT message box on the game window.`,
355
+ };
356
+ }
357
+ }
358
+ outTriggers.push({ ...t, readBack });
359
+ }
360
+ return { game: "cyberpunk2077", applied: !coldSkip && mode === "apply" && operations.length > 0, triggers: outTriggers, skipped, write };
361
+ }