File size: 5,208 Bytes
2cf7040
 
 
 
9432271
2cf7040
 
 
 
 
 
 
9432271
2cf7040
 
 
 
 
 
 
 
 
9432271
2cf7040
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9432271
2cf7040
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9432271
2cf7040
 
 
 
 
9432271
2cf7040
 
 
 
 
9432271
2cf7040
 
9432271
2cf7040
 
 
 
 
 
 
 
 
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
"""ASCII banner for sibyl-memory-cli.

Prints the SIBYL wordmark in ANSI Shadow boxchars with a 24-bit truecolor
vertical gradient flowing from cream/white at the top through warm gold
to deep ochre at the bottom β€” aligned with the lab visual identity per
the operator's brand-discipline rule (creme palette, deep-ochre accent).

Gracefully degrades:
  - NO_COLOR env var set       β†’ plain text fallback
  - stdout is not a TTY        β†’ plain text fallback (or skip entirely)
  - TERM=dumb                  β†’ plain text fallback

Truecolor support is detected via $COLORTERM (truecolor / 24bit) β€” most
modern terminals (iTerm2, Alacritty, Kitty, wezterm, Windows Terminal,
modern xterm builds, Ghostty) advertise it. Falls back to 256-color
gradient when not available.
"""
from __future__ import annotations

import os
import sys

# ANSI Shadow rendering of "SIBYL" β€” 6 rows, 41 cols. Each row gets its
# own gradient color (top = pale cream/white, bottom = deep ochre).
_LINES = (
    "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—β–ˆβ–ˆβ•—     ",
    "β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘     ",
    "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•‘     ",
    "β•šβ•β•β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—  β•šβ–ˆβ–ˆβ•”β•  β–ˆβ–ˆβ•‘     ",
    "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—",
    "β•šβ•β•β•β•β•β•β•β•šβ•β•β•šβ•β•β•β•β•β•    β•šβ•β•   β•šβ•β•β•β•β•β•β•",
)

# Vertical gradient Β· cream β†’ gold β†’ deep ochre. One RGB tuple per row.
# Tuned against the SIBYL palette: --paper #f5f1e6 (top blend),
# --accent #8a6a2a (mid-bottom), with extra highlight + shadow stops
# to give the wordmark visible dimension.
_GRADIENT = (
    (253, 251, 245),   # almost white, slight cream      (top highlight)
    (244, 229, 184),   # pale gold                       (upper)
    (224, 194, 119),   # mid gold                        (upper-mid)
    (184, 146,  73),   # rich ochre gold                 (mid)
    (138, 106,  42),   # deep ochre Β· brand --accent     (lower)
    (106,  79,  31),   # deepest                         (bottom shadow)
)

_TAGLINE = "memory you can hold in your hand"
_ATTRIBUTION = "a Sibyl Labs LLC Product. Agentic Infrastructure and Memory Products"


def _supports_truecolor() -> bool:
    """Detect 24-bit color support. Conservative β€” fall back gracefully."""
    if os.environ.get("NO_COLOR"):
        return False
    if os.environ.get("TERM", "").lower() == "dumb":
        return False
    if not sys.stdout.isatty():
        return False
    colorterm = os.environ.get("COLORTERM", "").lower()
    if "truecolor" in colorterm or "24bit" in colorterm:
        return True
    # Many modern terminals don't set COLORTERM but do support truecolor.
    # Recognize the well-behaved emitters.
    term_program = os.environ.get("TERM_PROGRAM", "").lower()
    if term_program in {"iterm.app", "wezterm", "ghostty", "vscode", "tabby"}:
        return True
    term = os.environ.get("TERM", "").lower()
    if any(k in term for k in ("256color", "kitty", "alacritty", "xterm-direct")):
        return True
    return False


def _color_supported() -> bool:
    """Plain ANSI color (3/4-bit). Stricter than truecolor."""
    if os.environ.get("NO_COLOR"):
        return False
    if os.environ.get("TERM", "").lower() == "dumb":
        return False
    return sys.stdout.isatty()


def _rgb(r: int, g: int, b: int) -> str:
    return f"\033[38;2;{r};{g};{b}m"


_RESET = "\033[0m"


def render_banner(*, force_color: bool | None = None) -> str:
    """Return the banner as a string ready to print.

    Args:
        force_color: Override auto-detection. None = auto, True = force
            truecolor, False = force plain text. Useful for testing.
    """
    use_truecolor = force_color if force_color is not None else _supports_truecolor()

    if not use_truecolor:
        # Plain text β€” still visually clean, just no color.
        body = "\n".join("  " + line for line in _LINES)
        tagline = f"\n  {_TAGLINE}"
        attribution = f"\n  {_ATTRIBUTION}\n"
        return body + tagline + attribution

    # Colored β€” apply per-row gradient.
    colored_lines = []
    for line, (r, g, b) in zip(_LINES, _GRADIENT):
        colored_lines.append(f"  {_rgb(r, g, b)}{line}{_RESET}")

    body = "\n".join(colored_lines)
    # Tagline in the deepest gold β€” present, but not competing with the wordmark.
    r, g, b = _GRADIENT[-1]
    tagline = f"\n  {_rgb(r, g, b)}{_TAGLINE}{_RESET}"
    # Attribution dimmer still β€” a half-step below the tagline so the hierarchy
    # reads SIBYL > tagline > attribution at a glance. ANSI dim (\033[2m) gives
    # ~55% perceived opacity across the supported terminals.
    attribution = f"\n  \033[2m{_rgb(r, g, b)}{_ATTRIBUTION}{_RESET}\n"
    return body + tagline + attribution


def print_banner(*, force_color: bool | None = None) -> None:
    """Print the banner. Safe to call unconditionally; honors NO_COLOR + TTY checks."""
    print(render_banner(force_color=force_color))