task_queue.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env python3
  2. """
  3. Task queue utility functions.
  4. Provides:
  5. list_tasks_by_status - List tasks by status
  6. list_pending_tasks - List tasks with pending status
  7. list_tasks_by_assignee - List tasks by assignee
  8. list_my_tasks - List tasks assigned to current developer
  9. get_task_stats - Get P0/P1/P2/P3 counts
  10. """
  11. from __future__ import annotations
  12. from pathlib import Path
  13. from .paths import (
  14. get_repo_root,
  15. get_developer,
  16. get_tasks_dir,
  17. )
  18. from .tasks import iter_active_tasks
  19. # =============================================================================
  20. # Internal helper
  21. # =============================================================================
  22. def _task_to_dict(t) -> dict:
  23. """Convert TaskInfo to the dict format callers expect."""
  24. return {
  25. "priority": t.priority,
  26. "id": t.raw.get("id", ""),
  27. "title": t.title,
  28. "status": t.status,
  29. "assignee": t.assignee or "-",
  30. "dir": t.dir_name,
  31. "children": list(t.children),
  32. "parent": t.parent,
  33. }
  34. # =============================================================================
  35. # Public Functions
  36. # =============================================================================
  37. def list_tasks_by_status(
  38. filter_status: str | None = None,
  39. repo_root: Path | None = None
  40. ) -> list[dict]:
  41. """List tasks by status.
  42. Args:
  43. filter_status: Optional status filter.
  44. repo_root: Repository root path. Defaults to auto-detected.
  45. Returns:
  46. List of task info dicts with keys: priority, id, title, status, assignee.
  47. """
  48. if repo_root is None:
  49. repo_root = get_repo_root()
  50. tasks_dir = get_tasks_dir(repo_root)
  51. results = []
  52. for t in iter_active_tasks(tasks_dir):
  53. if filter_status and t.status != filter_status:
  54. continue
  55. results.append(_task_to_dict(t))
  56. return results
  57. def list_pending_tasks(repo_root: Path | None = None) -> list[dict]:
  58. """List pending tasks.
  59. Args:
  60. repo_root: Repository root path. Defaults to auto-detected.
  61. Returns:
  62. List of task info dicts.
  63. """
  64. return list_tasks_by_status("planning", repo_root)
  65. def list_tasks_by_assignee(
  66. assignee: str,
  67. filter_status: str | None = None,
  68. repo_root: Path | None = None
  69. ) -> list[dict]:
  70. """List tasks assigned to a specific developer.
  71. Args:
  72. assignee: Developer name.
  73. filter_status: Optional status filter.
  74. repo_root: Repository root path. Defaults to auto-detected.
  75. Returns:
  76. List of task info dicts.
  77. """
  78. if repo_root is None:
  79. repo_root = get_repo_root()
  80. tasks_dir = get_tasks_dir(repo_root)
  81. results = []
  82. for t in iter_active_tasks(tasks_dir):
  83. if (t.assignee or "-") != assignee:
  84. continue
  85. if filter_status and t.status != filter_status:
  86. continue
  87. results.append(_task_to_dict(t))
  88. return results
  89. def list_my_tasks(
  90. filter_status: str | None = None,
  91. repo_root: Path | None = None
  92. ) -> list[dict]:
  93. """List tasks assigned to current developer.
  94. Args:
  95. filter_status: Optional status filter.
  96. repo_root: Repository root path. Defaults to auto-detected.
  97. Returns:
  98. List of task info dicts.
  99. Raises:
  100. ValueError: If developer not set.
  101. """
  102. if repo_root is None:
  103. repo_root = get_repo_root()
  104. developer = get_developer(repo_root)
  105. if not developer:
  106. raise ValueError("Developer not set")
  107. return list_tasks_by_assignee(developer, filter_status, repo_root)
  108. def get_task_stats(repo_root: Path | None = None) -> dict[str, int]:
  109. """Get task statistics.
  110. Args:
  111. repo_root: Repository root path. Defaults to auto-detected.
  112. Returns:
  113. Dict with keys: P0, P1, P2, P3, Total.
  114. """
  115. if repo_root is None:
  116. repo_root = get_repo_root()
  117. tasks_dir = get_tasks_dir(repo_root)
  118. stats = {"P0": 0, "P1": 0, "P2": 0, "P3": 0, "Total": 0}
  119. for t in iter_active_tasks(tasks_dir):
  120. if t.priority in stats:
  121. stats[t.priority] += 1
  122. stats["Total"] += 1
  123. return stats
  124. def format_task_stats(stats: dict[str, int]) -> str:
  125. """Format task stats as string.
  126. Args:
  127. stats: Stats dict from get_task_stats.
  128. Returns:
  129. Formatted string like "P0:0 P1:1 P2:2 P3:0 Total:3".
  130. """
  131. return f"P0:{stats['P0']} P1:{stats['P1']} P2:{stats['P2']} P3:{stats['P3']} Total:{stats['Total']}"
  132. # =============================================================================
  133. # Main Entry (for testing)
  134. # =============================================================================
  135. if __name__ == "__main__":
  136. stats = get_task_stats()
  137. print(format_task_stats(stats))
  138. print()
  139. print("Pending tasks:")
  140. for task in list_pending_tasks():
  141. print(f" {task['priority']}|{task['id']}|{task['title']}|{task['status']}|{task['assignee']}")