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
« prev ^ index » next coverage.py v7.12.0, created at 2026-03-18 16:20 -0500
1"""ll-loop config subcommands: validate, install."""
3from __future__ import annotations
5from pathlib import Path
7from little_loops.cli.loop._helpers import get_builtin_loops_dir, resolve_loop_path
8from little_loops.logger import Logger
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
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
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
45 builtin_dir = get_builtin_loops_dir()
46 source = builtin_dir / f"{loop_name}.yaml"
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
55 loops_dir.mkdir(exist_ok=True)
56 dest = loops_dir / f"{loop_name}.yaml"
58 if dest.exists():
59 logger.error(f"Loop already exists: {dest}")
60 print("Remove it first or edit it directly.")
61 return 1
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