← Files get-fableARCHIVED FILE

hooks/fable_mutation.py

1.7 KB · Oct 3, 2026 · 06:31 UTC

↓ Download file

#!/usr/bin/env python3
"""Advance get-fable mutation generation after write-oriented tool attempts.

Hosts may provide a matcher before invoking this hook, but the hook also checks
known tool names itself so broad host events do not mark read-only or command
activity as workspace mutations. Failed writes are conservative mutations
because a tool can partially change the workspace before reporting failure.
"""
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from _fable_common import (  # noqa: E402
    find_fable_dir,
    read_hook_input,
    record_workspace_mutation,
    start_dir,
)

MUTATING_TOOLS = {
    "edit",
    "write",
    "multiedit",
    "notebookedit",
    "apply_patch",
    "applypatch",
    "write_file",
    "write_to_file",
    "replace",
    "replace_file_content",
    "multi_replace_file_content",
    "create_file",
    "delete_file",
    "move_file",
    "rename_file",
}


def normalized_tool_name(value):
    return str(value).replace("-", "").replace("_", "").lower()


def mutating_tool(data):
    name = data.get("tool_name") or data.get("toolName") or data.get("tool")
    if name is None:
        return True
    normalized = normalized_tool_name(name)
    return normalized in {normalized_tool_name(item) for item in MUTATING_TOOLS}


def main():
    data = read_hook_input()
    if not mutating_tool(data):
        return 0

    fable_dir = find_fable_dir(start_dir(data))
    if not fable_dir:
        return 0

    record_workspace_mutation(fable_dir)
    return 0


if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception as exc:
        sys.stderr.write("[get-fable] mutation hook error (ignored): %r\n" % exc)
        sys.exit(0)

SHA-256: 347556bdce3b339ccc346c777bcb10d4a8ccc07a79f18af1c7eb4f61fec606cf