Coverage for little_loops / cli / issues / next_action.py: 100%
30 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-05-22 16:19 -0500
« prev ^ index » next coverage.py v7.12.0, created at 2026-05-22 16:19 -0500
1"""ll-issues next-action: Print the next refinement action needed across all active issues."""
3from __future__ import annotations
5import argparse
6from typing import TYPE_CHECKING
8if TYPE_CHECKING:
9 from little_loops.config import BRConfig
12def cmd_next_action(config: BRConfig, args: argparse.Namespace) -> int:
13 """Print the next refinement action needed across all active issues.
15 Output: NEEDS_FORMAT|NEEDS_VERIFY|NEEDS_SCORE|NEEDS_REFINE <id> (exit 1)
16 ALL_DONE (exit 0)
18 Args:
19 config: Project configuration
20 args: Parsed arguments with optional .refine_cap, .ready_threshold, .outcome_threshold
22 Returns:
23 Exit code (1 = work remains, 0 = all done)
24 """
25 from little_loops.cli_args import parse_issue_ids
26 from little_loops.issue_parser import find_issues, is_formatted
28 skip_ids = parse_issue_ids(getattr(args, "skip", None))
29 issues = find_issues(config, skip_ids=skip_ids or None)
30 issues.sort(key=lambda i: (i.priority_int, -int(i.issue_id.split("-")[1])))
32 refine_cap: int = getattr(args, "refine_cap", 5)
33 ready_threshold: int = getattr(args, "ready_threshold", 85)
34 outcome_threshold: int = getattr(args, "outcome_threshold", 70)
36 for issue in issues:
37 if not is_formatted(issue.path):
38 print(f"NEEDS_FORMAT {issue.issue_id}")
39 return 1
40 if "/ll:verify-issues" not in issue.session_commands:
41 print(f"NEEDS_VERIFY {issue.issue_id}")
42 return 1
43 cs = issue.confidence_score
44 oc = issue.outcome_confidence
45 if cs is None or oc is None:
46 print(f"NEEDS_SCORE {issue.issue_id}")
47 return 1
48 if issue.session_command_counts.get("/ll:refine-issue", 0) < refine_cap:
49 if cs < ready_threshold or oc < outcome_threshold:
50 print(f"NEEDS_REFINE {issue.issue_id}")
51 return 1
53 print("ALL_DONE")
54 return 0