Coverage for little_loops / init / core.py: 18%
33 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-06-16 13:11 -0500
« prev ^ index » next coverage.py v7.12.0, created at 2026-06-16 13:11 -0500
1"""Config building for headless ll-init."""
3from __future__ import annotations
5from typing import Any
7from little_loops.init.detect import TemplateMatch
9SCHEMA_URL = (
10 "https://raw.githubusercontent.com/BrennonTWilliams/little-loops/main/config-schema.json"
11)
13_DEFAULT_ANALYTICS_CAPTURE: dict[str, Any] = {
14 "skills": ["*"],
15 "cli_commands": ["*"],
16 "corrections": True,
17 "file_events": True,
18}
21def build_config(
22 template: TemplateMatch,
23 choices: dict[str, Any] | None = None,
24) -> dict[str, Any]:
25 """Build the output ll-config.json dict from a template and optional choices.
27 Ports the skill's Step 4 and Step 8 config-building logic. The resulting
28 dict is ready for serialisation with ``atomic_write_json``.
30 Args:
31 template: Matched template from detect_project_type().
32 choices: Optional overrides. Recognised keys:
33 - ``project_name`` (str): value written to project.name.
34 - ``src_dir`` (str): override project.src_dir.
35 - ``product_enabled`` (bool, default True): include product section.
36 - ``analytics_enabled`` (bool, default True): include analytics section.
37 - ``context_monitor_enabled`` (bool, default True): include context_monitor.
38 - ``learning_tests_enabled`` (bool, default True): include learning_tests.
40 Returns:
41 Complete config dict (``$schema`` key first, then sections).
42 """
43 choices = choices or {}
44 data = template.data
46 config: dict[str, Any] = {"$schema": SCHEMA_URL}
48 # --- project ---
49 project: dict[str, Any] = dict(data.get("project", {}))
50 if choices.get("project_name"):
51 project["name"] = choices["project_name"]
52 if choices.get("src_dir"):
53 project["src_dir"] = choices["src_dir"]
54 config["project"] = project
56 # --- issues ---
57 config["issues"] = dict(data.get("issues", {}))
59 # --- scan ---
60 config["scan"] = dict(data.get("scan", {}))
62 # --- learning_tests (always written) ---
63 learning_tests_enabled = bool(choices.get("learning_tests_enabled", True))
64 config["learning_tests"] = {"enabled": learning_tests_enabled}
66 # --- analytics (always written) ---
67 analytics_enabled = bool(choices.get("analytics_enabled", True))
68 if analytics_enabled:
69 config["analytics"] = {
70 "enabled": True,
71 "capture": dict(_DEFAULT_ANALYTICS_CAPTURE),
72 }
73 else:
74 config["analytics"] = {"enabled": False}
76 # --- context_monitor (omit if disabled) ---
77 context_monitor_enabled = bool(choices.get("context_monitor_enabled", True))
78 if context_monitor_enabled:
79 config["context_monitor"] = {"enabled": True}
81 # --- product (omit if disabled; default True for --yes mode) ---
82 product_enabled = bool(choices.get("product_enabled", True))
83 if product_enabled:
84 config["product"] = {"enabled": True}
86 # --- history.session_digest (always written) ---
87 session_digest_enabled = bool(choices.get("session_digest_enabled", True))
88 config["history"] = {
89 "session_digest": {
90 "enabled": session_digest_enabled,
91 "days": 7,
92 "char_cap": 1200,
93 }
94 }
96 # --- loops.run_defaults (always written; exposes the feature at init time) ---
97 config["loops"] = {
98 "run_defaults": {
99 "clear": False,
100 "show_diagrams": None,
101 "mode": None,
102 }
103 }
105 return config