Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 112 additions & 148 deletions CLAUDE.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

This is a public repository, and contributions — human or AI-agent-assisted — are welcome. See `CLAUDE.md` for build commands, architecture, and compatibility constraints; this file covers style and process. For the project's own fork lineage (this repo vs. the upstream `AnotherSymbiote/WitcherScriptMerger` project), see `CLAUDE.md`'s Project overview.
This is a public repository, and contributions — human or AI-agent-assisted — are welcome. See the root `CLAUDE.md` for build commands and architecture, and each project's own `CLAUDE.md` (`WitcherScriptMerger.Core/CLAUDE.md`, `WitcherScriptMerger/CLAUDE.md`, `WitcherScriptMerger.Headless/CLAUDE.md`, `WitcherScriptMerger.Tests/CLAUDE.md`) for that project's compatibility constraints; this file covers style and process. For the project's own fork lineage (this repo vs. the upstream `AnotherSymbiote/WitcherScriptMerger` project), see the root `CLAUDE.md`'s "Fork history" section.

## Code style

Expand All @@ -19,22 +19,22 @@ Match the existing source (e.g. `Inventory/FileMerger.cs`, `Controls/SMTree.cs`)
- **`main` is protected.** No direct commits or pushes — all changes land via pull request. Force-pushes and branch deletion are disabled on `main` at the GitHub level.
- **Branch per feature/fix**, off `main`: `feature/<short-description>` for new functionality, `fix/<short-description>` for bug fixes, `chore/<short-description>` for tooling/process/docs changes not tied to a feature or bug. Keep the description short and kebab-case (e.g. `fix/kdiff3-encoding-mismatch`).
- **Pull requests require 2 approving reviews** before merge (GitHub branch protection on `main`). This applies to everyone, including repository admins in normal circumstances — admin bypass exists at the platform level for genuine emergencies, not as a routine shortcut.
- **PR description should cover**: what changed and why, and — given there's no test suite (see Testing below) — specifically *how you verified it*. "Builds successfully" is necessary but not sufficient for anything touching hash output, `MergeInventory.xml` schema, QuickBMS/wcc_lite invocation, the DiffPlex-based merge engine, or encoding handling; see `CLAUDE.md`'s Compatibility constraints for why those are load-bearing, and its Tests section for the verification pattern this codebase uses in place of a test suite.
- **PR description should cover**: what changed and why, and specifically *how you verified it* (see Testing below). "Builds successfully" is necessary but not sufficient for anything touching hash output, `MergeInventory.xml` schema, QuickBMS/wcc_lite invocation, the DiffPlex-based merge engine, or encoding handling; see `WitcherScriptMerger.Core/CLAUDE.md`'s "Hash format", "DiffPlexMergeEngine", and "Text-merge input encoding" sections for why those are load-bearing, and `WitcherScriptMerger.Tests/CLAUDE.md` for the verification pattern this codebase uses to cover them.
- Commit messages are short, descriptive sentences (e.g. `Fixed crash after canceling file-open.`, `Replace hand-ported xxHash32 with System.IO.Hashing`). A `Category:` prefix (`Fixed:`, etc.) shows up occasionally but isn't enforced. No Conventional Commits format required.
- GitHub Actions CI (`.github/workflows/build.yml`) runs `dotnet build --configuration Release` and `dotnet format whitespace --verify-no-changes` on every PR targeting `main`, but don't rely on it to catch problems for you — run both locally first: `dotnet build WitcherScriptMerger.sln --configuration Release` and `dotnet format whitespace WitcherScriptMerger.sln --verify-no-changes` before opening a PR. Catching failures before CI does saves a round trip.
- External binary dependencies (QuickBMS, wcc_lite — see `CLAUDE.md`'s External tool dependencies) aren't in source control, so a fresh clone needs them sourced separately before the app runs end-to-end. PRs that only touch code not exercising those tools don't need them to build and review. (KDiff3 used to be a third such dependency; it was retired — see `docs/decisions/kdiff3-retirement.md`.)
- External binary dependencies (QuickBMS, wcc_lite — see the root `CLAUDE.md`'s "External tool dependencies & licensing" section) aren't in source control, so a fresh clone needs them sourced separately before the app runs end-to-end. PRs that only touch code not exercising those tools don't need them to build and review. (KDiff3 used to be a third such dependency; it was retired — see `docs/decisions/kdiff3-retirement.md`.)

## Testing

`WitcherScriptMerger.Tests` (xunit) covers `WitcherScriptMerger.Core` — see `CLAUDE.md`'s Tests section for what it covers and its constraints. For anything not covered there — especially further hash output or `MergeInventory.xml` schema changes — use a disposable, non-committed scratch console app: exercise synthetic edge cases plus a cross-check against a real value already recorded in a live `MergeInventory.xml`. Describe what you actually ran in your PR description — see Repository SOP above.
`WitcherScriptMerger.Tests` (xunit) covers `WitcherScriptMerger.Core` — see `WitcherScriptMerger.Tests/CLAUDE.md` for what it covers and its constraints. For anything not covered there — especially further hash output or `MergeInventory.xml` schema changes — use a disposable, non-committed scratch console app: exercise synthetic edge cases plus a cross-check against a real value already recorded in a live `MergeInventory.xml`. Describe what you actually ran in your PR description — see Repository SOP above.

## AI-assisted development

This repository is developed with AI coding agents (Claude Code, and expect others), openly — that's not hidden, and it's not discouraged. `CLAUDE.md` carries the operational guidance these tools use when working in this repo, kept up to date as the codebase changes; read it before pointing an agent at this repo. If these guidelines are silent on something and you're using an agent, defer to the explicit rules below over whatever the agent proposes on its own.
This repository is developed with AI coding agents (Claude Code, and expect others), openly — that's not hidden, and it's not discouraged. The federated `CLAUDE.md` files (a short root one, plus one per project) carry the operational guidance these tools use when working in this repo, kept up to date as the codebase changes; read the root one, plus whichever project's you're touching, before pointing an agent at this repo. If these guidelines are silent on something and you're using an agent, defer to the explicit rules below over whatever the agent proposes on its own.

- **Disclose it.** If a PR was substantially produced or assisted by an AI coding agent, say so in the PR description. Commits already carry a `Co-Authored-By` trailer when an agent is involved (Claude Code does this automatically) — that's necessary but not sufficient; the PR description is where a reviewer looks first.
- **You own what you submit, regardless of how it was produced.** Be able to explain any part of your own PR if a reviewer asks — "the agent wrote it that way" isn't an answer to "why does this work." If you can't explain a change, that's a signal to understand it better before submitting, not to submit it anyway.
- **The verification bar doesn't move for AI-assisted changes — if anything, hold it higher.** This codebase has a thin, Core-only test suite and several genuinely load-bearing, non-obvious compatibility constraints (hash format, text-merge input encoding normalization, the DiffPlex upstream bug `DiffPlexMergeEngine` has to defend against on every merge — all documented in `CLAUDE.md`). Agents are good at producing code that looks plausible and compiles; they have no way to know these constraints exist unless `CLAUDE.md` tells them, and no way to know their fix actually works unless it's actually run against real data. "Should work" is not verification — see Testing above.
- **The verification bar doesn't move for AI-assisted changes — if anything, hold it higher.** This codebase has a thin, Core-only test suite and several genuinely load-bearing, non-obvious compatibility constraints (hash format, text-merge input encoding normalization, the DiffPlex upstream bug `DiffPlexMergeEngine` has to defend against on every merge — all documented in `WitcherScriptMerger.Core/CLAUDE.md`). Agents are good at producing code that looks plausible and compiles; they have no way to know these constraints exist unless `CLAUDE.md` tells them, and no way to know their fix actually works unless it's actually run against real data. "Should work" is not verification — see Testing above.
- **Scrub machine-specific state before submitting.** Agent-assisted sessions tend to accumulate absolute local paths, scratch config pointing at a personal install, or test artifacts from the working process — check your diff for anything like a `G:\SteamLibrary\...`-style path or a personal game install location before opening a PR. `.gitignore` excludes common agent runtime-state directories (`.claude/`, `.cursor/`, etc.) and session handoff notes (`HANDOFF*.md`) for the same reason — extend it rather than working around it if your tool of choice uses a different local-state convention.
- **You're responsible for license compatibility of anything an agent produces**, same as for hand-written code — this project cares about this already (see `CLAUDE.md`'s External tool dependencies section on why QuickBMS/wcc_lite specifically aren't bundled). Don't accept agent output that reproduces code from a source with an incompatible license.
- **You're responsible for license compatibility of anything an agent produces**, same as for hand-written code — this project cares about this already (see the root `CLAUDE.md`'s "External tool dependencies & licensing" section on why QuickBMS/wcc_lite specifically aren't bundled). Don't accept agent output that reproduces code from a source with an incompatible license.
- **Bulk or automated PRs still go through the same process.** A large refactor being agent-generated isn't a reason to skip branch-per-change, PR review, or the two-approval requirement — if anything, larger diffs benefit more from review, not less.
83 changes: 77 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,81 @@
# Script Merger for The Witcher 3

I threw together this tool because I got tired of manually merging script files.
A tool for detecting and merging conflicting Witcher 3 mod script files. It scans your
Mods folder, finds `.ws`/`.xml` files (including inside `.bundle` packages) that more
than one mod modifies, and drives a 3-way merge (vanilla + mod1 + mod2) to combine them.

- Checks your Mods folder for mod conflicts. Uses [QuickBMS](http://aluigi.altervista.org/quickbms.htm) to scan .bundle packages.
- Merges .ws scripts or .xml files inside bundle packages using an in-process 3-way merge engine built on [DiffPlex](https://github.com/mmanela/diffplex) — no external merge tool required. A conflict that can't be auto-solved is written to a conflict-marker file and opened for manual review instead. (This fork previously used the external tool KDiff3 for this; see `docs/decisions/kdiff3-retirement.md` for why it was retired.)
- Packages new .bundle packages using the official mod tool [wcc_lite](http://www.nexusmods.com/witcher3/news/12625/?).
- Detects updated merge source files using the [xxHash](https://github.com/Cyan4973/xxHash) algorithm by Yann Collet, [implemented in .NET](https://github.com/wilhelmliao/xxHash.NET) by Wilhelm Liao.
This is [`TheValiantOne/WitcherScriptMerger`](https://github.com/TheValiantOne/WitcherScriptMerger),
a fork of the original [`AnotherSymbiote/WitcherScriptMerger`](https://github.com/AnotherSymbiote/WitcherScriptMerger),
mid-modernization: a .NET modernization pass, an in-process merge engine replacing the
external KDiff3 tool, a headless CLI mode, an MCP server mode, and a Linux-capable host
have all landed since the fork. See `CLAUDE.md` at the repo root (and each project's own
`CLAUDE.md`) for full architecture detail if you're contributing.

**QuickBMS & wcc_lite aren't included in this source code.**
## What it does

- Checks your Mods folder for mod conflicts. Uses [QuickBMS](http://aluigi.altervista.org/quickbms.htm)
to scan `.bundle` packages for conflicting internal content.
- Merges `.ws` scripts or `.xml` files (including those inside bundle packages) using an
in-process 3-way merge engine built on [DiffPlex](https://github.com/mmanela/diffplex)
— no external merge tool required. A conflict that can't be auto-solved is written to a
conflict-marker file (git/diff3-style markers) and opened for manual review instead.
(This fork previously used the external tool KDiff3 for this; see
[`docs/decisions/kdiff3-retirement.md`](docs/decisions/kdiff3-retirement.md) for why it
was retired.)
- Packages new `.bundle` packages using the official mod tool
[wcc_lite](http://www.nexusmods.com/witcher3/news/12625/?).
- Detects updated merge source files using the [xxHash](https://github.com/Cyan4973/xxHash)
algorithm (xxHash32), via the [`System.IO.Hashing`](https://www.nuget.org/packages/System.IO.Hashing)
NuGet package.

## Ways to run it

There are three entry points in the Windows GUI application, plus a fourth,
Linux-capable host that drops the GUI:

- **GUI** (Windows only) — launch `WitcherScriptMerger.exe` with no arguments, or
`dotnet run --project WitcherScriptMerger/WitcherScriptMerger.csproj`. The familiar
point-and-click conflict tree and merge workflow.
- **Headless CLI** (Windows only, same executable) —
`WitcherScriptMerger.exe merge [--order-file <path.json>]` merges every
auto-solvable conflict with no window at all, then exits.
- **MCP server** (Windows only, same executable) — `WitcherScriptMerger.exe mcp` runs an
MCP (Model Context Protocol) server over stdio, so an MCP client (e.g. a Claude Code
session) can inspect conflicts and drive merges directly.
- **`WitcherScriptMerger.Headless`** (Windows or Linux) — a second, smaller executable
with the same `merge` and `mcp` verbs and no GUI dependency at all, for
CLI/agent-driven workflows on either OS. Supports flat-file (`.ws`/`.xml`) conflicts
only — see "Dependencies" below.

## Building

```
dotnet build WitcherScriptMerger.sln
```

Single solution, four projects: `WitcherScriptMerger.Core` (shared domain logic),
`WitcherScriptMerger` (the WinForms host, all three entry points above),
`WitcherScriptMerger.Headless` (the Linux-capable CLI/MCP-only host), and
`WitcherScriptMerger.Tests`. See the root `CLAUDE.md` for the full breakdown and each
project's own `CLAUDE.md` for that project's build/run/publish details, including
self-contained single-file publish commands for both hosts (`win-x64`, plus `linux-x64`
for the headless host).

## Dependencies

**QuickBMS and wcc_lite aren't included in this source code.** Both are Windows-only
binaries with no license file in their own distribution, so they aren't committed here —
you'll need to source them separately and point `App.config`'s `QuickBmsPath`,
`QuickBmsPluginPath`, and `WccLitePath` settings at them. They're needed **only** for
`.bundle`-content conflicts; plain `.ws`/`.xml` file conflicts merge without them, on
either host.

DiffPlex, the library behind the merge engine, is MIT-licensed and pulled in as an
ordinary NuGet package — no separate download or licensing concern, unlike QuickBMS/
wcc_lite. (KDiff3, an earlier external dependency for merging, has been fully retired —
see [`docs/decisions/kdiff3-retirement.md`](docs/decisions/kdiff3-retirement.md).)

## License

Script Merger for The Witcher 3 is licensed under the **GNU General Public License v2.0**
— see [`LICENSE`](LICENSE).
Loading
Loading