sediment-cli 0.1.0__py3-none-any.whl
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.
- sediment_cli/__init__.py +22 -0
- sediment_cli/attribution.py +3881 -0
- sediment_cli/cli.py +1922 -0
- sediment_cli/client.py +323 -0
- sediment_cli/delivery.py +1334 -0
- sediment_cli/local_postgres.py +337 -0
- sediment_cli/transcript.py +1764 -0
- sediment_cli/ui.py +123 -0
- sediment_cli-0.1.0.dist-info/METADATA +16 -0
- sediment_cli-0.1.0.dist-info/RECORD +13 -0
- sediment_cli-0.1.0.dist-info/WHEEL +4 -0
- sediment_cli-0.1.0.dist-info/entry_points.txt +2 -0
- sediment_cli-0.1.0.dist-info/licenses/LICENSE +661 -0
sediment_cli/ui.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"""
|
|
3
|
+
Terminal styling for the operator CLI, in the Sediment brand palette.
|
|
4
|
+
|
|
5
|
+
Stdlib-only ANSI. Styling is gated per stream: on only for a TTY, never
|
|
6
|
+
under ``NO_COLOR`` or ``TERM=dumb`` — piped output, tests, and CI read
|
|
7
|
+
exactly the bytes they read before this module existed. Truecolor when
|
|
8
|
+
``COLORTERM`` advertises it, 256-color approximations otherwise.
|
|
9
|
+
|
|
10
|
+
The palette is the site design system (the ``--sds-*`` tokens): sandstone
|
|
11
|
+
is the one accent, phosphor means success, iron oxide means failure,
|
|
12
|
+
bleached is for headings, and hierarchy below that is dim — never a fourth
|
|
13
|
+
color. Flat color only (the brand allows no gradients), so the strata mark
|
|
14
|
+
is three flat bands, light to dark.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
from typing import TextIO
|
|
22
|
+
|
|
23
|
+
# name -> (truecolor RGB, 256-color fallback), from the brand kit.
|
|
24
|
+
_PALETTE = {
|
|
25
|
+
"sandstone": ((196, 147, 90), 173), # --sds-sandstone · primary accent
|
|
26
|
+
"phosphor": ((95, 216, 149), 78), # positive / success
|
|
27
|
+
"iron-oxide": ((184, 73, 43), 130), # negative / errors
|
|
28
|
+
"bleached": ((240, 237, 232), 255), # --sds-bleached · headings
|
|
29
|
+
"ochre": ((139, 115, 85), 95), # --sds-ochre · muted
|
|
30
|
+
}
|
|
31
|
+
_ATTRS = {"bold": "\x1b[1m", "dim": "\x1b[2m"}
|
|
32
|
+
_RESET = "\x1b[0m"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def on(stream: TextIO | None = None) -> bool:
|
|
36
|
+
"""Whether *stream* (default stdout) gets styled output."""
|
|
37
|
+
stream = sys.stdout if stream is None else stream
|
|
38
|
+
if "NO_COLOR" in os.environ or os.environ.get("TERM") == "dumb":
|
|
39
|
+
return False
|
|
40
|
+
return hasattr(stream, "isatty") and stream.isatty()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _fg(name: str) -> str:
|
|
44
|
+
rgb, fallback = _PALETTE[name]
|
|
45
|
+
if os.environ.get("COLORTERM") in ("truecolor", "24bit"):
|
|
46
|
+
return "\x1b[38;2;%d;%d;%dm" % rgb
|
|
47
|
+
return f"\x1b[38;5;{fallback}m"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def style(text: str, *names: str, stream: TextIO | None = None) -> str:
|
|
51
|
+
"""*text* wrapped in the named palette colors / attrs, unchanged when the
|
|
52
|
+
stream is not a styled TTY. Pad before styling — ANSI codes break
|
|
53
|
+
``str.format`` field widths."""
|
|
54
|
+
if not on(stream):
|
|
55
|
+
return text
|
|
56
|
+
codes = "".join(_ATTRS.get(n) or _fg(n) for n in names)
|
|
57
|
+
return f"{codes}{text}{_RESET}"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def glyph(char: str, name: str, stream: TextIO | None = None) -> str:
|
|
61
|
+
"""A styled ``✓ ``-style prefix on a styled TTY, ``""`` otherwise, so
|
|
62
|
+
plain output keeps its exact historical bytes."""
|
|
63
|
+
return f"{style(char, name, stream=stream)} " if on(stream) else ""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def error_line(msg: str) -> str:
|
|
67
|
+
"""The CLI's one stderr error shape: ``✗ error: <msg>`` styled on a
|
|
68
|
+
TTY, exactly ``error: <msg>`` piped — every verb routes through this so
|
|
69
|
+
the vocabulary and the bytes stay uniform."""
|
|
70
|
+
err = sys.stderr
|
|
71
|
+
label = glyph("✗", "iron-oxide", err) + style("error:", "iron-oxide", stream=err)
|
|
72
|
+
return f"{label} {msg}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def warn_line(msg: str) -> str:
|
|
76
|
+
"""The matching stderr warning shape: ``⚠ warning: <msg>`` styled on a
|
|
77
|
+
TTY, exactly ``warning: <msg>`` piped."""
|
|
78
|
+
err = sys.stderr
|
|
79
|
+
label = glyph("⚠", "sandstone", err) + style("warning:", "sandstone", stream=err)
|
|
80
|
+
return f"{label} {msg}"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Listing sections of help output whose first cell (command / flag) gets the
|
|
84
|
+
# accent; USAGE bodies and description text stay uncolored.
|
|
85
|
+
_HELP_LISTINGS = frozenset(
|
|
86
|
+
{"COMMANDS:", "FORMATS:", "OPTIONS:", "ARGUMENTS:", "REPORTS:"}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def style_help(text: str, stream: TextIO | None = None) -> str:
|
|
91
|
+
"""TTY-gated color pass over already-formatted help text: bold
|
|
92
|
+
headings, accent on the invocation cell of listing rows. Plain text
|
|
93
|
+
passes through untouched, so goldens and pipes never see codes."""
|
|
94
|
+
if not on(stream):
|
|
95
|
+
return text
|
|
96
|
+
out: list[str] = []
|
|
97
|
+
listing = False
|
|
98
|
+
for line in text.splitlines():
|
|
99
|
+
if line and not line.startswith(" ") and line == line.upper():
|
|
100
|
+
listing = line.endswith(":") and line in _HELP_LISTINGS
|
|
101
|
+
out.append(style(line, "bleached", "bold", stream=stream))
|
|
102
|
+
elif listing and line.startswith(" ") and len(line) > 2 and line[2] != " ":
|
|
103
|
+
cell, gap, rest = line[2:].partition(" ")
|
|
104
|
+
out.append(" " + style(cell, "sandstone", stream=stream) + gap + rest)
|
|
105
|
+
else:
|
|
106
|
+
out.append(line)
|
|
107
|
+
return "\n".join(out) + ("\n" if text.endswith("\n") else "")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def banner(title: str, subtitle: str) -> None:
|
|
111
|
+
"""The strata mark: wordmark over three flat bands, light to dark.
|
|
112
|
+
TTY-only — a piped invocation prints no banner at all."""
|
|
113
|
+
if not on():
|
|
114
|
+
return
|
|
115
|
+
bands = (
|
|
116
|
+
style("▬" * 10, "bleached")
|
|
117
|
+
+ style("▬" * 10, "sandstone")
|
|
118
|
+
+ style("▬" * 10, "ochre")
|
|
119
|
+
)
|
|
120
|
+
print()
|
|
121
|
+
print(f" {style(title, 'bleached', 'bold')} {style(subtitle, 'dim')}")
|
|
122
|
+
print(f" {bands}")
|
|
123
|
+
print()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sediment-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The sediment command: login, install, server, facts, exports
|
|
5
|
+
Project-URL: Source, https://github.com/sediment-ai/sediment
|
|
6
|
+
Project-URL: Documentation, https://github.com/sediment-ai/sediment/tree/main/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/sediment-ai/sediment/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/sediment-ai/sediment/blob/main/CHANGELOG.md
|
|
9
|
+
License-Expression: AGPL-3.0-or-later
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Requires-Dist: httpx>=0.27
|
|
13
|
+
Requires-Dist: sediment-api==0.1.0
|
|
14
|
+
Requires-Dist: sediment-core==0.1.0
|
|
15
|
+
Requires-Dist: sediment-derive==0.1.0
|
|
16
|
+
Requires-Dist: sediment-export==0.1.0
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
sediment_cli/__init__.py,sha256=6gb2sotSZC-wSD3UBl6h-9c5qPw8Df0UnBKLkmwdzVk,782
|
|
2
|
+
sediment_cli/attribution.py,sha256=saR1WOKd9IAQp-EKMGWKgttdUF6vzjTqFhSZbsXLZpk,148644
|
|
3
|
+
sediment_cli/cli.py,sha256=ixAiPhZjIt8NNZtyLZ9-U_ocV7Qs_ul_3ea0PF_j4j0,74974
|
|
4
|
+
sediment_cli/client.py,sha256=-PSnax17b2P4FGRfY5jxXSw5tHr-htJ5VobzY7xQDDw,11337
|
|
5
|
+
sediment_cli/delivery.py,sha256=iNfdVXTyYvPrzUuIthomlQPU3zesw-vTaqKKKpRUzws,47874
|
|
6
|
+
sediment_cli/local_postgres.py,sha256=NTYo0Wz2l0BahMqjCglRufZ4z6wN6CilfYkRuAfQR-s,12922
|
|
7
|
+
sediment_cli/transcript.py,sha256=3rtBHhHLCVRLRJOf2TGOUypR2OOyqupP8ZOKHpE9Bh8,70158
|
|
8
|
+
sediment_cli/ui.py,sha256=Z3OGv4wwDz6p3T-CVtqBlFBybCVnviy_UtehBXzo2UU,4811
|
|
9
|
+
sediment_cli-0.1.0.dist-info/METADATA,sha256=JbOniGzESp1Hj27MMX94xGfj9J665trzSEofz2rXc1Y,683
|
|
10
|
+
sediment_cli-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
11
|
+
sediment_cli-0.1.0.dist-info/entry_points.txt,sha256=1XF4d332LhsC0uzRrbOnB3NQooeCD7XtW74ioGaUVvo,47
|
|
12
|
+
sediment_cli-0.1.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
13
|
+
sediment_cli-0.1.0.dist-info/RECORD,,
|