kiwi-code 0.0.34__tar.gz → 0.0.35__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.
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/PKG-INFO +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/pyproject.toml +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/main.py +40 -33
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/attach_content.py +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/command_result.py +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/file_browser.py +23 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/help.py +2 -2
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/id_picker.py +11 -11
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/login.py +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/runtime_cleanup.py +31 -7
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/runtime_logs.py +28 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/slash_picker.py +2 -1
- kiwi_code-0.0.35/tests/test_tui_palette.py +68 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/uv.lock +1 -1
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/.github/workflows/publish.yml +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/.github/workflows/test.yml +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/.gitignore +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/.python-version +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/CLAUDE.md +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/Makefile +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/README.md +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/__init__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/auth.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/cli.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/client.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/commands.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/logger.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/models.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/runtime_manager.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_cli/server.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_runtime/__init__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_runtime/__main__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_runtime/main.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_runtime/snake_game/.gitignore +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_runtime/snake_game/requirements.txt +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/__init__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/inline_file_picker.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/random_words.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/runtime_agent.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/__init__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/screens/dashboard.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/slash_commands.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/status_words.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/src/kiwi_tui/widgets.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/test_hello.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/__init__.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/conftest.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_cli_help.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_imports.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_reexec_kiwi.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_runtime_log_trimming.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_tokens.py +0 -0
- {kiwi_code-0.0.34 → kiwi_code-0.0.35}/tests/test_tui_headless.py +0 -0
|
@@ -235,8 +235,8 @@ class AutobotsTUI(App):
|
|
|
235
235
|
# Brand color for the kiwi cyan, kept readable on both dark and
|
|
236
236
|
# light themes. Exposed to CSS as `$brand-cyan` via
|
|
237
237
|
# `get_css_variables` below.
|
|
238
|
-
BRAND_CYAN_DARK = "#
|
|
239
|
-
BRAND_CYAN_LIGHT = "#
|
|
238
|
+
BRAND_CYAN_DARK = "#63d8dc" # softened cyan — same feel, less eye strain on dark backgrounds
|
|
239
|
+
BRAND_CYAN_LIGHT = "#0b7084" # slightly softened teal for light backgrounds
|
|
240
240
|
|
|
241
241
|
def _is_dark_theme(self) -> bool:
|
|
242
242
|
"""Best-effort detection of whether the active theme is dark."""
|
|
@@ -249,65 +249,72 @@ class AutobotsTUI(App):
|
|
|
249
249
|
return bool(getattr(self, "dark", True))
|
|
250
250
|
|
|
251
251
|
def get_css_variables(self) -> dict[str, str]:
|
|
252
|
-
"""Inject theme-aware brand color and
|
|
253
|
-
|
|
254
|
-
UX requirement: use a minimal palette (white + kiwi cyan) for UI text and
|
|
255
|
-
accents across screens.
|
|
256
|
-
"""
|
|
252
|
+
"""Inject theme-aware brand color and a softer neutral palette."""
|
|
257
253
|
variables = super().get_css_variables()
|
|
258
|
-
|
|
254
|
+
dark = self._is_dark_theme()
|
|
255
|
+
cyan = self.BRAND_CYAN_DARK if dark else self.BRAND_CYAN_LIGHT
|
|
259
256
|
variables["brand-cyan"] = cyan
|
|
260
257
|
|
|
261
|
-
|
|
262
|
-
|
|
258
|
+
if dark:
|
|
259
|
+
# Match the reference terminal theme more closely:
|
|
260
|
+
# - global background around #1E1E1E
|
|
261
|
+
# - user prompts on a lighter gray chip around #3A3A3A
|
|
262
|
+
bg = "#1E1E1E"
|
|
263
|
+
surface = "#252526"
|
|
264
|
+
raised = "#2D2D2D"
|
|
265
|
+
panel = "#333333"
|
|
266
|
+
foreground = "#F3F3F3"
|
|
267
|
+
user_msg_bg = "#3A3A3A"
|
|
268
|
+
assistant_stream_bg = "#252526"
|
|
269
|
+
else:
|
|
270
|
+
bg = "#f6f7f8"
|
|
271
|
+
surface = "#ffffff"
|
|
272
|
+
raised = "#eef1f3"
|
|
273
|
+
panel = "#dbe7ea"
|
|
274
|
+
foreground = "#101213"
|
|
275
|
+
user_msg_bg = "#f1f3f4"
|
|
276
|
+
assistant_stream_bg = "#f4f6f7"
|
|
277
|
+
|
|
278
|
+
variables["background"] = bg
|
|
263
279
|
variables["foreground"] = foreground
|
|
264
280
|
variables["text"] = foreground
|
|
265
281
|
|
|
266
|
-
#
|
|
282
|
+
# Keep the kiwi cyan for accents while softening the surrounding surfaces.
|
|
267
283
|
for k in ("primary", "secondary", "accent", "error", "warning", "success"):
|
|
268
284
|
variables[k] = cyan
|
|
269
285
|
|
|
270
|
-
# Also align text-* semantic variants used by Markdown, notifications, etc.
|
|
271
286
|
for k in ("text-warning", "text-error", "text-success"):
|
|
272
287
|
variables[k] = cyan
|
|
273
288
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
variables["surface"] = bg
|
|
277
|
-
variables["boost"] = bg
|
|
289
|
+
variables["surface"] = surface
|
|
290
|
+
variables["boost"] = raised
|
|
278
291
|
variables["primary-background"] = bg
|
|
279
|
-
variables["panel"] =
|
|
280
|
-
variables["border"] =
|
|
281
|
-
variables["
|
|
292
|
+
variables["panel"] = panel
|
|
293
|
+
variables["border"] = panel
|
|
294
|
+
variables["block-hover-background"] = surface
|
|
295
|
+
variables["border-blurred"] = raised
|
|
282
296
|
|
|
297
|
+
variables["user-msg-bg"] = user_msg_bg
|
|
298
|
+
variables["assistant-stream-bg"] = assistant_stream_bg
|
|
283
299
|
|
|
284
|
-
# Chat UX: full-width highlight color for user-message rows.
|
|
285
|
-
# Keep it subtle and theme-aware.
|
|
286
|
-
variables["user-msg-bg"] = "#333333" if self._is_dark_theme() else "#e8e8e8"
|
|
287
|
-
# Chat UX: subtle highlight for the *active streaming* assistant message.
|
|
288
|
-
variables["assistant-stream-bg"] = "#222222" if self._is_dark_theme() else "#f2f2f2"
|
|
289
|
-
# Scrollbars: cyan thumb, dark track.
|
|
290
300
|
variables["scrollbar"] = cyan
|
|
291
301
|
variables["scrollbar-hover"] = cyan
|
|
292
302
|
variables["scrollbar-active"] = cyan
|
|
293
|
-
variables["scrollbar-background"] =
|
|
294
|
-
variables["scrollbar-background-hover"] =
|
|
295
|
-
variables["scrollbar-background-active"] =
|
|
303
|
+
variables["scrollbar-background"] = surface
|
|
304
|
+
variables["scrollbar-background-hover"] = surface
|
|
305
|
+
variables["scrollbar-background-active"] = raised
|
|
296
306
|
variables["scrollbar-corner-color"] = bg
|
|
297
307
|
|
|
298
|
-
|
|
299
|
-
variables["footer-background"] = bg
|
|
308
|
+
variables["footer-background"] = surface
|
|
300
309
|
variables["footer-foreground"] = foreground
|
|
301
|
-
variables["footer-description-background"] =
|
|
310
|
+
variables["footer-description-background"] = surface
|
|
302
311
|
variables["footer-description-foreground"] = foreground
|
|
303
312
|
|
|
304
|
-
# Cursor / selection highlight: cyan text on background (no extra colors).
|
|
305
313
|
variables["block-cursor-foreground"] = cyan
|
|
306
314
|
variables["block-cursor-background"] = bg
|
|
307
315
|
variables["block-cursor-blurred-foreground"] = cyan
|
|
308
316
|
variables["block-cursor-blurred-background"] = bg
|
|
309
317
|
return variables
|
|
310
|
-
|
|
311
318
|
def watch_theme(self, theme: str) -> None:
|
|
312
319
|
"""Re-resolve palette variables whenever the user switches theme."""
|
|
313
320
|
try:
|
|
@@ -29,7 +29,7 @@ class FileBrowserScreen(ModalScreen[list[str]]):
|
|
|
29
29
|
#file-browser-container {
|
|
30
30
|
width: 96%;
|
|
31
31
|
height: 95%;
|
|
32
|
-
background: $
|
|
32
|
+
background: $primary-background;
|
|
33
33
|
border: solid $accent;
|
|
34
34
|
padding: 0 1;
|
|
35
35
|
}
|
|
@@ -75,10 +75,32 @@ class FileBrowserScreen(ModalScreen[list[str]]):
|
|
|
75
75
|
#dir-tree {
|
|
76
76
|
height: 1fr;
|
|
77
77
|
width: 100%;
|
|
78
|
+
background: $primary-background;
|
|
78
79
|
border: solid $panel;
|
|
79
80
|
scrollbar-size: 1 1;
|
|
81
|
+
#dir-tree:focus {
|
|
82
|
+
background-tint: 0%;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#dir-tree > .tree--highlight-line {
|
|
86
|
+
background: $surface;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#dir-tree > .tree--cursor {
|
|
90
|
+
background: $surface;
|
|
91
|
+
color: $foreground;
|
|
92
|
+
text-style: none;
|
|
80
93
|
}
|
|
81
94
|
|
|
95
|
+
#dir-tree:focus > .tree--cursor {
|
|
96
|
+
background: $boost;
|
|
97
|
+
color: $foreground;
|
|
98
|
+
text-style: bold;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
82
104
|
#selected-files {
|
|
83
105
|
height: auto;
|
|
84
106
|
max-height: 3;
|
|
@@ -29,7 +29,7 @@ class HelpScreen(ModalScreen[None]):
|
|
|
29
29
|
#help-container {
|
|
30
30
|
width: 96;
|
|
31
31
|
height: 80%;
|
|
32
|
-
background: $
|
|
32
|
+
background: $primary-background;
|
|
33
33
|
border: solid $accent;
|
|
34
34
|
/* Reduce top padding so the title/hint sit closer to the border. */
|
|
35
35
|
padding: 0 3 1 3;
|
|
@@ -58,7 +58,7 @@ class HelpScreen(ModalScreen[None]):
|
|
|
58
58
|
height: 1fr;
|
|
59
59
|
width: 100%;
|
|
60
60
|
border: solid $panel;
|
|
61
|
-
background: $
|
|
61
|
+
background: $primary-background;
|
|
62
62
|
scrollbar-size: 1 1;
|
|
63
63
|
/* Keep the list away from the container border for consistent margins. */
|
|
64
64
|
margin: 0 1;
|
|
@@ -101,7 +101,7 @@ class IdPickerScreen(ModalScreen[str]):
|
|
|
101
101
|
#idpicker-container {
|
|
102
102
|
width: 90;
|
|
103
103
|
height: 90%;
|
|
104
|
-
background: $
|
|
104
|
+
background: $primary-background;
|
|
105
105
|
border: solid $accent;
|
|
106
106
|
padding: 0 1;
|
|
107
107
|
}
|
|
@@ -111,7 +111,7 @@ class IdPickerScreen(ModalScreen[str]):
|
|
|
111
111
|
text-align: center;
|
|
112
112
|
text-style: bold;
|
|
113
113
|
color: $primary;
|
|
114
|
-
background: $
|
|
114
|
+
background: $primary-background;
|
|
115
115
|
height: 1;
|
|
116
116
|
margin-bottom: 0;
|
|
117
117
|
}
|
|
@@ -119,17 +119,17 @@ class IdPickerScreen(ModalScreen[str]):
|
|
|
119
119
|
#idpicker-table {
|
|
120
120
|
height: 1fr;
|
|
121
121
|
width: 100%;
|
|
122
|
-
background: $
|
|
122
|
+
background: $primary-background;
|
|
123
123
|
/* Slightly dim the row text so it's easier on the eyes. */
|
|
124
124
|
color: $foreground 80%;
|
|
125
125
|
border: none;
|
|
126
126
|
overflow-x: auto;
|
|
127
127
|
overflow-y: auto;
|
|
128
128
|
scrollbar-gutter: auto;
|
|
129
|
-
scrollbar-background: $
|
|
130
|
-
scrollbar-background-hover: $
|
|
131
|
-
scrollbar-background-active: $
|
|
132
|
-
scrollbar-corner-color: $
|
|
129
|
+
scrollbar-background: $primary-background;
|
|
130
|
+
scrollbar-background-hover: $primary-background;
|
|
131
|
+
scrollbar-background-active: $primary-background;
|
|
132
|
+
scrollbar-corner-color: $primary-background;
|
|
133
133
|
scrollbar-color: $panel;
|
|
134
134
|
scrollbar-color-hover: $primary;
|
|
135
135
|
scrollbar-color-active: $primary;
|
|
@@ -163,10 +163,10 @@ class IdPickerScreen(ModalScreen[str]):
|
|
|
163
163
|
overflow-x: auto;
|
|
164
164
|
overflow-y: auto;
|
|
165
165
|
scrollbar-gutter: auto;
|
|
166
|
-
scrollbar-background: $
|
|
167
|
-
scrollbar-background-hover: $
|
|
168
|
-
scrollbar-background-active: $
|
|
169
|
-
scrollbar-corner-color: $
|
|
166
|
+
scrollbar-background: $primary-background;
|
|
167
|
+
scrollbar-background-hover: $primary-background;
|
|
168
|
+
scrollbar-background-active: $primary-background;
|
|
169
|
+
scrollbar-corner-color: $primary-background;
|
|
170
170
|
scrollbar-color: $panel;
|
|
171
171
|
scrollbar-color-hover: $primary;
|
|
172
172
|
scrollbar-color-active: $primary;
|
|
@@ -19,6 +19,7 @@ import json
|
|
|
19
19
|
from typing import Any
|
|
20
20
|
|
|
21
21
|
from loguru import logger
|
|
22
|
+
from rich.text import Text
|
|
22
23
|
from textual import events
|
|
23
24
|
from textual.binding import Binding
|
|
24
25
|
from textual.screen import ModalScreen
|
|
@@ -121,13 +122,29 @@ class RuntimeCleanupScreen(ModalScreen[list[int]]):
|
|
|
121
122
|
|
|
122
123
|
#runtime-cleanup-help {
|
|
123
124
|
padding: 1 2;
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
background: $background;
|
|
126
|
+
color: $brand-cyan;
|
|
127
|
+
text-style: bold;
|
|
128
|
+
opacity: 1;
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
#runtime-list {
|
|
129
132
|
height: 1fr;
|
|
130
133
|
width: 100%;
|
|
134
|
+
background: $background;
|
|
135
|
+
color: $foreground;
|
|
136
|
+
border: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#runtime-list > .option-list--option {
|
|
140
|
+
background: $background;
|
|
141
|
+
color: $foreground;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#runtime-list > .option-list--option-highlighted {
|
|
145
|
+
background: $panel;
|
|
146
|
+
color: $brand-cyan;
|
|
147
|
+
text-style: bold;
|
|
131
148
|
}
|
|
132
149
|
"""
|
|
133
150
|
|
|
@@ -139,8 +156,8 @@ class RuntimeCleanupScreen(ModalScreen[list[int]]):
|
|
|
139
156
|
def compose(self):
|
|
140
157
|
yield Header(icon="❊")
|
|
141
158
|
yield Static(
|
|
142
|
-
"
|
|
143
|
-
"Space
|
|
159
|
+
"Interactive runtime cleanup\n"
|
|
160
|
+
"Use ↑/↓ to move, Space to toggle kill, Enter to confirm & exit, Esc to keep all.",
|
|
144
161
|
id="runtime-cleanup-help",
|
|
145
162
|
)
|
|
146
163
|
yield RuntimeCleanupList(id="runtime-list")
|
|
@@ -164,12 +181,19 @@ class RuntimeCleanupScreen(ModalScreen[list[int]]):
|
|
|
164
181
|
def _option_id_for_row(self, r: RuntimeRow) -> str:
|
|
165
182
|
return f"{r.kind}:{r.runtime_id}:{r.pid}"
|
|
166
183
|
|
|
167
|
-
def _format_row(self, r: RuntimeRow) ->
|
|
184
|
+
def _format_row(self, r: RuntimeRow) -> Text:
|
|
168
185
|
kill = "YES" if r.kill else "NO"
|
|
169
186
|
# Note: kinds come from runtime_agent.list_known_runtimes(): "by-run" or "pending".
|
|
170
187
|
name = r.name or ("(pending)" if r.kind == "pending" else "(unknown)")
|
|
171
|
-
|
|
172
|
-
|
|
188
|
+
row = Text()
|
|
189
|
+
try:
|
|
190
|
+
cyan = self.app.get_css_variables().get("brand-cyan", "#63d8dc")
|
|
191
|
+
except Exception:
|
|
192
|
+
cyan = "#63d8dc"
|
|
193
|
+
row.append(f"Kill={kill}", style=f"bold {cyan}")
|
|
194
|
+
row.append(f" {name}", style="bold")
|
|
195
|
+
row.append(f" | {r.runtime_id} | pid {r.pid} | {r.kind}")
|
|
196
|
+
return row
|
|
173
197
|
|
|
174
198
|
def _selected_id(self) -> str | None:
|
|
175
199
|
lst = self.query_one("#runtime-list", RuntimeCleanupList)
|
|
@@ -63,14 +63,34 @@ class RuntimeLogsScreen(Screen):
|
|
|
63
63
|
background: $background;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
RichLog {
|
|
67
|
+
background: $background;
|
|
68
|
+
color: $foreground;
|
|
69
|
+
background-tint: 0%;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
RichLog:focus {
|
|
73
|
+
background: $background;
|
|
74
|
+
color: $foreground;
|
|
75
|
+
background-tint: 0%;
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
#runtime-log {
|
|
67
79
|
height: 1fr;
|
|
68
80
|
width: 100%;
|
|
81
|
+
background: $background;
|
|
82
|
+
color: $foreground;
|
|
83
|
+
background-tint: 0%;
|
|
69
84
|
scrollbar-size: 1 1;
|
|
85
|
+
scrollbar-background: $background;
|
|
86
|
+
scrollbar-background-hover: $background;
|
|
87
|
+
scrollbar-background-active: $background;
|
|
88
|
+
scrollbar-corner-color: $background;
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
#runtime-log-missing {
|
|
73
92
|
padding: 2 4;
|
|
93
|
+
background: $background;
|
|
74
94
|
color: $error;
|
|
75
95
|
}
|
|
76
96
|
"""
|
|
@@ -109,6 +129,14 @@ class RuntimeLogsScreen(Screen):
|
|
|
109
129
|
except Exception:
|
|
110
130
|
return
|
|
111
131
|
|
|
132
|
+
try:
|
|
133
|
+
bg = self.app.get_css_variables().get("background", "#1E1E1E")
|
|
134
|
+
fg = self.app.get_css_variables().get("foreground", "#F3F3F3")
|
|
135
|
+
log.styles.background = bg
|
|
136
|
+
log.styles.color = fg
|
|
137
|
+
except Exception:
|
|
138
|
+
pass
|
|
139
|
+
|
|
112
140
|
for line in _tail_lines(self._log_path, max_lines=2000):
|
|
113
141
|
log.write(Text.from_ansi(line))
|
|
114
142
|
|
|
@@ -35,7 +35,7 @@ class SlashPickerScreen(ModalScreen[str]):
|
|
|
35
35
|
#slash-container {
|
|
36
36
|
width: 70;
|
|
37
37
|
height: 80%;
|
|
38
|
-
background: $
|
|
38
|
+
background: $primary-background;
|
|
39
39
|
border: solid $accent;
|
|
40
40
|
padding: 1 2;
|
|
41
41
|
}
|
|
@@ -53,6 +53,7 @@ class SlashPickerScreen(ModalScreen[str]):
|
|
|
53
53
|
height: 1fr;
|
|
54
54
|
width: 100%;
|
|
55
55
|
border: solid $panel;
|
|
56
|
+
background: $primary-background;
|
|
56
57
|
}
|
|
57
58
|
"""
|
|
58
59
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from textual.css.stylesheet import Stylesheet
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from kiwi_tui.main import AutobotsTUI
|
|
5
|
+
from kiwi_tui.screens.attach_content import AttachContentScreen
|
|
6
|
+
from kiwi_tui.screens.command_result import CommandResultScreen
|
|
7
|
+
from kiwi_tui.screens.file_browser import FileBrowserScreen
|
|
8
|
+
from kiwi_tui.screens.help import HelpScreen
|
|
9
|
+
from kiwi_tui.screens.id_picker import IdPickerScreen
|
|
10
|
+
from kiwi_tui.screens.slash_picker import SlashPickerScreen
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_tui_dark_palette_vars(isolated_home: Path, monkeypatch) -> None:
|
|
14
|
+
app = AutobotsTUI()
|
|
15
|
+
monkeypatch.setattr(app, "_is_dark_theme", lambda: True)
|
|
16
|
+
|
|
17
|
+
variables = app.get_css_variables()
|
|
18
|
+
|
|
19
|
+
assert variables["background"] == "#1E1E1E"
|
|
20
|
+
assert variables["surface"] == "#252526"
|
|
21
|
+
assert variables["boost"] == "#2D2D2D"
|
|
22
|
+
assert variables["panel"] == "#333333"
|
|
23
|
+
assert variables["foreground"] == "#F3F3F3"
|
|
24
|
+
assert variables["user-msg-bg"] == "#3A3A3A"
|
|
25
|
+
assert variables["assistant-stream-bg"] == "#252526"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_tui_light_palette_vars(isolated_home: Path, monkeypatch) -> None:
|
|
29
|
+
app = AutobotsTUI()
|
|
30
|
+
monkeypatch.setattr(app, "_is_dark_theme", lambda: False)
|
|
31
|
+
|
|
32
|
+
variables = app.get_css_variables()
|
|
33
|
+
|
|
34
|
+
assert variables["background"] == "#f6f7f8"
|
|
35
|
+
assert variables["surface"] == "#ffffff"
|
|
36
|
+
assert variables["boost"] == "#eef1f3"
|
|
37
|
+
assert variables["panel"] == "#dbe7ea"
|
|
38
|
+
assert variables["foreground"] == "#101213"
|
|
39
|
+
assert variables["user-msg-bg"] == "#f1f3f4"
|
|
40
|
+
assert variables["assistant-stream-bg"] == "#f4f6f7"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_slash_related_modals_use_primary_background() -> None:
|
|
44
|
+
css_blocks = {
|
|
45
|
+
"slash_picker": SlashPickerScreen.CSS,
|
|
46
|
+
"help": HelpScreen.CSS,
|
|
47
|
+
"id_picker": IdPickerScreen.CSS,
|
|
48
|
+
"command_result": CommandResultScreen.CSS,
|
|
49
|
+
"attach_content": AttachContentScreen.CSS,
|
|
50
|
+
"file_browser": FileBrowserScreen.CSS,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
for name, css in css_blocks.items():
|
|
54
|
+
assert "$primary-background" in css, f"{name} should use the shared modal background"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_file_browser_css_parses(isolated_home: Path) -> None:
|
|
58
|
+
app = AutobotsTUI()
|
|
59
|
+
sheet = Stylesheet(variables=app.get_css_variables())
|
|
60
|
+
sheet.add_source(FileBrowserScreen.CSS, read_from=("file_browser.py", "FileBrowserScreen.CSS"))
|
|
61
|
+
sheet.parse()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_file_browser_tree_hover_styling_is_softened() -> None:
|
|
65
|
+
css = FileBrowserScreen.CSS
|
|
66
|
+
assert "#dir-tree > .tree--highlight-line" in css
|
|
67
|
+
assert "#dir-tree > .tree--cursor" in css
|
|
68
|
+
assert "background-tint: 0%" in css
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|