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.
- package/LICENSE +35 -0
- package/README.md +212 -0
- package/assets/claude/agents/mw-explore.md +46 -0
- package/assets/claude/agents/mw-fixture.md +33 -0
- package/assets/claude/agents/mw-rule-author.md +51 -0
- package/assets/claude/agents/mw-scaffold-author.md +48 -0
- package/assets/claude/skills/mw-author.md +59 -0
- package/assets/claude/skills/mw-new-item.md +51 -0
- package/assets/claude/skills/mw-new-spell.md +50 -0
- package/assets/claude/skills/mw-scaffold.md +59 -0
- package/assets/claude/skills/mw-ship.md +57 -0
- package/assets/claude/skills/mw-validate.md +51 -0
- package/assets/claude/skills/mw-verify.md +59 -0
- package/assets/nivalisnights/extract_resources.py +177 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Config.json +5 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapClient.lua +55 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapServer.lua +81 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Log.lua +96 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Probes.lua +1038 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/ProbesClient.lua +74 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Protocol.lua +985 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Watch.lua +175 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/meta.lsx +45 -0
- package/bridges/bg3-se/README.md +99 -0
- package/bridges/bg3-se/bridge.json +68 -0
- package/bridges/cp2077-cet/ModWrightBridge/init.lua +375 -0
- package/bridges/cp2077-cet/ModWrightBridge/probes.lua +1104 -0
- package/bridges/cp2077-cet/ModWrightBridge/protocol.lua +1306 -0
- package/bridges/cp2077-cet/README.md +165 -0
- package/bridges/cp2077-cet/bridge.json +53 -0
- package/dist/core/bridge/arm.js +175 -0
- package/dist/core/bridge/cet-console.js +26 -0
- package/dist/core/bridge/cet-log.js +362 -0
- package/dist/core/bridge/index.js +11 -0
- package/dist/core/bridge/locate.js +35 -0
- package/dist/core/bridge/paths.js +34 -0
- package/dist/core/bridge/pending.js +89 -0
- package/dist/core/bridge/poll.js +155 -0
- package/dist/core/bridge/stage.js +100 -0
- package/dist/core/bridge/status.js +97 -0
- package/dist/core/bridge/types.js +145 -0
- package/dist/core/bridge/validate.js +107 -0
- package/dist/core/build/index.js +6 -0
- package/dist/core/build/manifest.js +47 -0
- package/dist/core/build/paths.js +32 -0
- package/dist/core/build/run.js +342 -0
- package/dist/core/build/stage.js +265 -0
- package/dist/core/build/steps/bg3.js +129 -0
- package/dist/core/build/steps/core.js +195 -0
- package/dist/core/build/steps/cyberpunk.js +95 -0
- package/dist/core/build/steps/listing.js +35 -0
- package/dist/core/build/types.js +13 -0
- package/dist/core/build/zip.js +148 -0
- package/dist/core/compat/check.js +113 -0
- package/dist/core/compat/pe.js +220 -0
- package/dist/core/compat/types.js +1 -0
- package/dist/core/compat/version.js +70 -0
- package/dist/core/deploy/guards.js +292 -0
- package/dist/core/deploy/index.js +5 -0
- package/dist/core/deploy/plan.js +696 -0
- package/dist/core/deploy/reload-apply.js +361 -0
- package/dist/core/deploy/reload.js +358 -0
- package/dist/core/deploy/sources.js +169 -0
- package/dist/core/deploy/types.js +1 -0
- package/dist/core/epic.js +54 -0
- package/dist/core/fsutil.js +191 -0
- package/dist/core/home.js +70 -0
- package/dist/core/knowledge/facts.js +229 -0
- package/dist/core/knowledge/index.js +4 -0
- package/dist/core/knowledge/search.js +112 -0
- package/dist/core/knowledge/store.js +123 -0
- package/dist/core/knowledge/types.js +1 -0
- package/dist/core/ledger/check.js +42 -0
- package/dist/core/ledger/hooks.js +80 -0
- package/dist/core/ledger/index.js +7 -0
- package/dist/core/ledger/query.js +17 -0
- package/dist/core/ledger/record.js +84 -0
- package/dist/core/ledger/status.js +53 -0
- package/dist/core/ledger/store.js +98 -0
- package/dist/core/ledger/types.js +108 -0
- package/dist/core/logs/index.js +4 -0
- package/dist/core/logs/registry.js +50 -0
- package/dist/core/logs/scan.js +195 -0
- package/dist/core/logs/triage.js +160 -0
- package/dist/core/logs/types.js +1 -0
- package/dist/core/lsx.js +10 -0
- package/dist/core/lz4.js +66 -0
- package/dist/core/mods.js +229 -0
- package/dist/core/process.js +49 -0
- package/dist/core/project/build-steps.js +83 -0
- package/dist/core/project/describe.js +74 -0
- package/dist/core/project/index.js +5 -0
- package/dist/core/project/load.js +146 -0
- package/dist/core/project/schema.js +264 -0
- package/dist/core/project/types.js +3 -0
- package/dist/core/prompts.js +72 -0
- package/dist/core/registry.js +35 -0
- package/dist/core/safety/backup.js +206 -0
- package/dist/core/safety/execute.js +188 -0
- package/dist/core/safety/index.js +5 -0
- package/dist/core/safety/plan.js +122 -0
- package/dist/core/safety/restore.js +172 -0
- package/dist/core/safety/types.js +1 -0
- package/dist/core/scaffold/bootstrap.js +7 -0
- package/dist/core/scaffold/catalog.js +28 -0
- package/dist/core/scaffold/claude-assets.js +271 -0
- package/dist/core/scaffold/collisions.js +64 -0
- package/dist/core/scaffold/emit.js +356 -0
- package/dist/core/scaffold/engine.js +680 -0
- package/dist/core/scaffold/ids.js +78 -0
- package/dist/core/scaffold/index.js +10 -0
- package/dist/core/scaffold/jsonpath.js +121 -0
- package/dist/core/scaffold/load.js +81 -0
- package/dist/core/scaffold/render.js +85 -0
- package/dist/core/scaffold/sequence.js +396 -0
- package/dist/core/scaffold/types.js +309 -0
- package/dist/core/steam.js +63 -0
- package/dist/core/surfaceutil.js +36 -0
- package/dist/core/testplan/check.js +67 -0
- package/dist/core/testplan/index.js +5 -0
- package/dist/core/testplan/load.js +100 -0
- package/dist/core/testplan/registry.js +317 -0
- package/dist/core/testplan/run.js +389 -0
- package/dist/core/testplan/types.js +82 -0
- package/dist/core/text/converters/bg3.js +50 -0
- package/dist/core/text/converters/cyberpunk.js +36 -0
- package/dist/core/text/converters/index.js +261 -0
- package/dist/core/text/diff/cr2w.js +180 -0
- package/dist/core/text/diff/index.js +16 -0
- package/dist/core/text/diff/loca.js +43 -0
- package/dist/core/text/diff/lsx.js +126 -0
- package/dist/core/text/handles.js +86 -0
- package/dist/core/text/index.js +6 -0
- package/dist/core/text/json.js +46 -0
- package/dist/core/text/templates/cache.js +71 -0
- package/dist/core/text/templates/index.js +3 -0
- package/dist/core/text/templates/library.js +245 -0
- package/dist/core/text/templates/types.js +51 -0
- package/dist/core/text/toolchain.js +16 -0
- package/dist/core/text/types.js +1 -0
- package/dist/core/text/validate.js +149 -0
- package/dist/core/text/xml.js +58 -0
- package/dist/core/toolchain/datafetch.js +151 -0
- package/dist/core/toolchain/env.js +63 -0
- package/dist/core/toolchain/features.js +170 -0
- package/dist/core/toolchain/index.js +8 -0
- package/dist/core/toolchain/install.js +191 -0
- package/dist/core/toolchain/locate.js +275 -0
- package/dist/core/toolchain/remember.js +84 -0
- package/dist/core/toolchain/run.js +318 -0
- package/dist/core/toolchain/specs.js +351 -0
- package/dist/core/toolchain/types.js +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/userconfig.js +66 -0
- package/dist/core/validate/context.js +139 -0
- package/dist/core/validate/index.js +5 -0
- package/dist/core/validate/registry.js +58 -0
- package/dist/core/validate/run.js +131 -0
- package/dist/core/validate/suppressions.js +91 -0
- package/dist/core/validate/types.js +2 -0
- package/dist/core/yamledit.js +51 -0
- package/dist/index.js +389 -0
- package/dist/server.js +1914 -0
- package/dist/surfaces/baldursgate3/compat.js +164 -0
- package/dist/surfaces/baldursgate3/identity.js +110 -0
- package/dist/surfaces/baldursgate3/index/build.js +331 -0
- package/dist/surfaces/baldursgate3/index/index.js +17 -0
- package/dist/surfaces/baldursgate3/index/info.js +40 -0
- package/dist/surfaces/baldursgate3/index/parsers/loca.js +41 -0
- package/dist/surfaces/baldursgate3/index/parsers/lsx.js +137 -0
- package/dist/surfaces/baldursgate3/index/parsers/stats.js +45 -0
- package/dist/surfaces/baldursgate3/index/parsers/treasuretable.js +57 -0
- package/dist/surfaces/baldursgate3/index/parsers/xmlutil.js +142 -0
- package/dist/surfaces/baldursgate3/index/queries.js +327 -0
- package/dist/surfaces/baldursgate3/index/schema.js +62 -0
- package/dist/surfaces/baldursgate3/index.js +3 -0
- package/dist/surfaces/baldursgate3/logs.js +278 -0
- package/dist/surfaces/baldursgate3/modsettings.js +115 -0
- package/dist/surfaces/baldursgate3/pak.js +153 -0
- package/dist/surfaces/baldursgate3/settings.js +49 -0
- package/dist/surfaces/baldursgate3/surface.js +232 -0
- package/dist/surfaces/baldursgate3/validators/bridge.js +7 -0
- package/dist/surfaces/baldursgate3/validators/files.js +476 -0
- package/dist/surfaces/baldursgate3/validators/items.js +1001 -0
- package/dist/surfaces/baldursgate3/validators/progression.js +734 -0
- package/dist/surfaces/baldursgate3/validators/stats.js +1076 -0
- package/dist/surfaces/baldursgate3/validators/story.js +790 -0
- package/dist/surfaces/baldursgate3/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/compat.js +223 -0
- package/dist/surfaces/cyberpunk2077/index/build.js +231 -0
- package/dist/surfaces/cyberpunk2077/index/index.js +17 -0
- package/dist/surfaces/cyberpunk2077/index/info.js +51 -0
- package/dist/surfaces/cyberpunk2077/index/model.js +52 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweak.js +483 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweakxl-yaml.js +183 -0
- package/dist/surfaces/cyberpunk2077/index/queries.js +504 -0
- package/dist/surfaces/cyberpunk2077/index/resource.js +135 -0
- package/dist/surfaces/cyberpunk2077/index/schema.js +90 -0
- package/dist/surfaces/cyberpunk2077/index.js +3 -0
- package/dist/surfaces/cyberpunk2077/logs.js +742 -0
- package/dist/surfaces/cyberpunk2077/paths.js +12 -0
- package/dist/surfaces/cyberpunk2077/surface.js +218 -0
- package/dist/surfaces/cyberpunk2077/validators/bridge.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/cr2w.js +349 -0
- package/dist/surfaces/cyberpunk2077/validators/garments.js +1181 -0
- package/dist/surfaces/cyberpunk2077/validators/mesh.js +338 -0
- package/dist/surfaces/cyberpunk2077/validators/modsettings.js +120 -0
- package/dist/surfaces/cyberpunk2077/validators/packaging.js +463 -0
- package/dist/surfaces/cyberpunk2077/validators/red4ext.js +318 -0
- package/dist/surfaces/cyberpunk2077/validators/redscript.js +193 -0
- package/dist/surfaces/cyberpunk2077/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/tweaks.js +768 -0
- package/dist/surfaces/cyberpunk2077/validators/vehicles.js +531 -0
- package/dist/surfaces/cyberpunk2077/validators/xl.js +308 -0
- package/dist/surfaces/eldenring/binders.js +111 -0
- package/dist/surfaces/eldenring/compat.js +166 -0
- package/dist/surfaces/eldenring/dcx.js +49 -0
- package/dist/surfaces/eldenring/index.js +13 -0
- package/dist/surfaces/eldenring/loaders.js +132 -0
- package/dist/surfaces/eldenring/logs.js +67 -0
- package/dist/surfaces/eldenring/paramdef.js +256 -0
- package/dist/surfaces/eldenring/params.js +129 -0
- package/dist/surfaces/eldenring/surface.js +121 -0
- package/dist/surfaces/eldenring/tools.js +52 -0
- package/dist/surfaces/eldenring/validators/binders.js +193 -0
- package/dist/surfaces/eldenring/validators/packages.js +159 -0
- package/dist/surfaces/eldenring/validators/params.js +334 -0
- package/dist/surfaces/eldenring/validators/profiles.js +287 -0
- package/dist/surfaces/index.js +34 -0
- package/dist/surfaces/nivalisnights/compat.js +229 -0
- package/dist/surfaces/nivalisnights/index/build.js +310 -0
- package/dist/surfaces/nivalisnights/index/index.js +5 -0
- package/dist/surfaces/nivalisnights/index/queries.js +231 -0
- package/dist/surfaces/nivalisnights/index.js +4 -0
- package/dist/surfaces/nivalisnights/logs.js +473 -0
- package/dist/surfaces/nivalisnights/surface.js +195 -0
- package/dist/surfaces/skyrimse/archives.js +229 -0
- package/dist/surfaces/skyrimse/compat.js +163 -0
- package/dist/surfaces/skyrimse/index.js +12 -0
- package/dist/surfaces/skyrimse/loadorder.js +174 -0
- package/dist/surfaces/skyrimse/logs.js +241 -0
- package/dist/surfaces/skyrimse/plugins.js +149 -0
- package/dist/surfaces/skyrimse/records.js +94 -0
- package/dist/surfaces/skyrimse/surface.js +240 -0
- package/dist/surfaces/skyrimse/validators/archive-records.js +165 -0
- package/dist/surfaces/skyrimse/validators/archives.js +110 -0
- package/dist/surfaces/skyrimse/validators/plugins.js +374 -0
- package/dist/surfaces/skyrimse/validators/records.js +117 -0
- package/dist/surfaces/stardewvalley/compat.js +190 -0
- package/dist/surfaces/stardewvalley/config.js +42 -0
- package/dist/surfaces/stardewvalley/contentpatcher.js +203 -0
- package/dist/surfaces/stardewvalley/index/index.js +229 -0
- package/dist/surfaces/stardewvalley/index/wiki.js +190 -0
- package/dist/surfaces/stardewvalley/index.js +12 -0
- package/dist/surfaces/stardewvalley/logs.js +307 -0
- package/dist/surfaces/stardewvalley/mods.js +182 -0
- package/dist/surfaces/stardewvalley/surface.js +244 -0
- package/dist/surfaces/stardewvalley/validators/content.js +321 -0
- package/dist/surfaces/stardewvalley/validators/fields.js +147 -0
- package/dist/surfaces/stardewvalley/validators/loadorder.js +69 -0
- package/dist/surfaces/stardewvalley/validators/manifest.js +221 -0
- package/dist/surfaces/subnautica2/compat.js +138 -0
- package/dist/surfaces/subnautica2/index.js +5 -0
- package/dist/surfaces/subnautica2/logs.js +129 -0
- package/dist/surfaces/subnautica2/paks.js +173 -0
- package/dist/surfaces/subnautica2/surface.js +151 -0
- package/dist/surfaces/subnautica2/validators/packaging.js +298 -0
- package/dist/surfaces/valheim/compat.js +171 -0
- package/dist/surfaces/valheim/index/index.js +301 -0
- package/dist/surfaces/valheim/index/tables.js +103 -0
- package/dist/surfaces/valheim/index.js +11 -0
- package/dist/surfaces/valheim/logs.js +197 -0
- package/dist/surfaces/valheim/packaging.js +131 -0
- package/dist/surfaces/valheim/plugins.js +270 -0
- package/dist/surfaces/valheim/references.js +121 -0
- package/dist/surfaces/valheim/surface.js +223 -0
- package/dist/surfaces/valheim/validators/packaging.js +218 -0
- package/dist/surfaces/valheim/validators/plugins.js +287 -0
- package/dist/surfaces/valheim/validators/references.js +169 -0
- package/knowledge/baldursgate3/animations.gr2.yaml +166 -0
- package/knowledge/baldursgate3/audio.voice.yaml +182 -0
- package/knowledge/baldursgate3/audio.wwise.yaml +104 -0
- package/knowledge/baldursgate3/charactercreation.heads-hair.yaml +193 -0
- package/knowledge/baldursgate3/communitylibrary.shared-content.yaml +129 -0
- package/knowledge/baldursgate3/compatibilityframework.api.yaml +176 -0
- package/knowledge/baldursgate3/crash.causes.yaml +90 -0
- package/knowledge/baldursgate3/dialogue.dialogbank.yaml +120 -0
- package/knowledge/baldursgate3/dialogue.files.yaml +236 -0
- package/knowledge/baldursgate3/dialogue.osiris-goals.yaml +386 -0
- package/knowledge/baldursgate3/dialogue.yaml +122 -0
- package/knowledge/baldursgate3/feats.classes.yaml +164 -0
- package/knowledge/baldursgate3/items.cloth-physics.yaml +167 -0
- package/knowledge/baldursgate3/items.roottemplates.yaml +320 -0
- package/knowledge/baldursgate3/items.visualbank.yaml +628 -0
- package/knowledge/baldursgate3/journal.quests.yaml +214 -0
- package/knowledge/baldursgate3/loadorder.modsettings.yaml +128 -0
- package/knowledge/baldursgate3/localization.handles.yaml +92 -0
- package/knowledge/baldursgate3/misc.encoding-and-practice.yaml +111 -0
- package/knowledge/baldursgate3/origins.companions.yaml +144 -0
- package/knowledge/baldursgate3/osiris.signatures.yaml +211 -0
- package/knowledge/baldursgate3/packaging.meta.yaml +155 -0
- package/knowledge/baldursgate3/packaging.paks.yaml +79 -0
- package/knowledge/baldursgate3/process.launch.yaml +34 -0
- package/knowledge/baldursgate3/progressions.yaml +92 -0
- package/knowledge/baldursgate3/publishing.modio-nexus.yaml +170 -0
- package/knowledge/baldursgate3/publishing.toolkit-modio.yaml +135 -0
- package/knowledge/baldursgate3/races.progression.yaml +228 -0
- package/knowledge/baldursgate3/scriptextender.console.yaml +257 -0
- package/knowledge/baldursgate3/scriptextender.yaml +252 -0
- package/knowledge/baldursgate3/stats.boosts.yaml +293 -0
- package/knowledge/baldursgate3/stats.equipment-kits.yaml +69 -0
- package/knowledge/baldursgate3/stats.interrupts.yaml +45 -0
- package/knowledge/baldursgate3/stats.itemcombos.yaml +65 -0
- package/knowledge/baldursgate3/stats.spells.yaml +293 -0
- package/knowledge/baldursgate3/stats.weapons.yaml +210 -0
- package/knowledge/baldursgate3/toolchain.divine.yaml +179 -0
- package/knowledge/baldursgate3/toolchain.lslib-formats.yaml +242 -0
- package/knowledge/baldursgate3/toolkit.levels.yaml +177 -0
- package/knowledge/baldursgate3/ui.icons-atlas.yaml +78 -0
- package/knowledge/baldursgate3/ui.icons.yaml +412 -0
- package/knowledge/baldursgate3/ui.mcm.yaml +161 -0
- package/knowledge/baldursgate3/vfx.materials.yaml +174 -0
- package/knowledge/baldursgate3/visuals.characterfix.yaml +73 -0
- package/knowledge/cyberpunk2077/animations.anims.yaml +118 -0
- package/knowledge/cyberpunk2077/anims.archivexl.yaml +163 -0
- package/knowledge/cyberpunk2077/anims.authoring.yaml +579 -0
- package/knowledge/cyberpunk2077/anims.encoder.yaml +156 -0
- package/knowledge/cyberpunk2077/anims.graph.yaml +629 -0
- package/knowledge/cyberpunk2077/anims.method.yaml +360 -0
- package/knowledge/cyberpunk2077/anims.pipeline.yaml +352 -0
- package/knowledge/cyberpunk2077/anims.roundtrip.yaml +222 -0
- package/knowledge/cyberpunk2077/anims.sets.yaml +176 -0
- package/knowledge/cyberpunk2077/archivexl.bodytypes.yaml +149 -0
- package/knowledge/cyberpunk2077/archivexl.dynamic-appearances.yaml +218 -0
- package/knowledge/cyberpunk2077/archivexl.manifest.yaml +214 -0
- package/knowledge/cyberpunk2077/audio.events.yaml +168 -0
- package/knowledge/cyberpunk2077/audio.sounds.yaml +164 -0
- package/knowledge/cyberpunk2077/audio.voicesets.yaml +146 -0
- package/knowledge/cyberpunk2077/cet.sandbox.yaml +219 -0
- package/knowledge/cyberpunk2077/clothing.garments.yaml +283 -0
- package/knowledge/cyberpunk2077/clothing.refits.yaml +215 -0
- package/knowledge/cyberpunk2077/codeware.overview.yaml +111 -0
- package/knowledge/cyberpunk2077/codeware.systems.yaml +192 -0
- package/knowledge/cyberpunk2077/drones.combat.yaml +416 -0
- package/knowledge/cyberpunk2077/drones.control.yaml +552 -0
- package/knowledge/cyberpunk2077/entities.appearance.yaml +166 -0
- package/knowledge/cyberpunk2077/equipmentex.slots.yaml +151 -0
- package/knowledge/cyberpunk2077/fx.effects.yaml +246 -0
- package/knowledge/cyberpunk2077/fx.lights.yaml +171 -0
- package/knowledge/cyberpunk2077/hair.modding.yaml +145 -0
- package/knowledge/cyberpunk2077/items.wiring.yaml +246 -0
- package/knowledge/cyberpunk2077/loadorder.archives.yaml +71 -0
- package/knowledge/cyberpunk2077/mesh.blender.yaml +209 -0
- package/knowledge/cyberpunk2077/nativedb.dump.yaml +98 -0
- package/knowledge/cyberpunk2077/npc.appearance.yaml +275 -0
- package/knowledge/cyberpunk2077/npc.behaviour.yaml +128 -0
- package/knowledge/cyberpunk2077/npc.locomotion.yaml +490 -0
- package/knowledge/cyberpunk2077/packaging.deploy.yaml +175 -0
- package/knowledge/cyberpunk2077/packaging.variants.yaml +176 -0
- package/knowledge/cyberpunk2077/player.control.yaml +918 -0
- package/knowledge/cyberpunk2077/process.assetbuild.yaml +154 -0
- package/knowledge/cyberpunk2077/process.lessons.yaml +276 -0
- package/knowledge/cyberpunk2077/quests.minor.yaml +46 -0
- package/knowledge/cyberpunk2077/quests.scenes.yaml +282 -0
- package/knowledge/cyberpunk2077/quickhacks.tiers.yaml +41 -0
- package/knowledge/cyberpunk2077/red4ext.api.yaml +645 -0
- package/knowledge/cyberpunk2077/red4ext.plugins.yaml +124 -0
- package/knowledge/cyberpunk2077/redhottools.hotreload.yaml +245 -0
- package/knowledge/cyberpunk2077/redscript.compile-log.yaml +76 -0
- package/knowledge/cyberpunk2077/redscript.modules.yaml +118 -0
- package/knowledge/cyberpunk2077/toolchain.wolvenkit.yaml +163 -0
- package/knowledge/cyberpunk2077/tweakdb.loot-recipes.yaml +184 -0
- package/knowledge/cyberpunk2077/tweakdb.melee.yaml +352 -0
- package/knowledge/cyberpunk2077/tweakdb.weapons.yaml +325 -0
- package/knowledge/cyberpunk2077/tweakxl.hotreload.yaml +151 -0
- package/knowledge/cyberpunk2077/tweakxl.yaml-syntax.yaml +208 -0
- package/knowledge/cyberpunk2077/ui.icons.yaml +259 -0
- package/knowledge/cyberpunk2077/ui.inkatlas.yaml +81 -0
- package/knowledge/cyberpunk2077/ui.modsettings.yaml +204 -0
- package/knowledge/cyberpunk2077/vehicles.control.yaml +475 -0
- package/knowledge/cyberpunk2077/vehicles.dashboard-ui.yaml +203 -0
- package/knowledge/cyberpunk2077/vehicles.entities.yaml +195 -0
- package/knowledge/cyberpunk2077/vehicles.wiring.yaml +137 -0
- package/knowledge/cyberpunk2077/wolvenkit.cli.yaml +167 -0
- package/knowledge/cyberpunk2077/workspot.system.yaml +55 -0
- package/knowledge/cyberpunk2077/world.interactions.yaml +41 -0
- package/knowledge/cyberpunk2077/world.loot-container.yaml +167 -0
- package/knowledge/cyberpunk2077/world.sectors.yaml +233 -0
- package/knowledge/eldenring/formats.binders.yaml +237 -0
- package/knowledge/eldenring/launcher.me3.yaml +230 -0
- package/knowledge/eldenring/launcher.modengine2.yaml +119 -0
- package/knowledge/eldenring/params.paramdef.yaml +149 -0
- package/knowledge/eldenring/params.regulation.yaml +142 -0
- package/knowledge/eldenring/saves.online.yaml +118 -0
- package/knowledge/eldenring/toolchain.cli.yaml +256 -0
- package/knowledge/nivalisnights/modding.runtime.yaml +157 -0
- package/knowledge/skyrimse/archives.bsa.yaml +212 -0
- package/knowledge/skyrimse/install.detection.yaml +41 -0
- package/knowledge/skyrimse/loadorder.files.yaml +242 -0
- package/knowledge/skyrimse/plugins.esl.yaml +189 -0
- package/knowledge/skyrimse/plugins.format.yaml +224 -0
- package/knowledge/skyrimse/skse.runtime.yaml +283 -0
- package/knowledge/skyrimse/toolchain.xedit-spriggit.yaml +336 -0
- package/knowledge/stardewvalley/contentpatcher.format.yaml +338 -0
- package/knowledge/stardewvalley/distribution.channels.yaml +236 -0
- package/knowledge/stardewvalley/game.versions.yaml +202 -0
- package/knowledge/stardewvalley/install.layout.yaml +277 -0
- package/knowledge/stardewvalley/smapi.loader.yaml +284 -0
- package/knowledge/stardewvalley/smapi.logs.yaml +329 -0
- package/knowledge/stardewvalley/smapi.manifest.yaml +293 -0
- package/knowledge/stardewvalley/toolchain.build.yaml +261 -0
- package/knowledge/stardewvalley/wiki.dataformat.yaml +130 -0
- package/knowledge/subnautica2/game.build.yaml +331 -0
- package/knowledge/subnautica2/modding.state.yaml +210 -0
- package/knowledge/subnautica2/ue5.containers.yaml +72 -0
- package/knowledge/subnautica2/ue5.paks.yaml +203 -0
- package/knowledge/subnautica2/ue5.tooling.yaml +175 -0
- package/knowledge/subnautica2/ue5.ue4ss.yaml +203 -0
- package/knowledge/valheim/bepinex.loader.yaml +247 -0
- package/knowledge/valheim/bepinex.plugins.yaml +251 -0
- package/knowledge/valheim/game.versions.yaml +321 -0
- package/knowledge/valheim/install.layout.yaml +216 -0
- package/knowledge/valheim/jotunn.library.yaml +334 -0
- package/knowledge/valheim/thunderstore.packaging.yaml +217 -0
- package/knowledge/valheim/toolchain.build.yaml +111 -0
- package/package.json +29 -0
- package/scaffolds/baldursgate3/new-class-injection.yaml +148 -0
- package/scaffolds/baldursgate3/new-item.yaml +264 -0
- package/scaffolds/baldursgate3/new-mod.yaml +174 -0
- package/scaffolds/baldursgate3/new-passive.yaml +100 -0
- package/scaffolds/baldursgate3/new-project.yaml +118 -0
- package/scaffolds/baldursgate3/new-quest-stub.yaml +159 -0
- package/scaffolds/baldursgate3/new-spell.yaml +102 -0
- package/scaffolds/baldursgate3/new-status.yaml +119 -0
- package/scaffolds/baldursgate3/sequences/subclass-kit.yaml +50 -0
- package/scaffolds/cyberpunk2077/edit-tweak.yaml +70 -0
- package/scaffolds/cyberpunk2077/mesh-export-preset.yaml +170 -0
- package/scaffolds/cyberpunk2077/new-entity-patch.yaml +255 -0
- package/scaffolds/cyberpunk2077/new-garment-refit.yaml +279 -0
- package/scaffolds/cyberpunk2077/new-item-chain.yaml +548 -0
- package/scaffolds/cyberpunk2077/new-localization.yaml +130 -0
- package/scaffolds/cyberpunk2077/new-mod-settings.yaml +133 -0
- package/scaffolds/cyberpunk2077/new-player-replacer.yaml +1003 -0
- package/scaffolds/cyberpunk2077/new-project.yaml +157 -0
- package/scaffolds/cyberpunk2077/new-sector-node.yaml +156 -0
- package/scaffolds/cyberpunk2077/new-tweak.yaml +121 -0
- package/scaffolds/cyberpunk2077/new-vehicle-livery.yaml +148 -0
- package/scaffolds/cyberpunk2077/new-workspot-entity.yaml +177 -0
- package/scaffolds/cyberpunk2077/sequences/iconic-weapon.yaml +72 -0
- package/scaffolds/cyberpunk2077/sequences/quickhack-takeover.yaml +213 -0
- package/scaffolds/stardewvalley/new-cp-patch.yaml +106 -0
- package/scaffolds/stardewvalley/new-csharp-mod.yaml +195 -0
- package/scaffolds/stardewvalley/new-project.yaml +184 -0
- package/scaffolds/stardewvalley/sequences/content-pack.yaml +31 -0
- package/scripts/mw-tool.mjs +184 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
# new-item-chain (Cyberpunk 2077). A TweakXL record cloned from a
|
|
2
|
+
# vanilla/project `$base`, the `.xl` localization + factory entries, a
|
|
3
|
+
# factory CSV row, an `en-us.json.json` row pair, and one CR2W source under
|
|
4
|
+
# `sources/entities/<slug>/` cloned from a `template-record` input
|
|
5
|
+
# (`root.ent.json` for an item base, `appearance.app.json` for a weapon
|
|
6
|
+
# base; see the two branches below). `base`'s blueprint check is a
|
|
7
|
+
# `requires.through` worked example.
|
|
8
|
+
#
|
|
9
|
+
# The factory row is written as plain CSV text via `insert-csv-row`, not a
|
|
10
|
+
# JSON source plus a `convert deserialize` step. The shipped
|
|
11
|
+
# `factory_parts.csv` is compiled CR2W, but no fixture or validator in this
|
|
12
|
+
# repo carries a confirmed JSON-source shape for a compiled CSV (unlike
|
|
13
|
+
# `.ent`/`.app`/`en-us.json`, all attested by real examples):
|
|
14
|
+
# `cp2077.garments.factory-csv-rows` itself reads the staged file as plain
|
|
15
|
+
# CSV text, and the proven-clean `jacket.ok.synthetic` fixture ships its
|
|
16
|
+
# `factory_parts.csv` as plain text too. Inventing an unconfirmed JSON shape
|
|
17
|
+
# for the one file with no attested example would be guessing, so a real
|
|
18
|
+
# release build's compiled-CR2W factory CSV is left to a WolvenKit pass by
|
|
19
|
+
# hand. The `.inkatlas` entry the catalog also lists is left to the manual
|
|
20
|
+
# checklist for the same reason `new-item`'s recolor is: registering an icon
|
|
21
|
+
# needs UV coordinates only a human (or a GUI atlas tool, which does not
|
|
22
|
+
# exist yet) can supply.
|
|
23
|
+
#
|
|
24
|
+
# Deserialize steps:
|
|
25
|
+
# - The two `convert deserialize` build steps use the positional-input,
|
|
26
|
+
# directory-output form (`convert deserialize <src> -o <dir>`; see
|
|
27
|
+
# new-sector-node.yaml's matching note), via two `*CompiledDir` inputs:
|
|
28
|
+
# smaller than a general "directory of this path" derived value in the
|
|
29
|
+
# engine for the one pair of callers that need it.
|
|
30
|
+
# - WolvenKit.CLI names a `convert deserialize` output by stripping
|
|
31
|
+
# exactly one trailing `.json` off the source file's own name, confirmed
|
|
32
|
+
# on three real files (`x.streamingsector.json` -> `x.streamingsector`,
|
|
33
|
+
# `x.ent.json` -> `x.ent`, and `en-us.source.json` -> `en-us.source`,
|
|
34
|
+
# not `en-us.json`). The compiled localization resource the
|
|
35
|
+
# `.archive.xl` manifest points at (`mod\<slug>\en-us.json`) is itself a
|
|
36
|
+
# CR2W resource named `en-us.json`, so its JSON source has to be named
|
|
37
|
+
# `en-us.json.json` for the tool's real rule to produce it. A name like
|
|
38
|
+
# `en-us.source.json` only works for people who compile in the WolvenKit
|
|
39
|
+
# GUI and rename the output themselves afterward; it is not a convention
|
|
40
|
+
# ModWright's unattended `build` can honour. So the free-form file
|
|
41
|
+
# inputs are collapsed into a directory-only pair (`enUsSourceDir`,
|
|
42
|
+
# `entCompiledDir`) with both filenames fixed by the scaffold itself,
|
|
43
|
+
# `en-us.json.json` on the source side and `en-us.json` on the compiled
|
|
44
|
+
# side, so the two agree by construction instead of trusting a
|
|
45
|
+
# caller-supplied name to happen to match. The same fix applies to
|
|
46
|
+
# new-garment-refit's `resource.patch` and new-sector-node. No engine
|
|
47
|
+
# change is needed: both are plain `${input.*}` interpolation directly in
|
|
48
|
+
# each op's `path`/`args`/`expectOutputs`. The manifest names one
|
|
49
|
+
# mod/<slug> folder for both compiled files, so one compiled directory
|
|
50
|
+
# serves both.
|
|
51
|
+
#
|
|
52
|
+
# The blueprint:
|
|
53
|
+
# - No real vanilla base is already an iconic blueprint. A
|
|
54
|
+
# `requires.through` check ("the blueprint must already be an iconic
|
|
55
|
+
# blueprint") was run against 15 real vanilla iconic and non-iconic
|
|
56
|
+
# weapons and satisfied by NONE of them: every real weapon's blueprint
|
|
57
|
+
# carries only plain `<Family>_WeaponMod1/2Element` children, never an
|
|
58
|
+
# `Iconic*ModElement`. A shipped iconic weapon mod never inherits an
|
|
59
|
+
# iconic slot from its vanilla `$base` either: it authors its OWN
|
|
60
|
+
# blueprint, `$base`'d off the vanilla base's own blueprint, adding the
|
|
61
|
+
# iconic element itself (fact
|
|
62
|
+
# cp2077.tweakdb.iconic-blueprint-required-for-mod-slot). So `requires`
|
|
63
|
+
# only asks that the base's `blueprint` flat, when present, resolves to
|
|
64
|
+
# a real record (a weapon precondition, not an iconic one; a non-weapon
|
|
65
|
+
# base with no `blueprint` flat at all stays not-applicable); a
|
|
66
|
+
# project-owned `<ItemName>Blueprint` record is authored, `$base`'d off
|
|
67
|
+
# the base's own real blueprint (exposed into `${template.baseBlueprint}`
|
|
68
|
+
# by the `requires` entry's `expose`, engine.ts), and the new item's own
|
|
69
|
+
# `blueprint:` flat is set to it. Both emits are gated on
|
|
70
|
+
# `when: { templateDefined: baseBlueprint }` (a general emit guard,
|
|
71
|
+
# engine.ts/types.ts) so a non-weapon base's chain is untouched.
|
|
72
|
+
# - `iconicModElementName` (default `Items.IconicRangedWeaponModElement`,
|
|
73
|
+
# confirmed in game) is a plain input, not hardcoded. The melee
|
|
74
|
+
# equivalent is Items.IconicMeleeWeaponModElement (slot
|
|
75
|
+
# AttachmentSlots.IconicMeleeWeaponMod1), read from the installed game's
|
|
76
|
+
# blueprint_elements.tweak on 2026-09-11 (fact
|
|
77
|
+
# cp2077.tweakdb.melee.iconic-melee-mod-element-is-items-iconicmeleeweaponmodelement);
|
|
78
|
+
# a melee item chain passes that name. Separately worth knowing: a
|
|
79
|
+
# shipped melee iconic (a katana) never clones a blueprint at all. It
|
|
80
|
+
# sets `blueprint: Items.Iconic_Melee_Blueprint`, an existing vanilla
|
|
81
|
+
# record that already carries the iconic slot (fact
|
|
82
|
+
# cp2077.tweakdb.melee.iconic-quality-pattern-confirmed-across-mods), so
|
|
83
|
+
# a melee caller may prefer overriding this scaffold's own `blueprint:`
|
|
84
|
+
# flat to that vanilla record afterward instead of trusting an unproven
|
|
85
|
+
# `iconicModElementName`.
|
|
86
|
+
# - The new blueprint record's shape follows the shipped one: `$base`
|
|
87
|
+
# plus a restated `rootElement` whose `childElements` is a plain list,
|
|
88
|
+
# with no `!append` tag (a shipped file uses `!append` only on the item
|
|
89
|
+
# record's own top-level list flats, never inside `rootElement`). The
|
|
90
|
+
# shipped file also restates the base blueprint's `slot:` and its
|
|
91
|
+
# inherited childElements. Those are values only the index knows, so a
|
|
92
|
+
# `blueprint-root` lookup renders the base root (slot, named elements by
|
|
93
|
+
# name, inline elements as nested mappings) and
|
|
94
|
+
# `requires[].through.expose` carries it into the emit. An
|
|
95
|
+
# iconic-only restatement gave the item no slots at all (observed
|
|
96
|
+
# 2026-09-11).
|
|
97
|
+
# - `cp2077.vehicles.inkatlas-uv-range` is not in `satisfies`: it only
|
|
98
|
+
# applies to `*.inkatlas.json` files, which this scaffold never writes
|
|
99
|
+
# (the inkatlas registration is the manual checklist's own job, per the
|
|
100
|
+
# "no GUI atlas tool exists yet" note above).
|
|
101
|
+
# `cp2077.vehicles.inkatlas-part-resolves` stays: it is project-scoped
|
|
102
|
+
# (`appliesTo: project`), so it genuinely runs every time.
|
|
103
|
+
#
|
|
104
|
+
# The chain has two branches (2026-09-12), keyed on the same `baseBlueprint`
|
|
105
|
+
# guard the blueprint emits use.
|
|
106
|
+
# - A base WITHOUT a blueprint flat (a garment, a loot item): the item
|
|
107
|
+
# branch. The root entity is the appearance dictionary
|
|
108
|
+
# (cp2077.items.wiring.root-entity-is-appearance-lookup-dictionary), so
|
|
109
|
+
# a root.ent is cloned from the template with its first appearance
|
|
110
|
+
# pointed at mod\<slug>\appearance.app. This branch has a known gap:
|
|
111
|
+
# nothing this scaffold writes points AT that root.ent (the record names
|
|
112
|
+
# the factory row and the row names the .app), so wiring (or dropping)
|
|
113
|
+
# the root entity is the modder's own job.
|
|
114
|
+
# - A base WITH a blueprint flat (all 15 real vanilla weapons checked
|
|
115
|
+
# carry one): the weapon branch.
|
|
116
|
+
# A vanilla weapon record names no entity of its own: Items.Base_Weapon
|
|
117
|
+
# sets entityName=weapon_root, which weapons.csv maps to
|
|
118
|
+
# base\weapons\weapon_root.ent, a shared root with an EMPTY appearances
|
|
119
|
+
# list, and its look is the .app that weapons_appearances.csv maps its
|
|
120
|
+
# appearanceResourceName to (Preset_Kenshin_Default ->
|
|
121
|
+
# base\weapons\firearms\handgun\arasaka_kenshin\w_handgun__arasaka_kenshin.app).
|
|
122
|
+
# Cloning weapon_root.ent therefore cannot work (the appearance rewrite
|
|
123
|
+
# indexes appearances[0] of an empty list) and would be pointless if it
|
|
124
|
+
# did. A shipped weapon mod ships NO root entity at all: its
|
|
125
|
+
# factory_parts.csv maps the weapon's row to mod\<slug>\<weapon>.app
|
|
126
|
+
# and the record's appearanceResourceName names that row (fact
|
|
127
|
+
# cp2077.items.wiring.weapon-look-is-an-app-row-not-a-root-entity). So
|
|
128
|
+
# for a weapon base the template must be the base's own .app (kind
|
|
129
|
+
# weapon-app), cloned verbatim to sources/.../appearance.app.json with
|
|
130
|
+
# only its ArchiveFileName rewritten, compiled beside en-us.json, and
|
|
131
|
+
# named by the factory row this scaffold already writes. The two
|
|
132
|
+
# write-json-from-template emits and the two deserialize steps are
|
|
133
|
+
# mutually exclusive on `baseBlueprint`, the same way the two record
|
|
134
|
+
# blocks are; `entTemplate`'s expectKind map keys the .app kind for a
|
|
135
|
+
# WeaponItem base so a weapon-ent (or an unrelated entity such as a
|
|
136
|
+
# loot-container .ent) is refused with the reason.
|
|
137
|
+
# One gap the guard language cannot close: the branch keys on
|
|
138
|
+
# `baseBlueprint`, `expectKind` keys on `baseType`, so a WeaponItem
|
|
139
|
+
# base carrying no blueprint flat would demand an .app template and
|
|
140
|
+
# then run the ITEM branch on it: `setAtPath` would write
|
|
141
|
+
# appearances.0.name onto the .app's first appearance *handle* instead
|
|
142
|
+
# of refusing (jsonpath.ts only throws on a missing array element, not
|
|
143
|
+
# a wrong-shaped one). No such base has been seen (the 15 checked all
|
|
144
|
+
# carry a blueprint), and `when` has no form for "the base type is X";
|
|
145
|
+
# closing it properly needs an engine-side guard.
|
|
146
|
+
id: cyberpunk2077.new-item-chain
|
|
147
|
+
game: cyberpunk2077
|
|
148
|
+
title: New Cyberpunk 2077 item chain (TweakXL + ArchiveXL + entity)
|
|
149
|
+
summary: Clone a vanilla/project item's TweakXL record, register it in an .xl manifest with a factory row and localization entries, and clone its root .ent (an item base) or its appearance .app (a weapon base) from a template.
|
|
150
|
+
modTypes: [weapon, item, loot, garment]
|
|
151
|
+
needs: { index: true }
|
|
152
|
+
inputs:
|
|
153
|
+
- type: string
|
|
154
|
+
name: itemName
|
|
155
|
+
prompt: "Item name, used for the TweakDB record and LocKey namespace, e.g. TestBlade."
|
|
156
|
+
pattern: "^[A-Za-z][A-Za-z0-9_]*$"
|
|
157
|
+
- type: string
|
|
158
|
+
name: modSlug
|
|
159
|
+
prompt: "Lowercase depot folder name for this item, e.g. testblade (used in every mod\\\\<slug>\\\\... path)."
|
|
160
|
+
pattern: "^[a-z][a-z0-9_]*$"
|
|
161
|
+
- type: index-ref
|
|
162
|
+
name: base
|
|
163
|
+
prompt: "$base record this item's TweakXL record inherits from."
|
|
164
|
+
lookup: { kind: chain, params: { name: "${input.base}" } }
|
|
165
|
+
requires:
|
|
166
|
+
# No real vanilla base is already an iconic blueprint (see the header
|
|
167
|
+
# note), so the check is a weapon
|
|
168
|
+
# precondition, not an iconic one — the base's blueprint, when
|
|
169
|
+
# present, must name a real record, or the project-owned blueprint
|
|
170
|
+
# this scaffold builds below would inherit from nothing. `through`
|
|
171
|
+
# fires only when `$base`'s effective `blueprint` flat is present at
|
|
172
|
+
# all — a garment/loot item with no blueprint flat is not a weapon and
|
|
173
|
+
# this check does not apply to it (`expose` then leaves
|
|
174
|
+
# `${template.baseBlueprint}` unset, and the emits gated on it do not
|
|
175
|
+
# run either).
|
|
176
|
+
# The base's record type (WeaponItem, Clothing, ...) is exposed for the entTemplate's kind check below; any value
|
|
177
|
+
# passes here, an absent type leaves ${template.baseType} unset.
|
|
178
|
+
- path: type
|
|
179
|
+
expose: baseType
|
|
180
|
+
matches: ".*"
|
|
181
|
+
reason: "the base's record type is read to check the .ent template's kind against it (any value passes this entry)."
|
|
182
|
+
- path: "flats.blueprint.value"
|
|
183
|
+
expose: baseBlueprint
|
|
184
|
+
through: { kind: chain, param: name, path: name }
|
|
185
|
+
reason: "the base's blueprint flat, once resolved, must name a real TweakDB record — the project-owned blueprint this scaffold builds inherits from it directly (the iconic-mod slot is always a project-authored blueprint, never something a real vanilla base already carries)."
|
|
186
|
+
# A project-owned blueprint that restated only the iconic element gave
|
|
187
|
+
# the item no slots at all (observed 2026-09-11). The
|
|
188
|
+
# base blueprint's root is restated in full from the index (lookup
|
|
189
|
+
# blueprint-root: its slot, its named elements by name, its inline
|
|
190
|
+
# elements as nested mappings), with the iconic element put first,
|
|
191
|
+
# and lands under the emitted `rootElement:` as ${template.baseRootYaml}.
|
|
192
|
+
- path: "flats.blueprint.value"
|
|
193
|
+
through:
|
|
194
|
+
kind: blueprint-root
|
|
195
|
+
param: name
|
|
196
|
+
path: rootYaml
|
|
197
|
+
params: { indent: "4", prepend: "${input.iconicModElementName}" }
|
|
198
|
+
expose: baseRootYaml
|
|
199
|
+
reason: "the base's blueprint must carry a root element this scaffold can restate (a rootElement, or slot/childElements flats along its $base chain): a derived blueprint that restates only the iconic element gives the item no attachment slots at all."
|
|
200
|
+
- type: string
|
|
201
|
+
name: displayName
|
|
202
|
+
prompt: "Player-facing item name."
|
|
203
|
+
- type: string
|
|
204
|
+
name: description
|
|
205
|
+
prompt: "Item description text."
|
|
206
|
+
- type: string
|
|
207
|
+
name: appearanceName
|
|
208
|
+
prompt: "Appearance name this item's root .ent should declare (item branch: a base with no blueprint flat). A weapon base's cloned .app keeps the base's own appearance names and this value is not used."
|
|
209
|
+
default: "default"
|
|
210
|
+
- type: string
|
|
211
|
+
name: iconicModElementName
|
|
212
|
+
prompt: "childElements entry the new project-owned blueprint appends to grant the iconic-mod attachment slot (only used when the base has its own blueprint flat at all). Ranged bases use the default; a melee base passes Items.IconicMeleeWeaponModElement (slot AttachmentSlots.IconicMeleeWeaponMod1, the vanilla melee iconics' own element)."
|
|
213
|
+
default: "Items.IconicRangedWeaponModElement"
|
|
214
|
+
- type: path
|
|
215
|
+
name: tweaksFile
|
|
216
|
+
prompt: "Destination .yaml under a project source of kind \"tweaks\" (created if missing)."
|
|
217
|
+
mustExist: false
|
|
218
|
+
- type: path
|
|
219
|
+
name: xlFile
|
|
220
|
+
prompt: "Destination .archive.xl manifest (created with an empty skeleton if missing). Put it beside the staged folder, e.g. archive-staging/<Project>.archive.xl, not inside it: the pack step stages the archive-staging source, and a manifest inside it would ship in the archive where ArchiveXL never reads it. It is registered as a project source and deployed to archive/pc/mod by its file name."
|
|
221
|
+
mustExist: false
|
|
222
|
+
- type: path
|
|
223
|
+
name: factoryCsvFile
|
|
224
|
+
prompt: "Destination factory CSV under archive-staging (created with a header row if missing)."
|
|
225
|
+
mustExist: false
|
|
226
|
+
- type: path
|
|
227
|
+
name: enUsSourceDir
|
|
228
|
+
prompt: "Directory the localization JSON source should be written to (created with an empty entries[] skeleton if missing). Its filename is fixed by this scaffold — en-us.json.json, not a free-form name — because WolvenKit.CLI's convert deserialize names its output by stripping exactly one trailing \".json\" off the source's own filename: only a source literally named en-us.json.json strips to the en-us.json the .archive.xl manifest points at (a name like en-us.source.json strips to en-us.source instead)."
|
|
229
|
+
mustExist: false
|
|
230
|
+
- type: path
|
|
231
|
+
name: entSourceDir
|
|
232
|
+
prompt: "Directory the cloned CR2W JSON source is written to, typically sources/entities/<slug>. The file name is fixed by this scaffold: root.ent.json for an item base (compiled to mod\\<slug>\\root.ent) or appearance.app.json for a weapon base (the factory row this scaffold writes points at mod\\<slug>\\appearance.app), because WolvenKit.CLI's convert deserialize names its output by stripping exactly one trailing .json off the source's own name."
|
|
233
|
+
mustExist: false
|
|
234
|
+
- type: path
|
|
235
|
+
name: entCompiledDir
|
|
236
|
+
prompt: "Directory the compiled root.ent (or appearance.app, for a weapon base) and en-us.json both land in, typically <archive-staging>/mod/<slug> — passed to WolvenKit.CLI's convert deserialize -o, which takes a directory, not a file. Both file names are fixed by this scaffold to match the manifest and the factory row, which name the same mod/<slug> folder, so one directory serves both (a separate enUsCompiledDir input could only ever agree with this one or be wrong)."
|
|
237
|
+
mustExist: false
|
|
238
|
+
- type: template-record
|
|
239
|
+
name: entTemplate
|
|
240
|
+
prompt: "Cached template-record directory (record.json + content.json) this item's look is cloned from. Its record kind has to fit the base: for a WeaponItem base the base's own appearance resource (kind weapon-app — the .app that weapons_appearances.csv maps the base's appearanceResourceName to; a vanilla weapon has no entity of its own to clone, its weapon_root.ent carries no appearances, and a shipped weapon mod ships an .app and no root entity); for a Clothing base the root entity (kind garment-ent, clothing-ent or item-ent). Observed in game: a loot-container .ent cloned for a weapon hung the game on equip."
|
|
241
|
+
expectKind:
|
|
242
|
+
by: baseType
|
|
243
|
+
# The index keeps a record's type as written: the vanilla dump says
|
|
244
|
+
# WeaponItem, a TweakXL yaml says gamedataWeaponItem_Record; both
|
|
245
|
+
# spellings are keyed.
|
|
246
|
+
map:
|
|
247
|
+
WeaponItem: "^weapon-app$"
|
|
248
|
+
gamedataWeaponItem_Record: "^weapon-app$"
|
|
249
|
+
Clothing: "^(garment|clothing|item)-ent$"
|
|
250
|
+
gamedataClothing_Record: "^(garment|clothing|item)-ent$"
|
|
251
|
+
reason: "A weapon base's look is the .app its appearanceResourceName maps to through weapons_appearances.csv, never a root entity (Items.Base_Weapon's weapon_root.ent has an empty appearances list, and a shipped weapon mod ships an .app and no .ent), and a loot-container .ent cloned for a weapon hung the game on equip (observed in game). Extract the base's .app with `template extract` (kind weapon-app; the path is the base's row in base\\gameplay\\factories\\items\\weapons\\weapons_appearances.csv) for a weapon, or its root entity (kind garment-ent) for clothing, and pass that directory."
|
|
252
|
+
ids:
|
|
253
|
+
- name: recordName
|
|
254
|
+
slot: "Items.${project.name}_${input.itemName}"
|
|
255
|
+
form: tweak-record
|
|
256
|
+
collision:
|
|
257
|
+
project: true
|
|
258
|
+
index: { kind: record, param: name }
|
|
259
|
+
# Always allocated (cheap, collision-checked like any other id), but only ever written when `${template.baseBlueprint}` is set
|
|
260
|
+
# — the two emits below that reference it are both gated on that.
|
|
261
|
+
- name: blueprintName
|
|
262
|
+
slot: "Items.${project.name}_${input.itemName}Blueprint"
|
|
263
|
+
form: tweak-record
|
|
264
|
+
collision:
|
|
265
|
+
project: true
|
|
266
|
+
index: { kind: record, param: name }
|
|
267
|
+
emits:
|
|
268
|
+
# `${ids.recordName}` gets exactly ONE occurrence in this file — these two variants are mutually exclusive (`templateDefined`
|
|
269
|
+
# / `templateUndefined` on the same key), never both. A record redeclared
|
|
270
|
+
# a second time in the same file is a real, confirmed TweakXL "Ambiguous
|
|
271
|
+
# definition" compile failure for at least the dotted-path edit form
|
|
272
|
+
# (cp2077.tweakdb.melee.dotted-path-mod-of-same-file-record-fails); this
|
|
273
|
+
# scaffold does not risk finding out whether a second full-block
|
|
274
|
+
# occurrence is any safer.
|
|
275
|
+
# `appearanceResourceName` names the factory row this scaffold writes
|
|
276
|
+
# (observed 2026-09-11): without it the record inherited the
|
|
277
|
+
# base's appearance, the spawned item wore the base's model, and
|
|
278
|
+
# cp2077.garments.factory-csv-rows, which checks only rows a record names,
|
|
279
|
+
# never looked at the row's unstaged appearance.app. With it, that rule
|
|
280
|
+
# blocks until the .app is staged, which is the truth of the chain.
|
|
281
|
+
- op: insert-block
|
|
282
|
+
path: "${input.tweaksFile}"
|
|
283
|
+
when: { templateDefined: baseBlueprint }
|
|
284
|
+
createIfMissing: ""
|
|
285
|
+
anchor: append
|
|
286
|
+
body: |
|
|
287
|
+
${ids.recordName}:
|
|
288
|
+
$base: ${input.base}
|
|
289
|
+
displayName: LocKey#${project.name}-${input.itemName}-Name
|
|
290
|
+
localizedDescription: LocKey#${project.name}-${input.itemName}-Description
|
|
291
|
+
appearanceResourceName: ${input.itemName}
|
|
292
|
+
blueprint: ${ids.blueprintName}
|
|
293
|
+
- op: insert-block
|
|
294
|
+
path: "${input.tweaksFile}"
|
|
295
|
+
when: { templateUndefined: baseBlueprint }
|
|
296
|
+
createIfMissing: ""
|
|
297
|
+
anchor: append
|
|
298
|
+
body: |
|
|
299
|
+
${ids.recordName}:
|
|
300
|
+
$base: ${input.base}
|
|
301
|
+
displayName: LocKey#${project.name}-${input.itemName}-Name
|
|
302
|
+
localizedDescription: LocKey#${project.name}-${input.itemName}-Description
|
|
303
|
+
appearanceResourceName: ${input.itemName}
|
|
304
|
+
# The shipped-mod pattern: a project-owned blueprint, `$base`'d off the base's own real blueprint,
|
|
305
|
+
# carrying the iconic-mod element — instead of demanding (unsatisfiably,
|
|
306
|
+
# per every real vanilla base checked) that the base already be iconic.
|
|
307
|
+
# Skipped entirely for a non-weapon base with no blueprint flat at all.
|
|
308
|
+
#
|
|
309
|
+
# The emitted shape is a shipped, in-game-verified one (fact
|
|
310
|
+
# cp2077.tweakdb.iconic-blueprint-required-for-mod-slot): `$base` plus a
|
|
311
|
+
# restated `rootElement` whose `childElements` is a plain list naming the
|
|
312
|
+
# iconic element, with NO `!append` tag. A shipped file uses `!append`
|
|
313
|
+
# only on the item record's own top-level list flats (`tags:`,
|
|
314
|
+
# `statModifiers:`), never inside `rootElement`, and nothing confirms
|
|
315
|
+
# TweakXL applies a list-mutation tag at that nesting depth, so this
|
|
316
|
+
# scaffold does not invent one.
|
|
317
|
+
#
|
|
318
|
+
# The shipped file restates the base blueprint's `slot:` and its whole
|
|
319
|
+
# inherited childElements list alongside the iconic element, because a
|
|
320
|
+
# restated rootElement is what the in-game-verified file does. The base's
|
|
321
|
+
# root arrives rendered from the index through the `blueprint-root` lookup
|
|
322
|
+
# (the `requires` entry above), iconic element first, so the emitted
|
|
323
|
+
# record is complete.
|
|
324
|
+
- op: insert-block
|
|
325
|
+
path: "${input.tweaksFile}"
|
|
326
|
+
when: { templateDefined: baseBlueprint }
|
|
327
|
+
anchor: append
|
|
328
|
+
body: |
|
|
329
|
+
${ids.blueprintName}:
|
|
330
|
+
$base: ${template.baseBlueprint}
|
|
331
|
+
rootElement:
|
|
332
|
+
${template.baseRootYaml}
|
|
333
|
+
- op: write-text
|
|
334
|
+
path: "${input.xlFile}"
|
|
335
|
+
ifExists: skip
|
|
336
|
+
body: |
|
|
337
|
+
{
|
|
338
|
+
"localization": { "onscreens": {} },
|
|
339
|
+
"factories": []
|
|
340
|
+
}
|
|
341
|
+
- op: insert-xl-entry
|
|
342
|
+
path: "${input.xlFile}"
|
|
343
|
+
pointer: localization.onscreens.en-us
|
|
344
|
+
value: "mod\\${input.modSlug}\\en-us.json"
|
|
345
|
+
- op: insert-xl-entry
|
|
346
|
+
path: "${input.xlFile}"
|
|
347
|
+
pointer: factories.-
|
|
348
|
+
value: "mod\\${input.modSlug}\\factory_parts.csv"
|
|
349
|
+
- op: insert-csv-row
|
|
350
|
+
path: "${input.factoryCsvFile}"
|
|
351
|
+
row: { name: "${input.itemName}", path: "mod\\${input.modSlug}\\appearance.app", shared: "false" }
|
|
352
|
+
- op: write-text
|
|
353
|
+
path: "${input.enUsSourceDir}/en-us.json.json"
|
|
354
|
+
ifExists: skip
|
|
355
|
+
body: |
|
|
356
|
+
{
|
|
357
|
+
"Header": {
|
|
358
|
+
"WolvenKitVersion": "8.20.0",
|
|
359
|
+
"WKitJsonVersion": "0.0.9",
|
|
360
|
+
"GameVersion": 2310,
|
|
361
|
+
"DataType": "CR2W",
|
|
362
|
+
"ArchiveFileName": "mod\\${input.modSlug}\\en-us.json"
|
|
363
|
+
},
|
|
364
|
+
"Data": {
|
|
365
|
+
"Version": 195,
|
|
366
|
+
"BuildVersion": 0,
|
|
367
|
+
"RootChunk": {
|
|
368
|
+
"$type": "JsonResource",
|
|
369
|
+
"cookingPlatform": "PLATFORM_PC",
|
|
370
|
+
"root": {
|
|
371
|
+
"HandleId": "0",
|
|
372
|
+
"Data": { "$type": "localizationPersistenceOnScreenEntries", "entries": [] }
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"EmbeddedFiles": []
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
- op: insert-xl-entry
|
|
379
|
+
path: "${input.enUsSourceDir}/en-us.json.json"
|
|
380
|
+
pointer: Data.RootChunk.root.Data.entries.-
|
|
381
|
+
value:
|
|
382
|
+
$type: localizationPersistenceOnScreenEntry
|
|
383
|
+
femaleVariant: "${input.displayName}"
|
|
384
|
+
maleVariant: ""
|
|
385
|
+
primaryKey: "0"
|
|
386
|
+
secondaryKey: "${project.name}-${input.itemName}-Name"
|
|
387
|
+
- op: insert-xl-entry
|
|
388
|
+
path: "${input.enUsSourceDir}/en-us.json.json"
|
|
389
|
+
pointer: Data.RootChunk.root.Data.entries.-
|
|
390
|
+
value:
|
|
391
|
+
$type: localizationPersistenceOnScreenEntry
|
|
392
|
+
femaleVariant: "${input.description}"
|
|
393
|
+
maleVariant: ""
|
|
394
|
+
primaryKey: "0"
|
|
395
|
+
secondaryKey: "${project.name}-${input.itemName}-Description"
|
|
396
|
+
# Item branch (see the header): a base with no
|
|
397
|
+
# blueprint flat clones a root entity and points its first appearance at
|
|
398
|
+
# the mod's own .app.
|
|
399
|
+
- op: write-json-from-template
|
|
400
|
+
path: "${input.entSourceDir}/root.ent.json"
|
|
401
|
+
when: { templateUndefined: baseBlueprint }
|
|
402
|
+
template: entTemplate
|
|
403
|
+
rewrite:
|
|
404
|
+
- path: Header.ArchiveFileName
|
|
405
|
+
value: "mod\\${input.modSlug}\\root.ent"
|
|
406
|
+
- path: Data.RootChunk.appearances.0.name.$value
|
|
407
|
+
value: "${input.appearanceName}"
|
|
408
|
+
- path: Data.RootChunk.appearances.0.appearanceName.$value
|
|
409
|
+
value: "${input.appearanceName}"
|
|
410
|
+
- path: Data.RootChunk.appearances.0.appearanceResource.DepotPath.$value
|
|
411
|
+
value: "mod\\${input.modSlug}\\appearance.app"
|
|
412
|
+
- path: Data.RootChunk.defaultAppearance.$value
|
|
413
|
+
value: "${input.appearanceName}"
|
|
414
|
+
strip: []
|
|
415
|
+
renumberHandles: true
|
|
416
|
+
# Weapon branch: a base with a blueprint flat clones the base's own .app
|
|
417
|
+
# verbatim (its appearance names are the base's; the record inherits
|
|
418
|
+
# whichever the base selects) under the name the factory row above
|
|
419
|
+
# already points at. Only the archive-internal name is rewritten — the
|
|
420
|
+
# extracted header carries the extraction's temp path, never a depot path.
|
|
421
|
+
- op: write-json-from-template
|
|
422
|
+
path: "${input.entSourceDir}/appearance.app.json"
|
|
423
|
+
when: { templateDefined: baseBlueprint }
|
|
424
|
+
template: entTemplate
|
|
425
|
+
rewrite:
|
|
426
|
+
- path: Header.ArchiveFileName
|
|
427
|
+
value: "mod\\${input.modSlug}\\appearance.app"
|
|
428
|
+
strip: []
|
|
429
|
+
renumberHandles: true
|
|
430
|
+
# Against a fresh new-project output (no `build` block yet at all), a
|
|
431
|
+
# patch-project without `build.outDir` would leave modwright.json failing
|
|
432
|
+
# to reload ("build.outDir: Required"), the same gap new-sector-node and
|
|
433
|
+
# mesh-export-preset close. `add.outDir` only fills a genuinely missing
|
|
434
|
+
# `build.outDir`; a project that already set one keeps its own value
|
|
435
|
+
# (engine.ts's merge).
|
|
436
|
+
# The two deserialize steps go ahead of the
|
|
437
|
+
# project's stage step (`before: stage`; a project with no stage step gets
|
|
438
|
+
# them appended, with a line in the report's skipped list), or the compiled
|
|
439
|
+
# .ent and en-us.json land after the archive was already packed. The
|
|
440
|
+
# manifest this scaffold writes becomes a project source of kind xl (so
|
|
441
|
+
# the manifest rules see it wherever it lives) and an archive deploy
|
|
442
|
+
# target; both are idempotent across applies (engine.ts's merge).
|
|
443
|
+
# The deserialize step for the cloned CR2W source follows
|
|
444
|
+
# the branch (root.ent for an item base, appearance.app for a weapon base),
|
|
445
|
+
# so it lives in its own guarded patch-project op; the engine accumulates
|
|
446
|
+
# every patch-project op that ran into one merge, in op order (each step
|
|
447
|
+
# goes in ahead of the stage step, so the entity or appearance compiles
|
|
448
|
+
# first, then the localization), and a guarded op that did not run adds
|
|
449
|
+
# nothing.
|
|
450
|
+
- op: patch-project
|
|
451
|
+
when: { templateUndefined: baseBlueprint }
|
|
452
|
+
add:
|
|
453
|
+
steps:
|
|
454
|
+
- step: exec
|
|
455
|
+
id: "deserialize-${input.modSlug}-ent"
|
|
456
|
+
command: wolvenkit-cli
|
|
457
|
+
args: ["convert", "deserialize", "${input.entSourceDir}/root.ent.json", "-o", "${input.entCompiledDir}"]
|
|
458
|
+
expectOutputs: ["${input.entCompiledDir}/root.ent"]
|
|
459
|
+
before: stage
|
|
460
|
+
- op: patch-project
|
|
461
|
+
when: { templateDefined: baseBlueprint }
|
|
462
|
+
add:
|
|
463
|
+
steps:
|
|
464
|
+
- step: exec
|
|
465
|
+
id: "deserialize-${input.modSlug}-app"
|
|
466
|
+
command: wolvenkit-cli
|
|
467
|
+
args: ["convert", "deserialize", "${input.entSourceDir}/appearance.app.json", "-o", "${input.entCompiledDir}"]
|
|
468
|
+
expectOutputs: ["${input.entCompiledDir}/appearance.app"]
|
|
469
|
+
before: stage
|
|
470
|
+
- op: patch-project
|
|
471
|
+
add:
|
|
472
|
+
outDir: "archive-staging"
|
|
473
|
+
sources:
|
|
474
|
+
- id: "xl-${input.modSlug}"
|
|
475
|
+
path: "${input.xlFile}"
|
|
476
|
+
kind: xl
|
|
477
|
+
steps:
|
|
478
|
+
- step: exec
|
|
479
|
+
id: "deserialize-${input.modSlug}-enus"
|
|
480
|
+
command: wolvenkit-cli
|
|
481
|
+
args: ["convert", "deserialize", "${input.enUsSourceDir}/en-us.json.json", "-o", "${input.entCompiledDir}"]
|
|
482
|
+
expectOutputs: ["${input.entCompiledDir}/en-us.json"]
|
|
483
|
+
before: stage
|
|
484
|
+
deployTargets:
|
|
485
|
+
- rootId: archive
|
|
486
|
+
from: "${input.xlFile}"
|
|
487
|
+
locked: false
|
|
488
|
+
backup: true
|
|
489
|
+
templates:
|
|
490
|
+
- ref: entTemplate
|
|
491
|
+
from: "${template.entTemplate.contentPath}"
|
|
492
|
+
provenanceFrom: entTemplate
|
|
493
|
+
# Audited against a fresh new-project output
|
|
494
|
+
# (test/unit/scaffold/catalog-apply.test.ts). `entSourceDir`/`enUsSourceDir`
|
|
495
|
+
# both typically land under `sources/...`, invisible to
|
|
496
|
+
# `cp2077.vehicles.cr2w-unique-ids`/`cr2w-resource-path-shape` unless
|
|
497
|
+
# `cyberpunk2077.new-project` declares a `sources`-kind project source for
|
|
498
|
+
# it (it does, once for every scaffold in this position), so no further
|
|
499
|
+
# change to this file's satisfies[] is needed. The `patch-project` op's
|
|
500
|
+
# `add.outDir` covers a project with no `build` block yet.
|
|
501
|
+
satisfies:
|
|
502
|
+
- cp2077.tweaks.yaml-lint
|
|
503
|
+
- cp2077.tweaks.base-exists
|
|
504
|
+
- cp2077.tweaks.type-known
|
|
505
|
+
- cp2077.tweaks.flat-name-exists
|
|
506
|
+
- cp2077.tweaks.record-name-exists
|
|
507
|
+
- cp2077.tweaks.append-on-list-flat
|
|
508
|
+
- cp2077.tweaks.dotted-path-same-file
|
|
509
|
+
- cp2077.tweaks.instances-resolve
|
|
510
|
+
- cp2077.garments.factory-csv-rows
|
|
511
|
+
- cp2077.garments.xl-entries-resolve
|
|
512
|
+
- cp2077.history.xl-manifest-lint
|
|
513
|
+
- cp2077.history.clean-pack-json-sweep
|
|
514
|
+
- cp2077.vehicles.cr2w-unique-ids
|
|
515
|
+
- cp2077.vehicles.cr2w-resource-path-shape
|
|
516
|
+
- cp2077.vehicles.inkatlas-part-resolves
|
|
517
|
+
manual:
|
|
518
|
+
- title: Icon, inkatlas and (for a weapon base) the modifier slot
|
|
519
|
+
steps:
|
|
520
|
+
- "Draw the item's icon art and register a part + UV rect for it in the mod's .inkatlas (no GUI atlas tool exists yet — see this scaffold's own header note)."
|
|
521
|
+
- "If ${input.base} has a blueprint, ${ids.blueprintName} restates the base blueprint's whole root (slot and every child, from the index) with ${input.iconicModElementName} first, as a hand-written blueprint does; read the block and drop any element the item should not carry (for example a scope element on a weapon that has none). Then confirm it loads without a TweakXL-<timestamp>.log error, spawn the item, open the modding screen and confirm the base's own attachment slots are present beside the IconicWeaponModLegendary slot, and that it is populated with an iconic modifier's stats once one is authored on ${input.iconicModElementName}."
|
|
522
|
+
- "For a weapon base, ${input.entSourceDir}/appearance.app.json is the base's own .app verbatim (the base's meshes, so the item renders as the base until they are swapped): edit its appearances' mesh paths to the mod's own meshes when the look should change, and stage those meshes before packing. A vanilla weapon .app carries every preset appearance the base ships (the Kenshin's has ten); a shipped weapon mod's .app keeps just the single `default` one and its record names no appearanceName flat at all, so trimming the clone down to `default` is what the one working precedent did. For an item base, stage ${input.entSourceDir}/root.ent.json's appearance.app and referenced meshes before packing — the scaffold clones only the root .ent, not the mesh/appearance chain."
|
|
523
|
+
expected: "The item shows a real icon, and (for a weapon base) ${ids.blueprintName} loads cleanly with the iconic slot present and the base's own attachment slots intact on the modding screen."
|
|
524
|
+
claim:
|
|
525
|
+
idSuffix: spawns-with-stats
|
|
526
|
+
claim: "Game.AddToInventory(\"${ids.recordName}\", 1) yields an item whose displayName reads \"${input.displayName}\"."
|
|
527
|
+
testRows:
|
|
528
|
+
- gate: I-1
|
|
529
|
+
title: "Record exists with the right base"
|
|
530
|
+
# cp2077.tweakdb.flat reads a flat's raw TweakDB value — for displayName
|
|
531
|
+
# that is a LocKey handle, not the literal ${input.displayName} text
|
|
532
|
+
# (observed in game: TweakDB:GetFlat(...) returned a
|
|
533
|
+
# LocKey userdata) — so the probe confirms the flat *resolves*, not that
|
|
534
|
+
# it reads back as the display text verbatim; a human still confirms the
|
|
535
|
+
# actual rendered text in the manual checklist above.
|
|
536
|
+
expected: "cp2077.tweakdb.record confirms ${ids.recordName} exists; cp2077.tweakdb.flat confirms its displayName flat resolves (to a LocKey, not literal text — a human confirms the rendered text reads \"${input.displayName}\")."
|
|
537
|
+
manual: false
|
|
538
|
+
probes:
|
|
539
|
+
- kind: cp2077.tweakdb.record
|
|
540
|
+
params: { id: "${ids.recordName}" }
|
|
541
|
+
- kind: cp2077.tweakdb.flat
|
|
542
|
+
params: { id: "${ids.recordName}.displayName" }
|
|
543
|
+
- gate: I-2
|
|
544
|
+
title: "Icon and description review"
|
|
545
|
+
expected: "The spawned item's icon and description render correctly, and (if iconic) the modifier slot is populated."
|
|
546
|
+
manual: true
|
|
547
|
+
probeKinds: []
|
|
548
|
+
evidence: ["ModWright research"]
|