Pagonia Land Manager Changelog¶
User-visible changes to pagonia-manager. The manager bundles the patcher and paker, so their user-facing changes are recorded here as well — one changelog for the whole toolchain instead of three. Follows Keep a Changelog and Semantic Versioning.
The browser-based catalog browser has its own changelog (it ships with the site, not the tagged tool releases).
The repo-root
CHANGELOG.mdis a separate, unrelated log: it tracks GameDatabase changes per Pioneers of Pagonia version (the XML data the game ships), not tooling behaviour.
[0.4.0] - 2026-06-26¶
Changed¶
- Your own tweak settings are now tracked explicitly, not guessed. Until now the manager told a value you set yourself apart from one a collection seeded by comparing it to the collection's value — so a value you deliberately chose that happened to equal the collection's was mistaken for the collection's, shown as such in
tweak list, and discarded on acollection update. The manager now records which tweaks you set yourself (everytweak setmarks it), so the origin is exact: such a value stays your override and is carried forward across a collection update even when it matches the curator's value. Profiles created before this are migrated once on first read (the old value-comparison heuristic seeds the markers), then tracked explicitly from then on. Internal only — the profile gains an optionaluserTweaksmarker list; the profile format stays0.1(purely additive, nothing external consumes it yet). - Format-version files now read across compatible versions instead of hard-failing (patcher). Every distribution file carries a
MAJOR.MINORformat version (patchFormatVersion,collectionFormatVersion,collectionLockVersion,indexFormatVersion,catalogFormatVersion). Until now anything other than the exact version this build knew was rejected outright — including a purely additive bump — with a cryptic schema failure and no guidance. The tools now apply a tiered reader: a file at the same major and a newer minor still reads (any newer optional fields are ignored) and notesformatMinorAheadrecommending you update the tool; a newer or retired major — a breaking shape this build genuinely can't read — is refused with an actionableformatMajorUnsupported/formatMajorRetiredmessage naming where to get a newer release; a value that isn'tMAJOR.MINORreportsformatVersionMalformed. So a mod or collection authored against a slightly newer toolchain opens instead of bouncing, while a genuinely incompatible file tells you exactly what to do. Applies topagonia-patcher schema-validate, lockfile resolution, and anywhere the manager loads these files. The JSON Schemas underschemas/mod-patches/widen accordingly (same-major minors are valid); the gate runs before strict schema validation so a newer minor isn't rejected for a field the older schema didn't know. - Tools auto-migrate an older format minor on write (patcher). Complementing the read side above, the writers now stamp the current format version every time they write a managed file, and
pagonia-patcher index buildupgrades anindex.yamlauthored against an older same-major minor up to the current minor in place (formatMigratedInPlace), preserving all surrounding formatting. So a purely additive format bump rises the next time a tool touches the file — authors never hand-migrate it.index build --checkreports a pending migration as info without failing (an older minor is still valid); newer minors and majors are never silently rewritten. - The manager now applies the same format-version rule when it reads catalogs and repo indexes. Previously the manager deserialized a
catalog.yaml/ repoindex.yamlwithout checking itscatalogFormatVersion/indexFormatVersionat all. Now it runs the shared policy on every read — browse,catalog show, and install from agh:repo — so a catalog or index authored against a newer same-major minor reads with theformatMinorAheadnote, while a newer/retired major or a malformed version is refused (formatMajorUnsupported) before its repos enter your browse list or an install resolves against a structure it can't trust. Cached catalogs are gated identically to freshly-fetched ones. The manager and the patcher now share one format-version vocabulary end to end.
Added¶
pagonia-paker loca info <loca>— decode a mod's compiled localization blob (paker). Editor mods ship their UI strings as a compiledlocalization/loca_<lang>.bin(e.g.loca_en_us.bin), a format that was previously undocumented and unreadable by our tools.loca infoprints the strings it carries, in order, and--jsonwrites aLocaInfoReport. The byte layout — a bare sequence of .NET 7-bit-length-prefixed UTF-8 strings, no header/version/key table, read until end-of-stream — was reverse-engineered from two test paks produced by the 1.4.0 Pagonia Editor ("package gdb with dependency" / "package map with dlc1 and gdb") and is now documented in paker CLI → loca info and Mod Distribution → localization/loca_<lang>.bin. Decode is best-effort (no magic number to validate a candidate file); a 0-byte file is a valid empty blob.- The Pattern B scaffold now emits a
Localizationpointer for mods that ship translations (patcher). When a mod's overlay folder contains alocalization/folder (e.g. a compiledloca_<lang>.binadded viaentries.add), the generatedfiles.jsonnow carries aLocalizationkey pointing at that folder alongside the existingGameDatabasekey — matching how the shipped paks and EE's editor mods wire localization in. A mod with only localization and no*.gd.xmlgets afiles.jsonwith just theLocalizationkey (and no.gd.bin); an asset-only overlay with neither still skipsfiles.jsonentirely. Previously the scaffold only ever wrote theGameDatabasekey, so a translation a mod shipped was invisible to the engine. pagonia-paker gdbin infonow reads editor-emitted.gd.binindexes (paker). The 1.4.0 Pagonia Editor closes every.gd.binit writes with a zero-length terminator record (00 00 00 00) — after the last entry, or alone after the header for a map-only mod's empty module index — which the shipped paks (core/dlc1/…) don't have.gdbin infopreviously errored (gdbinEntryTruncated) on every such index, i.e. on every real editor mod. It now tolerates the terminator, reports it asEditorTerminator: yes/HasTrailingTerminatorin the JSON report, andGdBinWriterre-emits it so an editor index round-trips byte-identically. The reverse-engineered terminator + the unifiedbyte[3] = record-count − 1rule (the terminator counts as a record) are documented in paker CLI → .gd.bin Index Format.- The manager now auto-orders mods by their declared
loadAfter/loadBefore. Atplan/deploythe enabled set is topologically ordered to honour each mod'sloadAfter/loadBefore, with your manual profile order as the stable tiebreaker — a mod that must load after another lands in the right place without you hand-sorting. It never silently overrides your order: when a constraint reorders it, that's reported (manager.loadOrderAdjusted), and a constraint cycle is flagged (manager.loadOrderCycle) with those mods left in your manual order. The interactive Reorder load order screen now marks which positions are dependency-pinned and shows the effective deploy-time order. - The manager now acts on declared mod dependencies and incompatibilities. A mod's manifest can list
dependenciesandincompatibleWith, but until now nothing read them. The manager now evaluates them across your enabled set — when youenablea mod, inplan/deploy, and indoctor— and warns when a required mod isn't enabled (manager.modDependencyMissing, saying whether it's installed-but-disabled or not installed at all) or when two enabled mods declare each other incompatible (manager.modIncompatibleEnabled, naming both). Advisory only — it never blocks; it just stops the clash being silent. It also warns before you disable or uninstall a mod that other enabled mods still depend on (manager.modDependedUponByOthers), so a dependency isn't broken silently. install --with-depspulls a mod's missing dependencies for you. Installing a mod with--with-deps(or saying yes to the interactive Install a mod / Browse catalogs prompt) resolves its declareddependencies— and theirs, transitively — and installs them, looking in the same repo the mod came from first, then your subscribed catalogs. Each pulled dependency is reported (manager.modDependencyInstalled); one that can't be found anywhere is a warning (manager.modDependencyUnresolved) and the rest still install. A dependency cycle is handled (each mod is pulled once).contentHashper mod in the repo index — integrity + same-version drift detection (patcher). A mod's index entry can now carry acontentHash: a SHA-256 over the mod's logical payload (mod.yamlplus the patch files it references — the exact set fetched, so extra repo files don't affect it).pagonia-patcher index buildcomputes and inserts it (and refreshes a stale one), andindex-checkrecomputes and flags a mismatch — which catches the footgun a version string can't: a mod's content changed but itsversiondidn't. The shipped official index now carries hashes for its mods. The optional field is additive to the existing0.1index format (no version bump while the format is still in-development). Defined once in a sharedContentHashhelper so author and consumer agree byte-for-byte. On the consumer side, installing a mod from agh:repo whose index advertises acontentHashre-computes it over the downloaded payload and warns (manager.modContentHashMismatch) on a mismatch — download-integrity + tamper/drift detection — while still installing the authoritativemod.yaml(a mismatch usually just means the author forgot to re-runindex build).- Interactive "Update mods + collections" — review and apply updates from the menu. A new entry under Mods runs the read-only update check across your
gh:-sourced mods and collections, lists what's behind, and for whatever you pick shows the delta (from→to, gameDatabaseVersion, and whether your tweak overrides carry forward or get reseeded) before a confirm — then applies the transparent, reversible update. For a collection where you've personally changed tweak settings, it lists those and lets you keep them all, take the collection's new values, or decide per changed setting before applying. Nothing is touched until you confirm; a "Re-check now" entry rescans, and Esc finishes. This is the opt-in front door over the scriptableupdate/collection updateverbs. - Status dashboard shows an "Updates" line. Once you've run the update check this session, the Status dashboard surfaces "N update(s) available" (mods + collections) so you see it without reaching for a verb. The dashboard itself stays instant and offline — it reads the count cached from the Update screen rather than hitting the network on every open — and points you at the Update entry when no check has run yet.
pagonia-manager doctor --check-updates— fold update detection into the health roll-up.doctoris offline by default; pass--check-updatesto add an "Updates available" check that reports how many mods/collections are behind. A source it can't reach degrades to a per-item warning (or the whole check to Skipped), never an error, so it stays CI-safe.pagonia-manager collection update <collection-id>— move a whole collection to its newer version. The collection counterpart ofupdate <mod-id>: it re-checks the collection's source repo, and if a newer version is published, re-fetches it and reinstalls over the existing profile, picking up the curator's new mod set. The previous collection version stays on disk as a rollback anchor, and each referenced mod version coexists. Only a collection installed from agh:repo can be updated (that's the one with a recorded source); a local-file install, an already-current collection, or an uninstalled id all change nothing and say so. Your own tweak settings are carried forward by default (a "merge"): a value you personally changed survives the update, while a tweak you'd left at the curator's value follows the collection's new default — the same non-destructive spirit as the per-modupdate. Pass--reseed-tweaksto instead discard your overrides and take the curator's values wholesale. (In the interactive Update mods + collections screen you're asked per changed setting; see below.)pagonia-manager update <mod-id>— move a mod to its newer version, transparently and reversibly. The apply step thatoutdatedonly reports: it installs the newer version from the same source, re-points your active profile's pin to it, and carries your per-mod tweak overrides forward across the bump (a renamed tweak is migrated forward, so no value is lost). Crucially it keeps the old version on disk — the new one installs alongside it — so an update is a one-liner to undo (enable <mod-id> --version <old>). Nothing is silent: you name the mod, it tells you from→to, and if the pin is already current (or the mod isn't enabled / has no remote source) it changes nothing and says so. (Also available interactively via Update mods + collections.)pagonia-manager outdated— see which installed mods and collections have a newer version published. A read-only check: for each mod and collection you installed from agh:repo, it re-fetches that repo's catalogindex.yamlat the default branch and compares the advertised version to what you have, printingid: installed → availablefor anything behind — mods and collections listed separately. It changes nothing — it just answers "is anything out of date?" so you can decide. Items installed from a local folder/zip/file have no source to compare and are reported as skipped; a repo that's unreachable or no longer lists an item gives a per-item warning instead of failing the whole check. It also catches a same-version content re-publish — when a mod's source re-published the same version with different content,outdatedrecomputes the installed payload's hash, compares it to the index's advertisedcontentHash, and flags it (manager.modContentDriftAvailable, "re-install to refresh") instead of leaving it silent (the version string alone can't show this). It writes a machine-readable report with--json <out>(theupdatesreport — mods + collections behind, same-version content drifts, and the checked/skipped counts). (The one-step apply lives inupdate/collection updateand the Update mods + collections screen; the Status dashboard +doctor --check-updatessurface the count.)- The manager refuses a store or profile written by a newer version of itself.
state.yaml(storeVersion) and profiles (profileVersion) are internal files only ever read and written by the same install. If you run an older manager against a store a newer one wrote, reading it and writing it back would silently drop the fields the newer manager added. The manager now detects that on read and stops with a clearmanager.storeSchemaVersionUnsupported/manager.profileVersionUnsupportederror telling you to upgrade, instead of quietly corrupting the store. An absent or older same-version file reads normally — this only triggers on a genuinely newer one. (Forward groundwork: it does nothing today, where everything is at0.1; it's the safety net that has to already be in the binary before any future store/profile format bump.)
Fixed¶
classifyno longer reports a falseglobalscope for editor map paks (paker). A map authored by the 1.4.0 Pagonia Editor ships an empty module-level.gd.bin(header + the editor's zero-length terminator = 11 bytes). The scope detector decided "contributes GameDatabase content" from any byte past the 7-byte header, so it mistook those 4 terminator bytes for a resource entry and tagged the pakglobalon top of its realmap-scopedscope. It now reads the first record's length and treats a zero (the terminator) — or no record at all — as empty, so a map-only editor pak classifies asmap-scopedonly. Verified against the real EE "package map with dlc1 and gdb" test pak. The synthetic-empty case (a bare 7-byte header) was already correct; this fixes the realistic editor shape.
[0.3.0] - 2026-06-16¶
Added¶
- Example mods are now drift-checked against a real game database (preflight). A new local gate,
scripts/check-examples-against-gdb.ps1, dry-runs (pagonia-patcher plan) every shipped example and official mod against an extractedgame-gdband fails if any patch target no longer resolves — a staleexpectedOldValue/expectedOldXml/ target GUID after a game update. It is the systematic form of the out-of-bandplancheck the schema-validate stages always referred to: schema validation only proves an example is well-formed, never that it still matches the current game data. The game database is resolved from-GameRoot,$env:PAGONIA_GAME_GDB,game-gdb/, or the newestsnapshots/*/game-gdb; with none available it skips itself (exit 0), so CI stays green while local runs gate. Wired intoscripts/preflight.ps1as a final stage. classifynow reports a mod's GameDatabase scope — global vs map-scoped (paker). A newGdbScopessignal tells you, at a glance, whether a downloaded mod changes the GameDatabaseglobally (active in all your games — likecore/dlc1or a globally-active editor mod) or onlymap-scoped(the per-map "hosted game database", active only when playing that map), or both. Detected from whether each gd.bin actually lists any*.gd.xmlresources, so an empty module-level<m>.gd.bin(the editor emits one even for a map-only mod) is correctly not reported as global — a published editor map readsGdbScopes: map-scoped, not a falseglobal. An emptyGdbScopesmeans the pak contributes no GameDatabase content at all. This is the foundation for filtering mods by reach; the filter UI in catalog browse is a follow-on. See paker CLI → classify.index-check/index build— keep a repo'sindex.yamlin sync with its mods (patcher). A distribution repo'sindex.yamlduplicates a curated subset of everymod.yaml(name, version, gameDatabaseVersion, safety flags) so the manager can browse a catalog without fetching each mod — a cache that could silently drift.pagonia-patcher index-check <repo-root>cross-checks the mirrored fields against eachmod.yamland flags drift, orphaned entries (index entry with no mod on disk), missing entries (mod folder absent from the index), and id mismatches;index build <repo-root>re-syncs the drifted values in place (preserving formatting), with--checkas a write-nothing CI gate. The curateddescription/tags/screenshotsfields are intentionally allowed to differ and are never compared. Wired into preflight against the first-partyofficial-mods/tree. See patcher CLI → index-check and Mod Distribution → the index mirror contract.- Esc at the main menu quits with a one-key confirm. Pressing Esc on the main menu now offers a quick exit — a small "Quit Pagonia Land Manager?" prompt where Enter quits and Esc backs out to the menu. A friendlier way to close the app from a fresh menu than reaching for Ctrl+C (which still works). Esc inside a submenu continues to mean "Back", not quit.
- Catalog browse now shows mod safety, and install warns on stale catalog metadata.
catalog showrenders a Safety column (needs-new-game / safe-to-remove / multiplayer / campaign) from each index entry'ssafetyFlags, so you can weigh a mod before installing without fetching it — the consumer-side payoff for the index duplicating that data. And when installing from a repo with anindex.yaml, the manager cross-checks what the catalog advertised (version / gameDatabaseVersion / safety) against themod.yamlit actually downloads, emitting amanager.repoIndexMetadataMismatchwarning on any disagreement (non-fatal — the authoritativemod.yamlstill installs; the warning flags that the browse list may have misled you). The consumer-side complement to the author-sideindex-check. See Mod Catalogs → How It Looks From The User Side.
Changed¶
- Yes/no prompts now confirm on a single keypress. Every interactive
[y/n]question (enable a mod, switch profile, activate a collection, roll back, overwrite drifted files, …) now submits the moment you press y or n — no trailing Enter needed. A bare Enter still accepts the highlighted default, so the destructive prompts that default to no are unchanged: rolling back or force-overwriting still takes a deliberate y. Routed through one shared confirm helper so the keystroke behaviour is uniform across the shell. - Interactive Plan + Deploy no longer dead-ends on a warning. When a plan carries a blocking warning — most often a mod whose
gameDatabaseVersiondoesn't match the install you pointed at — the wizard now offers an inline "Deploy anyway (accept the warnings)" choice, the same one-key opt-in the conflict and live-drift paths already had. Previously only patcher conflicts got that prompt; a manager-level warning fell through to a hardDeploy aborted: pass --accept-warningsand forced you to quit and re-run on the scripted CLI. The bypass stays a per-deploy, in-context choice (not a persistent "always ignore" setting) so a genuinely incompatible mod can't slip in silently on a later deploy.
Fixed¶
- Example mods/docs realigned with the current game database. The Beta Update renamed the icon assets from
.pngto.imageand added aPileLocatorto building cost entries; the shipped examples still referenced the old data and now failed to deploy. Updated thewine-icon-testexample mod, thesanctuary-add-custom-abilityoverlay, and the resource-icon / optional-DLC / change-display docs to the.imageasset paths, and theremove-stone-costexample'sexpectedOldXmlto match the Sawmill's current Stone Block cost item. Caught by the new game-gdb drift check above. profile exportcanonicalises renamed tweak ids. When a profile stored a tweak override under a tweak's old id (the author later renamed it and listed the old id underaliases:), exporting that profile to a collection now folds the value intomods[].tweaksunder the current id instead of carrying the stale alias forward — the same alias-forward migration the manager already applies when reading tweaks. The export is read-only on the profile (it doesn't rewrite the stored ids) and surfaces a one-line note when it migrates, conflicts, or finds an orphaned override.- Interactive selection prompts are now cancellable (Esc). Once you'd picked an action from a menu, the follow-up list picker — which mod to enable/disable, which profile to switch/copy/export/delete, which subscription to remove, which version to uninstall, which tweak to set/reset, which value for an enum tweak, and every step of Reorder load order / Active-Profile move — forced you to choose with no way back; only Ctrl+C escaped. All of these now accept Esc to cancel and return to the previous menu, matching the empty-line back-out the free-text prompts already offer. The reorder/move flows are cancellable at each of their three steps.
[0.2.0] - 2026-06-09¶
Added¶
- Op-aware tweak hints in the interactive configure-mod wizard. When a tweak feeds an arithmetic op, the wizard now explains what the value does instead of showing a bare number: the tweak table has an Effect column (e.g.
x 4 -> 10), the edit screen shows a one-line hint with the op's reason, and setting a value echoes the resultingvanilla -> newpreview. The preview is computed the same way a deploy writes it (rounding + clamping included). - Arithmetic patch operations (
multiplyValue/addValue). Patches can now scale a value relative to its vanilla amount instead of only replacing it with a literal:multiplyValuewritesexpectedOldValue × factor,addValuewritesexpectedOldValue + delta(negative subtracts). The factor/delta can be a literal or a{{ tweaks.<id> }}placeholder, so one shared multiplier tweak scales many targets — the "Hardcore = ×1.5 costs" knob a literal tweak couldn't express. Results round (round/floor/ceil, defaultround) and optionally clamp (clampMin/clampMax); a clamp that fires is reported in the plan. See Patch Format → Arithmetic operations. - Conflict-minimising authoring advisor. Installing a mod that ships its own GameDatabase overlay (
*.gd.xml) now surfaces conflict-risk findings — prefer additiveIncremental/Templateover destructiveReplace/Unload, with a warning when anUnloadwould dangle a still-referenced entity. Advisory only (never blocks install). Advanced → Mods → advise re-runs it on any installed mod, optionally base-aware against a game root (cross-database unload check + a "this Replace could be Incremental" hint). - Cross-mod overlay conflict detection.
plan/deploynow warn (manager.crossModOverlayConflict) when two enabled mods destructively (Replace/Unload) target the same inherited entity — naming the load-order winner and the silently-overridden mods, so you can reorder, disable one, or ask for additive modes. Surfaces in the CLI and the interactive plan/deploy flow. doctorhealth roll-up. Newpagonia-manager doctor [--game <path>]verb: one read-only first-stop check covering store init, active profile, enabled-mods-installed, cross-mod overlay conflicts, orphaned deploys, deploy-backup storage, and (with a game root) expansion ownership. Prints[OK]/[WARN]/[FAIL]/[SKIP]+ a summary; exits non-zero only on an error (CI-friendly). The scriptable form of the interactive Status dashboard.- Interactive mode: every free-text prompt (mod source, game-install path, profile / collection names, catalog sources, tweak values, …) now accepts an empty line to cancel and return to the previous menu, instead of forcing you to type a value or hit Ctrl+C. This mirrors the Back entry the selection menus already offer; each prompt shows an
(empty to cancel)hint. - Interactive mode: long selection lists (installed mods, profiles, catalog subscriptions, collections, tweaks, load order) now support type-to-filter search — start typing to narrow the list instead of scrolling. Short fixed menus are unaffected.
- Status dashboard: when the deploy-backups storage warning fires, it now shows a per-install breakdown chart (GB + share by game-install fingerprint) so it's obvious which install's backups dominate the total. Shown only when more than one install has backups.
Changed¶
- Interactive menus now remember your last selection: stepping into an entry and back lands the cursor on that same entry instead of resetting to the top (main menu and every Advanced submenu).
- Interactive menus now wrap around: pressing up on the first entry jumps to the last, and down on the last jumps to the first.
- Interactive menus accept ESC to back out (same as choosing the menu's Back entry).
- Interactive progress is now uniformly the plain-ASCII dot ticker (
-> label ...) across every operation — install, catalog / collection fetches, advanced commands — matching deploy / rollback. It replaces Spectre's animated spinner, which could render as a frozen glyph (looking like a hung program) on terminals that don't support its cursor-control escapes. - Status dashboard: raised the deploy-backups storage warning threshold from ~5 GB to ~15 GB. A single live deploy already backs up ~5 GB (the game's
core.pakis that large), so the old 5 GB threshold nagged after the very first deploy — when the only backup is the protectedlastDeployand there is nothing to reclaim yet.
Fixed¶
- Rollback no longer leaves a mixed install when a backup is missing or corrupt. Previously, if restoring a rebuilt pak failed mid-way (missing/tampered backup), rollback still went on to delete the Pattern B overlay paks before aborting — leaving the game half-reverted with no clean recovery. It now aborts before removing any overlay, so a failed rollback leaves the install in its pre-rollback state.
- Rollback preserves an overlay pak you replaced by hand. If a
mods/*.pakoverlay was swapped for different content after deploy, rollback would delete it unconditionally under--force. It now re-checks the file's hash and, on a mismatch, leaves it in place with a warning instead of discarding it. - Pak reader hardened against malformed input. Extracting a compressed pak entry now bounds the output to the index-declared uncompressed size and rejects an entry that inflates beyond it (decompression-bomb guard); the reader also refuses a structurally corrupt index up front — an index region larger than the reader supports, or an entry count too large to fit the index data — instead of wrapping a length to a negative value or spinning a huge parse loop.
- Installing from
modio:rejects a non-HTTPS download URL. The mod.io download link is now scheme-checked and refused if it isn'thttps, instead of being fetched over an unencrypted/unknown transport. - Plan / apply JSON reports validate for arithmetic mods. The report schemas were missing
multiplyValue/addValuein their operation-type list, so--jsonreports for a mod using the new arithmetic ops failed their own schema. Both ops are now accepted. deploys clean --keep 0always keeps each install's newest deploy. It could previously remove the newest deploy of a non-active install, leaving that install with no rollback path. The newest deploy per game install is now retained as the rollback anchor (thelastDeployguard still applies on top).doctorflags an unreadable enabled mod instead of reporting "all present". An enabled mod that is installed but whose manifest can't be read now grades the enabled-mods check as an error rather than being silently dropped from the count.- Interactive menus no longer crash on profile / subscription names containing
[or]. Selection lists and the Status dashboard now escape choice text, so a name with markup metacharacters renders literally instead of throwing. - Direct
pagonia-patcher --tweakoverrides are now type-checked. An out-of-setenumvalue or a non-boolean value now warns at plan time (previously only the manager validated overrides; the patcher substituted them unchecked). A{{ tweaks.* }}placeholder inclampMin/clampMaxnow resolves too. validate-mod --game-rootwarns when the path holds no game data. A wrong or mistyped game root no longer silently skips the base-aware advisor checks while still exiting clean.validate-mod/plancatch more authoring mistakes. A fractional default on anintegertweak is now rejected, and a malformed target path (an empty segment from a leading/trailing/doubled/, or a predicate with no element name before[) is reported with a specific reason instead of the generic "did not resolve".- Hardened arithmetic ops + pak decompression against malformed input.
multiplyValue/addValuenow rejectNaN/Infinityoperands and guard the integer-format step against overflow on very large results; the pak reader and the standalonedecompresscommand bound decompressed output to guard against decompression bombs. - Boolean tweak overrides with stray whitespace now apply correctly.
tweak setnormalises a stored value (canonicaltrue/false, all values trimmed), so a value like" true "no longer silently resolves to the false branch of a tweak ternary. pagonia-patcher applyrefuses an output directory that overlaps the source. Applying with the output set to — or nested inside — the source game root is now rejected up front instead of wiping (and destroying) the source.- A deploy that fails mid-write now restores the install to its pre-deploy state. If writing the patched files (or overlay paks) into the game throws partway through, the deploy rolls itself back from the just-made backups and removes any overlay paks already written, instead of leaving the install half-modified with nothing to roll back.
- Remote-install hardening. Downloaded archives are now refused if they declare an implausible entry count or uncompressed size (zip-bomb guard); the per-download size cap (default 8 GiB) is overridable via
PAGONIA_MAX_DOWNLOAD_BYTES; GitHub raw paths from a remote index are URL-escaped; and a catalog URL on a loopback or link-local host (e.g. the cloud-metadata endpoint) is rejected (SSRF guard). --versionno longer prints a duplicated commit hash. Release builds showed<version>+<sha>.<sha>because the SDK auto-appended the git commit on top of the hash the release workflow already stamped. The auto-append is now disabled, so release builds show<version>+<sha>and local dev builds show<version>-devcleanly.
[0.1.0] - 2026-06-05¶
Initial release of the Pagonia Land toolchain — declarative XML mod patching, pak (un)packing, and mod install / profile / deploy management. See the README for the feature overview.