hubble-cli 4.0.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.
- hubble/__init__.py +3 -0
- hubble/__main__.py +4 -0
- hubble/agent.py +546 -0
- hubble/banner.py +484 -0
- hubble/board.py +118 -0
- hubble/main.py +299 -0
- hubble/models.py +92 -0
- hubble/onboarding.py +94 -0
- hubble/permissions.py +139 -0
- hubble/prompts.py +157 -0
- hubble/provider.py +283 -0
- hubble/providers.py +186 -0
- hubble/repl.py +976 -0
- hubble/scanner.py +134 -0
- hubble/session.py +128 -0
- hubble/settings.py +184 -0
- hubble/skills.py +173 -0
- hubble/spinner.py +77 -0
- hubble/tools.py +763 -0
- hubble/ui.py +469 -0
- hubble/web.py +279 -0
- hubble_cli-4.0.0.dist-info/METADATA +275 -0
- hubble_cli-4.0.0.dist-info/RECORD +27 -0
- hubble_cli-4.0.0.dist-info/WHEEL +5 -0
- hubble_cli-4.0.0.dist-info/entry_points.txt +3 -0
- hubble_cli-4.0.0.dist-info/licenses/LICENSE +21 -0
- hubble_cli-4.0.0.dist-info/top_level.txt +1 -0
hubble/spinner.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Animated activity indicator: pulsing glyph, rotating verbs and a shimmer sweeping over the text.
|
|
2
|
+
|
|
3
|
+
Used through rich.live.Live, which calls __rich__ on every refresh, so the animation is purely
|
|
4
|
+
time-based and costs nothing between frames.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import random
|
|
8
|
+
import time
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from rich.live import Live
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
|
|
14
|
+
VERBS = [
|
|
15
|
+
"Thinking", "Stargazing", "Orbiting", "Focusing the lens", "Aligning mirrors", "Charting the stars",
|
|
16
|
+
"Scanning the cosmos", "Decoding signals", "Calculating trajectories", "Mapping nebulae", "Pondering",
|
|
17
|
+
"Drifting through code", "Collecting photons", "Warping", "Consulting the stars", "Tuning the antenna",
|
|
18
|
+
"Surveying galaxies", "Cogitating", "Tinkering", "Noodling", "Contemplating", "Launching probes",
|
|
19
|
+
]
|
|
20
|
+
GLYPHS = ["·", "✢", "✳", "✶", "✻", "✽", "✻", "✶", "✳", "✢"]
|
|
21
|
+
|
|
22
|
+
# Warm shimmer palette: base, near highlight, highlight.
|
|
23
|
+
BASE, NEAR, PEAK = "#d7875f", "#ffaf87", "bold #ffe7d7"
|
|
24
|
+
GLYPH_STYLE = "bold #ff875f"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Shimmer:
|
|
28
|
+
def __init__(self, label: Optional[str] = None, hint: str = "ctrl+c to interrupt", details: bool = True):
|
|
29
|
+
self.start = time.time()
|
|
30
|
+
self.details = details
|
|
31
|
+
self.label = label
|
|
32
|
+
self.hint = hint
|
|
33
|
+
self.tokens = 0
|
|
34
|
+
self._offset = random.randrange(len(VERBS))
|
|
35
|
+
|
|
36
|
+
def set_label(self, label: Optional[str]):
|
|
37
|
+
self.label = label
|
|
38
|
+
|
|
39
|
+
def __rich__(self) -> Text:
|
|
40
|
+
t = time.time() - self.start
|
|
41
|
+
glyph = GLYPHS[int(t * 10) % len(GLYPHS)]
|
|
42
|
+
words = (self.label or VERBS[(int(t / 3.5) + self._offset) % len(VERBS)]) + "…"
|
|
43
|
+
sweep = len(words) + 10
|
|
44
|
+
pos = (t * 16) % sweep - 5 # highlight position; runs off both ends for a pause between sweeps
|
|
45
|
+
out = Text(f"{glyph} ", style=GLYPH_STYLE)
|
|
46
|
+
for i, ch in enumerate(words):
|
|
47
|
+
d = abs(i - pos)
|
|
48
|
+
out.append(ch, style=PEAK if d < 1.2 else NEAR if d < 3 else BASE)
|
|
49
|
+
if not self.details:
|
|
50
|
+
return out
|
|
51
|
+
details = [f"{int(t)}s"]
|
|
52
|
+
if self.tokens:
|
|
53
|
+
details.append(f"↓ {self.tokens:,} tokens")
|
|
54
|
+
if self.hint:
|
|
55
|
+
details.append(self.hint)
|
|
56
|
+
out.append(f" ({' · '.join(details)})", style="dim")
|
|
57
|
+
return out
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def start_shimmer(console, label: Optional[str] = None) -> "ShimmerLive":
|
|
61
|
+
live = ShimmerLive(Shimmer(label), console)
|
|
62
|
+
live.start()
|
|
63
|
+
return live
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ShimmerLive:
|
|
67
|
+
"""Live display with the same start/stop interface as rich's Status."""
|
|
68
|
+
|
|
69
|
+
def __init__(self, shimmer: Shimmer, console):
|
|
70
|
+
self.shimmer = shimmer
|
|
71
|
+
self.live = Live(shimmer, console=console, refresh_per_second=15, transient=True)
|
|
72
|
+
|
|
73
|
+
def start(self):
|
|
74
|
+
self.live.start()
|
|
75
|
+
|
|
76
|
+
def stop(self):
|
|
77
|
+
self.live.stop()
|