check_task_cycles: fix import path for tasklib

This commit is contained in:
Rai (Michael Pokorny)
2025-06-25 01:05:32 -07:00
parent a4a2680b39
commit 53efec12b1
21 changed files with 102 additions and 8 deletions

View File

@@ -6,7 +6,13 @@ repos:
entry: python3 agentydragon/tools/check_task_frontmatter.py
language: python
additional_dependencies: [PyYAML, toml, pydantic]
files: ^agentydragon/tasks/[0-9]{2}-.*\.md$
files: ^agentydragon/tasks/(?:\.done/)?[0-9]{2}-.*\.md$
- id: check-task-dependency-cycles
name: Check for circular task dependencies
entry: python3 agentydragon/tools/check_task_cycles.py
language: python
additional_dependencies: [toml, pydantic]
files: ^agentydragon/tasks/(?:\.done/)?[0-9]{2}-.*\.md$
- id: cargo-build
name: Check Rust workspace builds
entry: bash -lc 'cd codex-rs && RUSTFLAGS="-D warnings" cargo build --workspace --locked'

View File

@@ -0,0 +1 @@
# Keep this directory in version control

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python3
"""
check_task_cycles.py: Pre-commit hook to detect circular dependencies among non-merged tasks.
"""
import re
import sys
from manager_utils.tasklib import task_dir, load_task
def main():
# Load all tasks and separate merged vs non-merged
merged = set()
deps_map = {}
for md in task_dir().rglob('[0-9][0-9]-*.md'):
if md.name == 'task-template.md' or md.name.endswith('-plan.md'):
continue
meta, _ = load_task(md)
if meta.status == 'Merged':
merged.add(meta.id)
else:
# extract numeric dependencies
deps = [d for d in re.findall(r"\d+", meta.dependencies)]
deps_map[meta.id] = deps
# filter out dependencies on merged tasks
for tid in deps_map:
deps_map[tid] = [d for d in deps_map[tid] if d not in merged]
# detect cycles via DFS
visited = set()
stack = []
def visit(n):
if n in stack:
cycle = stack[stack.index(n):] + [n]
print(f"Circular dependency detected: {' -> '.join(cycle)}")
sys.exit(1)
if n in visited:
return
stack.append(n)
for m in deps_map.get(n, []):
visit(m)
stack.pop()
visited.add(n)
for node in deps_map:
if node not in visited:
visit(node)
if __name__ == '__main__':
main()

View File

@@ -23,12 +23,12 @@ except ImportError:
sys.exit(1)
REQUIRED_KEYS = ["id", "title", "status", "summary", "goal"]
ALLOWED_STATUSES = ["Not started", "Started", "Needs manual review", "Done", "Cancelled"]
ALLOWED_STATUSES = ["Not started", "Started", "Needs manual review", "Done", "Cancelled", "Merged"]
def main():
failures = 0
for md in tasklib.task_dir().glob('[0-9][0-9]-*.md'):
for md in tasklib.task_dir().rglob('[0-9][0-9]-*.md'):
if md.name == 'task-template.md' or md.name.endswith('-plan.md'):
continue
try:

View File

@@ -31,7 +31,7 @@ def status():
# Load all task metadata, reporting load errors with file path
all_meta: dict[str, TaskMeta] = {}
path_map: dict[str, Path] = {}
for md in sorted(task_dir().glob('*.md')):
for md in sorted(task_dir().rglob('[0-9][0-9]-*.md')):
if md.name in ('task-template.md',) or md.name.endswith('-plan.md'):
continue
try:
@@ -133,9 +133,17 @@ def status():
['git', 'rev-list', '--left-right', '--count',
f'{branches[0]}...agentydragon'], cwd=root
).decode().split()
stat = subprocess.check_output(
['git', 'diff', '--shortstat', f'{branches[0]}...agentydragon'], cwd=root
).decode().strip().replace(' file changed', '')
# compact diffstat: e.g. "56 files changed, 1265 insertions(+), 342 deletions(-)" -> "56f,1265i,342d"
raw = subprocess.check_output(
['git', 'diff', '--shortstat', f'{branches[0]}...agentydragon'], cwd=root
).decode().strip()
stat = (
raw.replace(' files changed', 'f')
.replace(' file changed', 'f')
.replace(' insertions(+)', 'i')
.replace(' deletions(-)', 'd')
.replace(', ', ',')
)
base = subprocess.check_output(
['git', 'merge-base', 'agentydragon', branches[0]], cwd=root
).decode().strip()
@@ -175,7 +183,7 @@ def status():
# summary of fully merged tasks (no branch, no worktree)
if merged_tasks:
items = ' '.join(f"{tid} ({title})" for tid, title in merged_tasks)
print(f"\n\033[32mDone & merged:\033[0m {items}")
print(f"\n\033[32mMerged:\033[0m {items}")
# summary of tasks Ready to merge (Done with branch commits)
ready_tasks: list[tuple[str, str]] = []

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""
organize_done_tasks.py: Move merged task files under tasks/.done/ subdirectory.
This script should be run once to migrate all tasks with status "Merged"
to the .done folder.
"""
import subprocess
from pathlib import Path
from tasklib import task_dir, load_task
def main():
root = task_dir()
done_dir = root / '.done'
done_dir.mkdir(exist_ok=True)
for md in sorted(root.glob('[0-9][0-9]-*.md')):
if md.name == 'task-template.md' or md.name.endswith('-plan.md'):
continue
meta, _ = load_task(md)
if meta.status == 'Merged':
target = done_dir / md.name
print(f'Moving {md.name} -> .done/')
subprocess.run(['git', 'mv', str(md), str(target)], check=True)
print('Migration complete.')
if __name__ == '__main__':
main()