Report working-tree status and diff as a pre-hook.
Designed for injection into protocol briefings via
inject_result + inline: true.
params:
path — project root (default ".").
diff_lines — max diff lines (default 200, 0 to disable).
Source code in packages/axm-git/src/axm_git/hooks/preflight.py
| @dataclass
class PreflightHook:
"""Report working-tree status and diff as a pre-hook.
Designed for injection into protocol briefings via
``inject_result`` + ``inline: true``.
*params*:
``path`` — project root (default ``"."``).
``diff_lines`` — max diff lines (default 200, 0 to disable).
"""
def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
"""Execute the hook action.
Args:
context: Session context dictionary.
**params: Optional ``path`` and ``diff_lines``.
Returns:
HookResult with ``files``, ``diff``, ``file_count``, and ``clean``.
"""
if not params.get("enabled", True):
return HookResult.ok(skipped=True, reason="git disabled")
working_dir = _resolve_working_dir(params, context, param_key="path").resolve()
max_diff_lines: int = int(params.get("diff_lines", 200))
git_root = find_git_root(working_dir)
if git_root is None:
return HookResult.ok(skipped=True, reason="not a git repo")
# Scope to package when inside a workspace (git root != working dir)
rel = working_dir.resolve().relative_to(git_root.resolve())
pathspec = ["--", str(rel)] if str(rel) != "." else []
# git status --porcelain [-- rel_path]
status = run_git(["status", "--porcelain", *pathspec], git_root)
if status.returncode != 0:
return HookResult.fail(f"git status failed: {status.stderr}")
files: list[dict[str, str]] = []
for line in status.stdout.splitlines():
if len(line) < _MIN_STATUS_LINE_LEN:
continue
code = line[:2].strip()
filepath = line[3:]
files.append({"path": filepath, "status": code})
# git diff -U2 [-- rel_path]
diff_content = ""
if max_diff_lines > 0:
diff_result = run_git(["diff", "-U2", *pathspec], git_root)
lines = diff_result.stdout.splitlines()
if len(lines) > max_diff_lines:
diff_content = "\n".join(lines[:max_diff_lines])
else:
diff_content = diff_result.stdout.strip()
return HookResult.ok(
files=files,
diff=diff_content,
file_count=len(files),
clean=len(files) == 0,
)
|
execute(context, **params)
Execute the hook action.
Parameters:
| Name |
Type |
Description |
Default |
context
|
dict[str, Any]
|
Session context dictionary.
|
required
|
**params
|
Any
|
Optional path and diff_lines.
|
{}
|
Returns:
| Type |
Description |
HookResult
|
HookResult with files, diff, file_count, and clean.
|
Source code in packages/axm-git/src/axm_git/hooks/preflight.py
| def execute(self, context: dict[str, Any], **params: Any) -> HookResult:
"""Execute the hook action.
Args:
context: Session context dictionary.
**params: Optional ``path`` and ``diff_lines``.
Returns:
HookResult with ``files``, ``diff``, ``file_count``, and ``clean``.
"""
if not params.get("enabled", True):
return HookResult.ok(skipped=True, reason="git disabled")
working_dir = _resolve_working_dir(params, context, param_key="path").resolve()
max_diff_lines: int = int(params.get("diff_lines", 200))
git_root = find_git_root(working_dir)
if git_root is None:
return HookResult.ok(skipped=True, reason="not a git repo")
# Scope to package when inside a workspace (git root != working dir)
rel = working_dir.resolve().relative_to(git_root.resolve())
pathspec = ["--", str(rel)] if str(rel) != "." else []
# git status --porcelain [-- rel_path]
status = run_git(["status", "--porcelain", *pathspec], git_root)
if status.returncode != 0:
return HookResult.fail(f"git status failed: {status.stderr}")
files: list[dict[str, str]] = []
for line in status.stdout.splitlines():
if len(line) < _MIN_STATUS_LINE_LEN:
continue
code = line[:2].strip()
filepath = line[3:]
files.append({"path": filepath, "status": code})
# git diff -U2 [-- rel_path]
diff_content = ""
if max_diff_lines > 0:
diff_result = run_git(["diff", "-U2", *pathspec], git_root)
lines = diff_result.stdout.splitlines()
if len(lines) > max_diff_lines:
diff_content = "\n".join(lines[:max_diff_lines])
else:
diff_content = diff_result.stdout.strip()
return HookResult.ok(
files=files,
diff=diff_content,
file_count=len(files),
clean=len(files) == 0,
)
|