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

32 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-06-08 15:34 -0500

1"""ll-issues fingerprint: extract structured fingerprint from an issue file.""" 

2 

3from __future__ import annotations 

4 

5import argparse 

6import json 

7import re 

8import sys 

9from pathlib import Path 

10from typing import TYPE_CHECKING 

11 

12if TYPE_CHECKING: 

13 from little_loops.config import BRConfig 

14 

15 

16def cmd_fingerprint(config: BRConfig, args: argparse.Namespace) -> int: 

17 """Extract structured fingerprint (id, files_to_modify, key_terms) from an issue file. 

18 

19 Reads the issue file and outputs JSON with: 

20 - id: issue ID from frontmatter (falls back to filename parsing) 

21 - files_to_modify: sorted list of file paths from the Integration Map section 

22 - key_terms: sorted list of significant words after stop-word filtering 

23 

24 Args: 

25 config: Project configuration. 

26 args: Parsed arguments with .issue_path. 

27 

28 Returns: 

29 0 on success, 1 on error. 

30 """ 

31 from little_loops.parallel.file_hints import extract_file_hints 

32 from little_loops.text_utils import extract_words 

33 

34 issue_path = Path(args.issue_path) 

35 if not issue_path.is_absolute(): 

36 issue_path = config.project_root / issue_path 

37 

38 if not issue_path.is_file(): 

39 print(f"Error: issue file not found: {issue_path}", file=sys.stderr) 

40 return 1 

41 

42 content = issue_path.read_text() 

43 

44 # Extract issue ID from frontmatter 

45 issue_id = "" 

46 fm_match = re.search(r"^---\n(.*?)^---", content, re.MULTILINE | re.DOTALL) 

47 if fm_match: 

48 id_match = re.search(r"^id:\s*(\S+)", fm_match.group(1), re.MULTILINE) 

49 if id_match: 

50 issue_id = id_match.group(1) 

51 if not issue_id: 

52 # Fallback: parse from filename (P3-ENH-1801-title -> ENH-1801) 

53 stem = issue_path.stem 

54 parts = stem.split("-") 

55 issue_id = "-".join(parts[1:3]) if len(parts) >= 3 else stem 

56 

57 hints = extract_file_hints(content, issue_id=issue_id) 

58 key_terms = extract_words(content) 

59 

60 result = { 

61 "id": issue_id, 

62 "files_to_modify": sorted(hints.files), 

63 "key_terms": sorted(key_terms), 

64 } 

65 

66 print(json.dumps(result, indent=2)) 

67 return 0