Skip to content

File header

file_header

FileHeaderHook — file header extraction for protocol briefings.

Protocol hook that extracts the first ~30 lines of source files referenced by source_body results, providing import blocks, __all__, and TYPE_CHECKING context without requiring a full Read. Registered as ast:file-header via axm.hooks entry point.

FileHeaderHook dataclass

Extract the first ~30 lines of source files.

Reads path from params (or working_dir from context) and files from params. When files is not provided, extracts file paths from source_body in context.

Source code in packages/axm-ast/src/axm_ast/hooks/file_header.py
@dataclass
class FileHeaderHook:
    """Extract the first ~30 lines of source files.

    Reads ``path`` from *params* (or ``working_dir`` from context)
    and ``files`` from *params*.  When *files* is not provided,
    extracts file paths from ``source_body`` in context.
    """

    def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
        """Execute the hook action.

        Args:
            context: Session context dictionary.
            **params: Optional ``files`` (newline-separated paths or list).
                Optional ``path`` (overrides ``working_dir`` from context).

        Returns:
            HookResult with ``headers`` list in metadata on success.
        """
        path = params.get("path") or context.get("working_dir", ".")
        working_dir = Path(path).resolve()
        if not working_dir.is_dir():
            return HookResult.fail(f"working_dir not a directory: {working_dir}")

        files = params.get("files")
        if files is None:
            source_body = context.get("source_body")
            if not source_body:
                return HookResult.ok(headers=[])
            files = _extract_files_from_source_body(source_body)

        if isinstance(files, str):
            files = [f.strip() for f in files.splitlines() if f.strip()]

        # Deduplicate preserving order
        unique_files = list(dict.fromkeys(files))

        headers: list[dict[str, str]] = []
        for file in unique_files:
            file_path = working_dir / file
            try:
                text = file_path.read_text(encoding="utf-8")
            except FileNotFoundError:
                continue
            except UnicodeDecodeError:
                logger.warning("Skipping binary file: %s", file)
                continue

            lines = text.splitlines(keepends=True)
            header = "".join(lines[:_MAX_HEADER_LINES])
            headers.append({"file": file, "header": header})

        return HookResult.ok(headers=headers)
execute(context, **params)

Execute the hook action.

Parameters:

Name Type Description Default
context dict[str, Any]

Session context dictionary.

required
**params Any

Optional files (newline-separated paths or list). Optional path (overrides working_dir from context).

{}

Returns:

Type Description
HookResult

HookResult with headers list in metadata on success.

Source code in packages/axm-ast/src/axm_ast/hooks/file_header.py
def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
    """Execute the hook action.

    Args:
        context: Session context dictionary.
        **params: Optional ``files`` (newline-separated paths or list).
            Optional ``path`` (overrides ``working_dir`` from context).

    Returns:
        HookResult with ``headers`` list in metadata on success.
    """
    path = params.get("path") or context.get("working_dir", ".")
    working_dir = Path(path).resolve()
    if not working_dir.is_dir():
        return HookResult.fail(f"working_dir not a directory: {working_dir}")

    files = params.get("files")
    if files is None:
        source_body = context.get("source_body")
        if not source_body:
            return HookResult.ok(headers=[])
        files = _extract_files_from_source_body(source_body)

    if isinstance(files, str):
        files = [f.strip() for f in files.splitlines() if f.strip()]

    # Deduplicate preserving order
    unique_files = list(dict.fromkeys(files))

    headers: list[dict[str, str]] = []
    for file in unique_files:
        file_path = working_dir / file
        try:
            text = file_path.read_text(encoding="utf-8")
        except FileNotFoundError:
            continue
        except UnicodeDecodeError:
            logger.warning("Skipping binary file: %s", file)
            continue

        lines = text.splitlines(keepends=True)
        header = "".join(lines[:_MAX_HEADER_LINES])
        headers.append({"file": file, "header": header})

    return HookResult.ok(headers=headers)