File size: 2,296 Bytes
2415446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""Admin config source loading and source precedence."""

import os
from io import StringIO
from pathlib import Path
from typing import Literal

from dotenv import dotenv_values

from free_claude_code.config.env_files import (
    explicit_env_path as configured_explicit_env_path,
)
from free_claude_code.config.env_files import (
    repo_env_path as configured_repo_env_path,
)
from free_claude_code.config.env_files import (
    settings_env_files,
)
from free_claude_code.config.env_template import load_env_template_or_empty

from .manifest import FIELDS

SourceType = Literal[
    "default",
    "template",
    "repo_env",
    "managed_env",
    "explicit_env_file",
    "process",
]


def repo_env_path() -> Path:
    """Return the repo-local env path."""

    return configured_repo_env_path()


def explicit_env_path() -> Path | None:
    """Return the explicit FCC_ENV_FILE path, when configured."""

    return configured_explicit_env_path(os.environ)


def configured_env_files() -> tuple[tuple[SourceType, Path], ...]:
    """Return dotenv files in low-to-high precedence order."""

    source_names: tuple[SourceType, ...] = (
        "repo_env",
        "managed_env",
        "explicit_env_file",
    )
    return tuple(zip(source_names, settings_env_files(), strict=False))


def dotenv_values_from_text(text: str) -> dict[str, str]:
    """Parse dotenv text into string values."""

    values = dotenv_values(stream=StringIO(text))
    return {key: "" if value is None else value for key, value in values.items()}


def template_values() -> dict[str, str]:
    """Return .env.example values plus manifest defaults for newer fields."""

    values = dotenv_values_from_text(load_env_template_or_empty())
    for field in FIELDS:
        values.setdefault(field.key, field.default)
    return values


def dotenv_values_from_file(path: Path) -> dict[str, str]:
    """Return dotenv values from a file, or an empty mapping when absent."""

    if not path.is_file():
        return {}
    values = dotenv_values(path)
    return {key: "" if value is None else value for key, value in values.items()}


def is_locked_source(source: SourceType) -> bool:
    """Return whether an admin value source must not be overwritten."""

    return source in {"process", "explicit_env_file"}