sibyl-memory-cli 0.1.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sibyl-memory-cli
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats.
5
- Author-email: Sibyl Labs <sibyl@sibyllabs.org>
5
+ Author-email: "SIBYL, Sibyl Labs LLC" <sibyl@sibyllabs.org>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://sibyllabs.org/plugin
8
8
  Project-URL: Documentation, https://docs.sibyllabs.org/memory/
@@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sibyl-memory-cli"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats."
9
- authors = [{ name = "Sibyl Labs", email = "sibyl@sibyllabs.org" }]
9
+ authors = [{ name = "SIBYL, Sibyl Labs LLC", email = "sibyl@sibyllabs.org" }]
10
10
  license = { text = "MIT" }
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.10"
@@ -0,0 +1,117 @@
1
+ """ASCII banner for sibyl-memory-cli.
2
+
3
+ Prints the SIBYL wordmark in ANSI Shadow boxchars with a 24-bit truecolor
4
+ vertical gradient flowing from cream/white at the top through warm gold
5
+ to deep ochre at the bottom — aligned with the lab visual identity per
6
+ the operator's brand-discipline rule (creme palette, deep-ochre accent).
7
+
8
+ Gracefully degrades:
9
+ - NO_COLOR env var set → plain text fallback
10
+ - stdout is not a TTY → plain text fallback (or skip entirely)
11
+ - TERM=dumb → plain text fallback
12
+
13
+ Truecolor support is detected via $COLORTERM (truecolor / 24bit) — most
14
+ modern terminals (iTerm2, Alacritty, Kitty, wezterm, Windows Terminal,
15
+ modern xterm builds, Ghostty) advertise it. Falls back to 256-color
16
+ gradient when not available.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import os
21
+ import sys
22
+
23
+ # ANSI Shadow rendering of "SIBYL" — 6 rows, 41 cols. Each row gets its
24
+ # own gradient color (top = pale cream/white, bottom = deep ochre).
25
+ _LINES = (
26
+ "███████╗██╗██████╗ ██╗ ██╗██╗ ",
27
+ "██╔════╝██║██╔══██╗╚██╗ ██╔╝██║ ",
28
+ "███████╗██║██████╔╝ ╚████╔╝ ██║ ",
29
+ "╚════██║██║██╔══██╗ ╚██╔╝ ██║ ",
30
+ "███████║██║██████╔╝ ██║ ███████╗",
31
+ "╚══════╝╚═╝╚═════╝ ╚═╝ ╚══════╝",
32
+ )
33
+
34
+ # Vertical gradient · cream → gold → deep ochre. One RGB tuple per row.
35
+ # Tuned against the SIBYL palette: --paper #f5f1e6 (top blend),
36
+ # --accent #8a6a2a (mid-bottom), with extra highlight + shadow stops
37
+ # to give the wordmark visible dimension.
38
+ _GRADIENT = (
39
+ (253, 251, 245), # almost white, slight cream (top highlight)
40
+ (244, 229, 184), # pale gold (upper)
41
+ (224, 194, 119), # mid gold (upper-mid)
42
+ (184, 146, 73), # rich ochre gold (mid)
43
+ (138, 106, 42), # deep ochre · brand --accent (lower)
44
+ (106, 79, 31), # deepest (bottom shadow)
45
+ )
46
+
47
+ _TAGLINE = "memory you can hold in your hand"
48
+
49
+
50
+ def _supports_truecolor() -> bool:
51
+ """Detect 24-bit color support. Conservative — fall back gracefully."""
52
+ if os.environ.get("NO_COLOR"):
53
+ return False
54
+ if os.environ.get("TERM", "").lower() == "dumb":
55
+ return False
56
+ if not sys.stdout.isatty():
57
+ return False
58
+ colorterm = os.environ.get("COLORTERM", "").lower()
59
+ if "truecolor" in colorterm or "24bit" in colorterm:
60
+ return True
61
+ # Many modern terminals don't set COLORTERM but do support truecolor.
62
+ # Recognize the well-behaved emitters.
63
+ term_program = os.environ.get("TERM_PROGRAM", "").lower()
64
+ if term_program in {"iterm.app", "wezterm", "ghostty", "vscode", "tabby"}:
65
+ return True
66
+ term = os.environ.get("TERM", "").lower()
67
+ if any(k in term for k in ("256color", "kitty", "alacritty", "xterm-direct")):
68
+ return True
69
+ return False
70
+
71
+
72
+ def _color_supported() -> bool:
73
+ """Plain ANSI color (3/4-bit). Stricter than truecolor."""
74
+ if os.environ.get("NO_COLOR"):
75
+ return False
76
+ if os.environ.get("TERM", "").lower() == "dumb":
77
+ return False
78
+ return sys.stdout.isatty()
79
+
80
+
81
+ def _rgb(r: int, g: int, b: int) -> str:
82
+ return f"\033[38;2;{r};{g};{b}m"
83
+
84
+
85
+ _RESET = "\033[0m"
86
+
87
+
88
+ def render_banner(*, force_color: bool | None = None) -> str:
89
+ """Return the banner as a string ready to print.
90
+
91
+ Args:
92
+ force_color: Override auto-detection. None = auto, True = force
93
+ truecolor, False = force plain text. Useful for testing.
94
+ """
95
+ use_truecolor = force_color if force_color is not None else _supports_truecolor()
96
+
97
+ if not use_truecolor:
98
+ # Plain text — still visually clean, just no color.
99
+ body = "\n".join(" " + line for line in _LINES)
100
+ tagline = f"\n {_TAGLINE}\n"
101
+ return body + tagline
102
+
103
+ # Colored — apply per-row gradient.
104
+ colored_lines = []
105
+ for line, (r, g, b) in zip(_LINES, _GRADIENT):
106
+ colored_lines.append(f" {_rgb(r, g, b)}{line}{_RESET}")
107
+
108
+ body = "\n".join(colored_lines)
109
+ # Tagline in dim italic-feeling color (the deepest gold)
110
+ r, g, b = _GRADIENT[-1]
111
+ tagline = f"\n {_rgb(r, g, b)}{_TAGLINE}{_RESET}\n"
112
+ return body + tagline
113
+
114
+
115
+ def print_banner(*, force_color: bool | None = None) -> None:
116
+ """Print the banner. Safe to call unconditionally; honors NO_COLOR + TTY checks."""
117
+ print(render_banner(force_color=force_color))
@@ -166,6 +166,11 @@ def cmd_init(args: argparse.Namespace) -> int:
166
166
  The pairing code is printed in the terminal. If the user picks the
167
167
  email path in the browser, they type both their email and this code.
168
168
  No external email service is required."""
169
+ # Brand moment — gold/white gradient SIBYL wordmark.
170
+ # Honors NO_COLOR + TTY detection automatically; safe to always call.
171
+ from ._banner import print_banner
172
+ print_banner()
173
+
169
174
  cred_path = Path(args.credentials).expanduser()
170
175
  if cred_path.exists() and not args.force:
171
176
  existing = read_credentials(cred_path) or {}
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sibyl-memory-cli
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats.
5
- Author-email: Sibyl Labs <sibyl@sibyllabs.org>
5
+ Author-email: "SIBYL, Sibyl Labs LLC" <sibyl@sibyllabs.org>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://sibyllabs.org/plugin
8
8
  Project-URL: Documentation, https://docs.sibyllabs.org/memory/
@@ -1,6 +1,7 @@
1
1
  README.md
2
2
  pyproject.toml
3
3
  src/sibyl_memory_cli/__init__.py
4
+ src/sibyl_memory_cli/_banner.py
4
5
  src/sibyl_memory_cli/cli.py
5
6
  src/sibyl_memory_cli.egg-info/PKG-INFO
6
7
  src/sibyl_memory_cli.egg-info/SOURCES.txt