Skip to content

Engine

engine

Batch file editing engine.

Implements the validate-then-apply strategy from the axm-edit spec:

  1. Read all affected files once (snapshot)
  2. Validate every operation against the snapshot
  3. Resolve line positions (fuzzy search for old content)
  4. Sort replace edits bottom-to-top to avoid line-shift
  5. Apply all operations atomically (or fail with 0 files touched)

ResolvedEdit dataclass

An edit whose line position has been resolved against the file.

Source code in packages/axm-edit/src/axm_edit/core/engine.py
Python
@dataclass(frozen=True)
class ResolvedEdit:
    """An edit whose line position has been resolved against the file."""

    line: int  # actual 1-indexed start line found
    old: str
    new: str
    indent: str = ""  # indent prefix to apply to new (from dedent match)

batch_apply(root, operations)

Validate and apply a batch of file operations atomically.

Parameters:

Name Type Description Default
root Path

Project root directory (all paths are relative to this).

required
operations Sequence[Operation]

List of replace, create, and delete operations.

required

Returns:

Type Description
BatchResult

BatchResult with success status, checkpoint SHA, and summary.

Source code in packages/axm-edit/src/axm_edit/core/engine.py
Python
def batch_apply(root: Path, operations: Sequence[Operation]) -> BatchResult:
    """Validate and apply a batch of file operations atomically.

    Args:
        root: Project root directory (all paths are relative to this).
        operations: List of replace, create, and delete operations.

    Returns:
        BatchResult with success status, checkpoint SHA, and summary.
    """
    root = root.resolve()
    grouped = _group_operations(operations)
    resolved_by_file, errors = _validate_all(root, grouped)

    if errors:
        return BatchResult(
            success=False,
            error="Validation failed",
            details=errors,
        )

    checkpoint = create_checkpoint(root)

    total_applied = 0
    for file_rel, resolved in resolved_by_file.items():
        total_applied += _apply_replace(root, file_rel, resolved)
    total_applied += _apply_creates_deletes(root, grouped.creates, grouped.deletes)

    return BatchResult(
        success=True,
        checkpoint=checkpoint,
        applied=total_applied,
        summary={
            "modified": len(resolved_by_file),
            "created": len(grouped.creates),
            "deleted": len(grouped.deletes),
        },
    )