Coverage for little_loops/cli/issues/sequence.py: 0%

1"""ll-issues sequence: Suggest dependency-ordered implementation sequence."""

2

3 from __future__ import annotations

4

5 import argparse

6 from typing import TYPE_CHECKING

7

8 from little_loops.cli.output import PRIORITY_COLOR, TYPE_COLOR, colorize, print_json

9

10 if TYPE_CHECKING:

11 from little_loops.config import BRConfig

12

13

14 def cmd_sequence(config: BRConfig, args: argparse.Namespace) -> int:

15 """Output a dependency-ordered list of active issues with rationale.

16

17 Args:

18 config: Project configuration

19 args: Parsed arguments with .limit attribute

20

21 Returns:

22 Exit code (0 = success)

23 """

24 from little_loops.dependency_graph import DependencyGraph

25 from little_loops.issue_parser import find_issues

26

27 issues = find_issues(config)

28

29 if not issues:

30 print("No active issues found.")

31 return 0

32

33 graph = DependencyGraph.from_issues(issues)

34

35 try:

36 ordered = graph.topological_sort()

37 except ValueError as exc:

38 print(f"Warning: dependency cycle detected — {exc}")

39 ordered = issues # fall back to priority order

40

41 limit = args.limit

42 shown = ordered[:limit]

43

44 if getattr(args, "json", False):

45 print_json(

46 [

47 {

48 "id": issue.issue_id,

49 "priority": issue.priority,

50 "title": issue.title,

51 "path": str(issue.path),

52 "blocked_by": sorted(graph.blocked_by.get(issue.issue_id, set())),

53 "blocks": issue.blocks,

54 }

55 for issue in shown

56 ]

57 )

58 return 0

59

60 print(f"Suggested implementation sequence ({len(shown)} of {len(ordered)} issues):\n")

61 for issue in shown:

62 blockers = graph.blocked_by.get(issue.issue_id, set())

63 if blockers:

64 rationale = f"blocked by: {', '.join(sorted(blockers))}"

65 else:

66 rationale = "no blockers"

67 issue_prefix = issue.issue_id.split("-", 1)[0]

68 colored_id = colorize(issue.issue_id, TYPE_COLOR.get(issue_prefix, "0"))

69 colored_pri = colorize(issue.priority, PRIORITY_COLOR.get(issue.priority, "0"))

70 print(f" [{colored_pri}, {rationale}] {colored_id}: {issue.title}")

71

72 if len(ordered) > limit:

73 remaining = len(ordered) - limit

74 print(f"\n … +{remaining} more (use --limit to show more)")

75

76 return 0