Text Diff, Patch & Three-Way Merge
difflib generates a unified diff but the standard library cannot apply
one, and there was no three-way merge anywhere — so updating a .received
artifact, replaying a recorded text edit, or merging two edits of a base file
had no headless primitive. This adds the missing pieces. It complements
utils/json_patch (structured JSON); this is line-based text.
Pure standard library (difflib + re); imports no PySide6.
Headless API
from je_auto_control import unified_diff, apply_unified, three_way_merge
diff = unified_diff(original, edited)
restored = apply_unified(original, diff) # == edited
merge = three_way_merge(base, ours, theirs)
if merge.clean:
save(merge.text)
else:
print(merge.conflicts, "conflict(s)") # text has <<<<<<< markers
unified_diff wraps difflib; apply_unified is the missing applier —
it walks each @@ hunk, verifies the context/removed lines match, and raises
PatchApplyError on mismatch. three_way_merge merges line-based:
non-overlapping edits from each side combine cleanly; if both sides edit the
same region (and differ), it emits a conflict block with
<<<<<<< / ======= / >>>>>>> markers and reports clean=False. Trivial
cases (one side unchanged, or identical edits) resolve automatically.
Executor commands
AC_unified_diff ({diff}), AC_apply_unified ({result}) and
AC_three_way_merge ({text, clean, conflicts}). Each is also exposed as
an MCP tool (ac_unified_diff / ac_apply_unified / ac_three_way_merge)
and as a Script Builder command under Data.