Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2756f5f1dd |
@@ -32,10 +32,9 @@ separate dev team rather than an in-tree Worldtree tool.
|
||||
|
||||
## Current state / in-flight
|
||||
|
||||
_As of 2026-05-24 (post-v0.4.0 §5 entry point: layout reshape +
|
||||
Tools pane):_
|
||||
_As of 2026-05-24 (post-v0.4.1 Australis theme retheme):_
|
||||
|
||||
**Status: v0.4.0 shipped.** Nine core issues complete (`sse_client`
|
||||
**Status: v0.4.1 shipped.** Nine core issues complete (`sse_client`
|
||||
#1, `sessions` #2, `cli` #3, `tui` #4, `--end-user-id` #5, TUI
|
||||
startup error visibility #6, presenter contract semantics amendment
|
||||
#12, startup agent picker #8, §5 layout reshape + Tools pane #13)
|
||||
@@ -52,7 +51,8 @@ Static in the footer (static "Tools" v1; dynamic when more tabs
|
||||
land). CLI mode (--send) unaffected by design — INV-018.
|
||||
|
||||
Last commits on `main`:
|
||||
- v0.4.0 feat(tui): issue #13 — §5 layout reshape + Tools pane
|
||||
- v0.4.1 style(tui): apply Australis theme to TUI chrome + widgets
|
||||
- `24e4371` feat(tui): issue #13 — §5 layout reshape + Tools pane (v0.4.0)
|
||||
- `d30be12` feat(sessions,cli,tui): issue #8 — startup agent picker (v0.3.0)
|
||||
- `c85f6bd` fix(tui): anchor layout via dock so Input never moves (v0.2.1)
|
||||
- `3b9c610` feat(cli,tui): issue #12 — presenter contract semantics amendment (v0.2.0)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "ratatoskr"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
description = "Worldtree Conversation API debug TUI — multi-pane observability dashboard"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
+103
-3
@@ -17,6 +17,7 @@ import httpx
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Horizontal, Vertical
|
||||
from textual.theme import Theme
|
||||
from textual.widgets import (
|
||||
Footer,
|
||||
Header,
|
||||
@@ -61,6 +62,64 @@ from ratatoskr.sse_client import (
|
||||
stream_turn,
|
||||
)
|
||||
|
||||
# ---- Australis theme (https://github.com/lkraven/australis) ------------------
|
||||
#
|
||||
# The Australis Dark color theme, inspired by the Southern Lights. 16 cool-tone
|
||||
# terminal colors with medium contrast. Preference order: blue > cyan > green
|
||||
# for primary surfaces; Dawn accents (red/yellow/magenta) used sparingly for
|
||||
# terminal-event labels (error/cancelled).
|
||||
#
|
||||
# Mapping to Textual's Theme semantic tokens:
|
||||
# primary = Aurora blue (#6388D8) — focus rings, active selection.
|
||||
# secondary = Aurora cyan (#00b1a8) — secondary highlights.
|
||||
# accent = Aurora bright cyan (#42dcd1) — bright accents (pane-name, prompt echo).
|
||||
# success = Aurora green (#16B866) — [done] label.
|
||||
# warning = Dawn yellow (#e1c631) — [cancelled] label.
|
||||
# error = Dawn red (#ff491a) — [error] label.
|
||||
# foreground = Ice white (#a9bcc3) — default text.
|
||||
# background = Ice black (#222531) — App background.
|
||||
# surface = Sea bright black (#373b46) — raised chrome (header/footer/input).
|
||||
# panel = Sea dark 30 (#414751) — borders, separators.
|
||||
|
||||
AUSTRALIS_THEME = Theme(
|
||||
name="australis",
|
||||
primary="#6388D8",
|
||||
secondary="#00b1a8",
|
||||
accent="#42dcd1",
|
||||
success="#16B866",
|
||||
warning="#e1c631",
|
||||
error="#ff491a",
|
||||
foreground="#a9bcc3",
|
||||
background="#222531",
|
||||
surface="#373b46",
|
||||
panel="#414751",
|
||||
dark=True,
|
||||
variables={
|
||||
# Sea contrast palette — usable via $au-dark-50 etc. in TCSS.
|
||||
"au-dark-30": "#414751",
|
||||
"au-dark-40": "#565f69",
|
||||
"au-dark-50": "#6e7882",
|
||||
"au-dark-60": "#86929d",
|
||||
"au-bright-70": "#9daeb6",
|
||||
"au-bright-80": "#b3cbcf",
|
||||
"au-bright-white": "#cce7ec",
|
||||
"au-bright-blue": "#a4c4ff",
|
||||
"au-bright-cyan": "#42dcd1",
|
||||
"au-bright-green": "#51e08a",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# Direct hex constants for Rich Text styling (Done/Error/Cancelled labels +
|
||||
# transcript user-prompt echo). Themes set TCSS variables; Rich's RichText
|
||||
# style strings live outside the theme system, so we resolve to hex here.
|
||||
_AU_SUCCESS = "#16B866"
|
||||
_AU_ERROR = "#ff491a"
|
||||
_AU_WARNING = "#e1c631"
|
||||
_AU_USER_ECHO = "#42dcd1" # bright cyan — operator's voice
|
||||
_AU_DEMOTED = "#86929d" # dark 60 — demoted telemetry (was bare "dim")
|
||||
|
||||
|
||||
# ---- Issue #12 presenter contract semantics amendment -------------------------
|
||||
#
|
||||
# TuiPresenterState replaces the stateless _render_event_to_log with a stateful
|
||||
@@ -150,8 +209,14 @@ class TuiPresenterState:
|
||||
from rich.text import Text as RichText
|
||||
|
||||
def _dim(s: str) -> RichText:
|
||||
"""Wrap a demoted-telemetry line in dim style for the RichLog."""
|
||||
return RichText(s, style="dim")
|
||||
"""Wrap a demoted-telemetry line in Australis dark-60 grey.
|
||||
|
||||
v0.4.1 retheme: was `style="dim"` (terminal-dim filter, varies by
|
||||
emulator); now explicit Australis Sea dark-60 (#86929d) so the
|
||||
shade renders consistently across terminals and stays anchored to
|
||||
the brand palette.
|
||||
"""
|
||||
return RichText(s, style=_AU_DEMOTED)
|
||||
|
||||
try:
|
||||
# Thinking events: accumulate into buffer, update widget per delta.
|
||||
@@ -257,9 +322,16 @@ class AgentPickerApp(App[str | None]):
|
||||
dock: top;
|
||||
height: 1;
|
||||
padding: 0 1;
|
||||
color: $au-bright-cyan;
|
||||
background: $surface;
|
||||
}
|
||||
#agent-list {
|
||||
height: 1fr;
|
||||
background: $background;
|
||||
}
|
||||
#agent-list > ListItem.--highlight {
|
||||
background: $primary;
|
||||
color: $au-bright-white;
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -276,6 +348,8 @@ class AgentPickerApp(App[str | None]):
|
||||
# [no_agents] before constructing the picker.
|
||||
assert agents
|
||||
self.agents = agents
|
||||
self.register_theme(AUSTRALIS_THEME)
|
||||
self.theme = "australis"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
@@ -314,12 +388,18 @@ class RatatoskrApp(App[int]):
|
||||
# in the left column doesn't reflow the right column's TabbedContent.
|
||||
# The v0.2.1 layout-stability property is preserved within the left
|
||||
# column by docking thinking-current top + prompt bottom of that column.
|
||||
#
|
||||
# v0.4.1: Australis theme — Aurora blue/cyan primary, Ice background,
|
||||
# Sea darks for chrome separators. Widget colors use theme variables
|
||||
# ($primary/$accent/$au-dark-60/$au-bright-cyan/etc.) so a future theme
|
||||
# swap rebinds them centrally.
|
||||
DEFAULT_CSS = """
|
||||
#main-row {
|
||||
height: 1fr;
|
||||
}
|
||||
#left-column {
|
||||
width: 2fr;
|
||||
border-right: solid $panel;
|
||||
}
|
||||
#right-column {
|
||||
width: 1fr;
|
||||
@@ -327,24 +407,39 @@ class RatatoskrApp(App[int]):
|
||||
#thinking-current {
|
||||
dock: top;
|
||||
height: auto;
|
||||
color: $au-dark-60;
|
||||
}
|
||||
#transcript {
|
||||
height: 1fr;
|
||||
background: $background;
|
||||
}
|
||||
#tools-log {
|
||||
background: $background;
|
||||
}
|
||||
#prompt {
|
||||
dock: bottom;
|
||||
border: tall $panel;
|
||||
}
|
||||
#prompt:focus {
|
||||
border: tall $primary;
|
||||
}
|
||||
#identity {
|
||||
dock: bottom;
|
||||
height: 1;
|
||||
color: $au-bright-blue;
|
||||
padding: 0 1;
|
||||
}
|
||||
#pane-name {
|
||||
dock: bottom;
|
||||
height: 1;
|
||||
color: $au-bright-cyan;
|
||||
padding: 0 1;
|
||||
}
|
||||
#hint {
|
||||
dock: bottom;
|
||||
height: 1;
|
||||
color: $au-dark-60;
|
||||
padding: 0 1;
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -378,6 +473,8 @@ class RatatoskrApp(App[int]):
|
||||
self.active_turn_id: int | None = None
|
||||
self.stream_worker = None
|
||||
self.hint: str = self.HINT_IDLE
|
||||
self.register_theme(AUSTRALIS_THEME)
|
||||
self.theme = "australis"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
@@ -444,7 +541,10 @@ class RatatoskrApp(App[int]):
|
||||
content = event.input.value.strip()
|
||||
if not content:
|
||||
return
|
||||
log.write(f"❯ {content}") # noqa: RUF001 — intentional INV-006 prefix
|
||||
# v0.4.1 retheme: operator's voice gets Australis bright cyan so it
|
||||
# stands out against the default-foreground assistant text below it.
|
||||
from rich.text import Text as RichText
|
||||
log.write(RichText(f"❯ {content}", style=_AU_USER_ECHO)) # noqa: RUF001
|
||||
event.input.value = ""
|
||||
self.state = "streaming"
|
||||
self._set_hint(self.HINT_STREAMING)
|
||||
|
||||
+4
-2
@@ -430,9 +430,11 @@ class TestTuiPresenterState:
|
||||
raw=False,
|
||||
)
|
||||
renderable = log.write.call_args[0][0]
|
||||
# INV-003: must be a dim-styled Rich Text renderable, not a plain str.
|
||||
# INV-003: must be a styled Rich Text renderable, not a plain str.
|
||||
# v0.4.1 retheme: style is now Australis Sea dark-60 ("#86929d") instead
|
||||
# of the terminal-dim filter "dim". Assert non-empty styling either way.
|
||||
assert isinstance(renderable, RichText), type(renderable)
|
||||
assert renderable.style == "dim"
|
||||
assert renderable.style, "demoted telemetry must carry SOME style"
|
||||
text = renderable.plain
|
||||
assert text.startswith("· worker_phase:")
|
||||
assert "[worker_phase]" not in text
|
||||
|
||||
Reference in New Issue
Block a user