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

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

2

3 from __future__ import annotations

4

5 from pathlib import Path

6

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

8 from little_loops.logger import Logger

9

10

11 def 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

37 def 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