Coverage for little_loops / cli / loop / config_cmds.py: 0%

42 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-03-18 16:20 -0500

1"""ll-loop config subcommands: validate, install.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6 

7from little_loops.cli.loop._helpers import get_builtin_loops_dir, resolve_loop_path 

8from little_loops.logger import Logger 

9 

10 

11def cmd_validate( 

12 loop_name: str, 

13 loops_dir: Path, 

14 logger: Logger, 

15) -> int: 

16 """Validate a loop definition.""" 

17 from little_loops.fsm.validation import load_and_validate 

18 

19 try: 

20 path = resolve_loop_path(loop_name, loops_dir) 

21 fsm, warnings = load_and_validate(path) 

22 logger.success(f"{loop_name} is valid") 

23 print(f" States: {', '.join(fsm.states.keys())}") 

24 print(f" Initial: {fsm.initial}") 

25 print(f" Max iterations: {fsm.max_iterations}") 

26 for w in warnings: 

27 print(f"{w}") 

28 return 0 

29 except FileNotFoundError as e: 

30 logger.error(str(e)) 

31 return 1 

32 except ValueError as e: 

33 logger.error(f"{loop_name} is invalid: {e}") 

34 return 1 

35 

36 

37def cmd_install( 

38 loop_name: str, 

39 loops_dir: Path, 

40 logger: Logger, 

41) -> int: 

42 """Copy a built-in loop to .loops/ for customization.""" 

43 import shutil 

44 

45 builtin_dir = get_builtin_loops_dir() 

46 source = builtin_dir / f"{loop_name}.yaml" 

47 

48 if not source.exists(): 

49 available = [f.stem for f in builtin_dir.glob("*.yaml")] if builtin_dir.exists() else [] 

50 logger.error(f"No built-in loop named '{loop_name}'") 

51 if available: 

52 print(f"Available built-in loops: {', '.join(sorted(available))}") 

53 return 1 

54 

55 loops_dir.mkdir(exist_ok=True) 

56 dest = loops_dir / f"{loop_name}.yaml" 

57 

58 if dest.exists(): 

59 logger.error(f"Loop already exists: {dest}") 

60 print("Remove it first or edit it directly.") 

61 return 1 

62 

63 shutil.copy2(source, dest) 

64 print(f"Installed {loop_name} to {dest}") 

65 print("You can now customize it by editing the file.") 

66 return 0