File size: 3,624 Bytes
5ef3875
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""The YCode start-up banner.

The art is assembled from per-letter glyphs (ANSI Shadow style) so every row
has exactly the same width and the letters always line up. A plain-ASCII
fallback is used when the terminal cannot encode box-drawing characters.
"""

from __future__ import annotations

from dataclasses import dataclass

_GLYPHS: dict[str, tuple[str, ...]] = {
    "Y": (
        "β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—",
        "β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•",
        " β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• ",
        "  β•šβ–ˆβ–ˆβ•”β•  ",
        "   β–ˆβ–ˆβ•‘   ",
        "   β•šβ•β•   ",
    ),
    "C": (
        " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—",
        "β–ˆβ–ˆβ•”β•β•β•β•β•",
        "β–ˆβ–ˆβ•‘     ",
        "β–ˆβ–ˆβ•‘     ",
        "β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—",
        " β•šβ•β•β•β•β•β•",
    ),
    "O": (
        " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— ",
        "β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—",
        "β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘",
        "β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘",
        "β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•",
        " β•šβ•β•β•β•β•β• ",
    ),
    "D": (
        "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— ",
        "β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—",
        "β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘",
        "β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘",
        "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•",
        "β•šβ•β•β•β•β•β• ",
    ),
    "E": (
        "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—",
        "β–ˆβ–ˆβ•”β•β•β•β•β•",
        "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  ",
        "β–ˆβ–ˆβ•”β•β•β•  ",
        "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—",
        "β•šβ•β•β•β•β•β•β•",
    ),
}

_ASCII_FALLBACK = (
    "__   __ ____          _      ",
    "\\ \\ / // ___|___   __| | ___ ",
    " \\ V /| |   / _ \\ / _` |/ _ \\",
    "  | | | |__| (_) | (_| |  __/",
    "  |_|  \\____\\___/ \\__,_|\\___|",
)

TAGLINE = "AI Coding Agent"


def render_word(word: str = "YCODE", gap: str = "") -> list[str]:
    """Render ``word`` with the block glyphs; returns one string per row."""
    letters = [_GLYPHS[ch] for ch in word.upper()]
    height = len(letters[0])
    return [gap.join(letter[row] for letter in letters) for row in range(height)]


def banner_lines(*, unicode: bool = True) -> list[str]:
    return render_word("YCODE") if unicode else list(_ASCII_FALLBACK)


def supports_unicode(encoding: str | None) -> bool:
    if not encoding:
        return False
    try:
        "β–ˆβ•—β•”β•β•‘β•šβ•".encode(encoding)
    except (LookupError, UnicodeEncodeError):
        return False
    return True


@dataclass(frozen=True)
class BannerInfo:
    version: str
    model: str
    directory: str
    branch: str | None = None
    project_types: tuple[str, ...] = ()
    approval_mode: str = "normal"
    instructions_loaded: bool = False


def info_lines(info: BannerInfo) -> list[tuple[str, str]]:
    """Key/value rows shown under the banner. Never includes secrets."""
    rows = [
        ("YCode", f"v{info.version}"),
        ("Model", info.model),
        ("Directory", info.directory),
    ]
    if info.branch:
        rows.append(("Git branch", info.branch))
    if info.project_types:
        rows.append(("Project", ", ".join(info.project_types)))
    rows.append(("Approvals", info.approval_mode))
    if info.instructions_loaded:
        rows.append(("Instructions", "YCODE.md loaded"))
    return rows


def render_banner_text(info: BannerInfo, *, unicode: bool = True) -> str:
    """Plain-text banner (used by tests and non-rich output)."""
    lines = banner_lines(unicode=unicode)
    width = max(len(line) for line in lines)
    out = list(lines)
    out.append(TAGLINE.center(width).rstrip())
    out.append("")
    out.extend(f"{key + ':':<13} {value}" for key, value in info_lines(info))
    return "\n".join(out)