klaude-code 1.2.23__py3-none-any.whl → 1.2.24__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.
@@ -5,14 +5,13 @@ from contextlib import contextmanager
5
5
  from dataclasses import dataclass
6
6
  from typing import Any
7
7
 
8
- from rich import box
9
- from rich.box import Box
10
8
  from rich.console import Console
11
9
  from rich.spinner import Spinner
12
10
  from rich.status import Status
13
11
  from rich.style import Style, StyleType
14
12
  from rich.text import Text
15
13
 
14
+ from klaude_code import const
16
15
  from klaude_code.protocol import events, model
17
16
  from klaude_code.ui.renderers import assistant as r_assistant
18
17
  from klaude_code.ui.renderers import developer as r_developer
@@ -32,6 +31,7 @@ from klaude_code.ui.rich.theme import ThemeKey, get_theme
32
31
  @dataclass
33
32
  class SessionStatus:
34
33
  color: Style | None = None
34
+ color_index: int | None = None
35
35
  sub_agent_state: model.SubAgentState | None = None
36
36
 
37
37
 
@@ -43,9 +43,9 @@ class REPLRenderer:
43
43
  self.console: Console = Console(theme=self.themes.app_theme)
44
44
  self.console.push_theme(self.themes.markdown_theme)
45
45
  self._spinner: Status = self.console.status(
46
- ShimmerStatusText("Thinking …", ThemeKey.SPINNER_STATUS_TEXT),
46
+ ShimmerStatusText(const.STATUS_DEFAULT_TEXT),
47
47
  spinner=r_status.spinner_name(),
48
- spinner_style=ThemeKey.SPINNER_STATUS,
48
+ spinner_style=ThemeKey.STATUS_SPINNER,
49
49
  )
50
50
 
51
51
  self.session_map: dict[str, SessionStatus] = {}
@@ -57,7 +57,9 @@ class REPLRenderer:
57
57
  sub_agent_state=sub_agent_state,
58
58
  )
59
59
  if sub_agent_state is not None:
60
- session_status.color = self.pick_sub_agent_color()
60
+ color, color_index = self.pick_sub_agent_color()
61
+ session_status.color = color
62
+ session_status.color_index = color_index
61
63
  self.session_map[session_id] = session_status
62
64
 
63
65
  def is_sub_agent_session(self, session_id: str) -> bool:
@@ -70,12 +72,12 @@ class REPLRenderer:
70
72
  return
71
73
  self.sub_agent_color_index = (self.sub_agent_color_index + 1) % palette_size
72
74
 
73
- def pick_sub_agent_color(self) -> Style:
75
+ def pick_sub_agent_color(self) -> tuple[Style, int]:
74
76
  self._advance_sub_agent_color_index()
75
77
  palette = self.themes.sub_agent_colors
76
78
  if not palette:
77
- return Style()
78
- return palette[self.sub_agent_color_index]
79
+ return Style(), 0
80
+ return palette[self.sub_agent_color_index], self.sub_agent_color_index
79
81
 
80
82
  def get_session_sub_agent_color(self, session_id: str) -> Style:
81
83
  status = self.session_map.get(session_id)
@@ -83,8 +85,12 @@ class REPLRenderer:
83
85
  return status.color
84
86
  return Style()
85
87
 
86
- def box_style(self) -> Box:
87
- return box.ROUNDED
88
+ def get_session_sub_agent_background(self, session_id: str) -> Style:
89
+ status = self.session_map.get(session_id)
90
+ backgrounds = self.themes.sub_agent_backgrounds
91
+ if status and status.color_index is not None and backgrounds:
92
+ return backgrounds[status.color_index]
93
+ return Style()
88
94
 
89
95
  @contextmanager
90
96
  def session_print_context(self, session_id: str) -> Iterator[None]:
@@ -114,7 +120,7 @@ class REPLRenderer:
114
120
  def display_tool_call_result(self, e: events.ToolResultEvent) -> None:
115
121
  if r_tools.is_sub_agent_tool(e.tool_name):
116
122
  return
117
- renderable = r_tools.render_tool_result(e)
123
+ renderable = r_tools.render_tool_result(e, code_theme=self.themes.code_theme)
118
124
  if renderable is not None:
119
125
  self.print(renderable)
120
126
 
@@ -152,7 +158,6 @@ class REPLRenderer:
152
158
  case events.ThinkingEvent() as e:
153
159
  if is_sub_agent:
154
160
  continue
155
- self.display_thinking_prefix()
156
161
  self.display_thinking(e.content)
157
162
  case events.DeveloperMessageEvent() as e:
158
163
  self.display_developer_message(e)
@@ -196,7 +201,7 @@ class REPLRenderer:
196
201
  self.print()
197
202
 
198
203
  def display_welcome(self, event: events.WelcomeEvent) -> None:
199
- self.print(r_metadata.render_welcome(event, box_style=self.box_style()))
204
+ self.print(r_metadata.render_welcome(event))
200
205
 
201
206
  def display_user_message(self, event: events.UserMessageEvent) -> None:
202
207
  self.print(r_user_input.render_user_input(event.content))
@@ -229,12 +234,17 @@ class REPLRenderer:
229
234
 
230
235
  def display_task_finish(self, event: events.TaskFinishEvent) -> None:
231
236
  if self.is_sub_agent_session(event.session_id):
237
+ session_status = self.session_map.get(event.session_id)
238
+ description = session_status.sub_agent_state.sub_agent_desc if session_status and session_status.sub_agent_state else None
239
+ panel_style = self.get_session_sub_agent_background(event.session_id)
232
240
  with self.session_print_context(event.session_id):
233
241
  self.print(
234
242
  r_sub_agent.render_sub_agent_result(
235
243
  event.task_result,
236
244
  code_theme=self.themes.code_theme,
237
245
  has_structured_output=event.has_structured_output,
246
+ description=description,
247
+ panel_style=panel_style,
238
248
  )
239
249
  )
240
250
 
@@ -249,9 +259,6 @@ class REPLRenderer:
249
259
  )
250
260
  )
251
261
 
252
- def display_thinking_prefix(self) -> None:
253
- self.print(r_thinking.thinking_prefix())
254
-
255
262
  # -------------------------------------------------------------------------
256
263
  # Spinner control methods
257
264
  # -------------------------------------------------------------------------
@@ -266,7 +273,7 @@ class REPLRenderer:
266
273
 
267
274
  def spinner_update(self, status_text: str | Text, right_text: Text | None = None) -> None:
268
275
  """Update the spinner status text with optional right-aligned text."""
269
- self._spinner.update(ShimmerStatusText(status_text, ThemeKey.SPINNER_STATUS_TEXT, right_text))
276
+ self._spinner.update(ShimmerStatusText(status_text, right_text))
270
277
 
271
278
  def spinner_renderable(self) -> Spinner:
272
279
  """Return the spinner's renderable for embedding in other components."""
@@ -6,7 +6,7 @@ from klaude_code.ui.renderers.common import create_grid
6
6
  from klaude_code.ui.rich.markdown import NoInsetMarkdown
7
7
 
8
8
  # UI markers
9
- ASSISTANT_MESSAGE_MARK = ""
9
+ ASSISTANT_MESSAGE_MARK = ""
10
10
 
11
11
 
12
12
  def render_assistant_message(content: str, *, code_theme: str) -> RenderableType | None:
@@ -1,7 +1,6 @@
1
1
  from importlib.metadata import version
2
2
 
3
3
  from rich import box
4
- from rich.box import Box
5
4
  from rich.console import Group, RenderableType
6
5
  from rich.padding import Padding
7
6
  from rich.panel import Panel
@@ -165,11 +164,8 @@ def render_task_metadata(e: events.TaskMetadataEvent) -> RenderableType:
165
164
  return Group(*renderables)
166
165
 
167
166
 
168
- def render_welcome(e: events.WelcomeEvent, *, box_style: Box | None = None) -> RenderableType:
167
+ def render_welcome(e: events.WelcomeEvent) -> RenderableType:
169
168
  """Render the welcome panel with model info and settings."""
170
- if box_style is None:
171
- box_style = box.ROUNDED
172
-
173
169
  debug_mode = is_debug_enabled()
174
170
 
175
171
  # First line: Klaude Code version
@@ -219,6 +215,6 @@ def render_welcome(e: events.WelcomeEvent, *, box_style: Box | None = None) -> R
219
215
 
220
216
  border_style = ThemeKey.WELCOME_DEBUG_BORDER if debug_mode else ThemeKey.LINES
221
217
  return Group(
222
- Panel.fit(panel_content, border_style=border_style, box=box_style),
218
+ Panel.fit(panel_content, border_style=border_style, box=box.ROUNDED),
223
219
  "", # empty line
224
220
  )
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  from typing import Any, cast
3
3
 
4
+ from rich import box
4
5
  from rich.console import Group, RenderableType
5
6
  from rich.json import JSON
6
7
  from rich.panel import Panel
@@ -58,10 +59,22 @@ def render_sub_agent_call(e: model.SubAgentState, style: Style | None = None) ->
58
59
 
59
60
 
60
61
  def render_sub_agent_result(
61
- result: str, *, code_theme: str, style: Style | None = None, has_structured_output: bool = False
62
+ result: str,
63
+ *,
64
+ code_theme: str,
65
+ style: Style | None = None,
66
+ has_structured_output: bool = False,
67
+ description: str | None = None,
68
+ panel_style: Style | None = None,
62
69
  ) -> RenderableType:
63
70
  stripped_result = result.strip()
64
71
 
72
+ # Add markdown heading if description is provided
73
+ if description:
74
+ stripped_result = f"# {description}\n\n{stripped_result}"
75
+
76
+ result_panel_style = panel_style or ThemeKey.SUB_AGENT_RESULT_PANEL
77
+
65
78
  # Use rich JSON for structured output
66
79
  if has_structured_output:
67
80
  try:
@@ -73,7 +86,9 @@ def render_sub_agent_result(
73
86
  ),
74
87
  JSON(stripped_result),
75
88
  ),
89
+ box=box.SIMPLE,
76
90
  border_style=ThemeKey.LINES,
91
+ style=result_panel_style,
77
92
  )
78
93
  except json.JSONDecodeError:
79
94
  # Fall back to markdown if not valid JSON
@@ -82,20 +97,28 @@ def render_sub_agent_result(
82
97
  lines = stripped_result.splitlines()
83
98
  if len(lines) > const.SUB_AGENT_RESULT_MAX_LINES:
84
99
  hidden_count = len(lines) - const.SUB_AGENT_RESULT_MAX_LINES
85
- truncated_text = "\n".join(lines[-const.SUB_AGENT_RESULT_MAX_LINES :])
100
+ head_count = const.SUB_AGENT_RESULT_MAX_LINES // 2
101
+ tail_count = const.SUB_AGENT_RESULT_MAX_LINES - head_count
102
+ head_text = "\n".join(lines[:head_count])
103
+ tail_text = "\n".join(lines[-tail_count:])
86
104
  return Panel.fit(
87
105
  Group(
106
+ NoInsetMarkdown(head_text, code_theme=code_theme, style=style or ""),
88
107
  Text(
89
- f"… more {hidden_count} lines — use /export to view full output",
90
- style=ThemeKey.TOOL_RESULT,
108
+ f"\n… more {hidden_count} lines — use /export to view full output\n",
109
+ style=ThemeKey.TOOL_RESULT_TRUNCATED,
91
110
  ),
92
- NoInsetMarkdown(truncated_text, code_theme=code_theme, style=style or ""),
111
+ NoInsetMarkdown(tail_text, code_theme=code_theme, style=style or ""),
93
112
  ),
113
+ box=box.SIMPLE,
94
114
  border_style=ThemeKey.LINES,
115
+ style=result_panel_style,
95
116
  )
96
117
  return Panel.fit(
97
118
  NoInsetMarkdown(stripped_result, code_theme=code_theme),
119
+ box=box.SIMPLE,
98
120
  border_style=ThemeKey.LINES,
121
+ style=result_panel_style,
99
122
  )
100
123
 
101
124
 
@@ -4,12 +4,13 @@ from rich.console import RenderableType
4
4
  from rich.padding import Padding
5
5
  from rich.text import Text
6
6
 
7
+ from klaude_code import const
8
+ from klaude_code.ui.renderers.common import create_grid
7
9
  from klaude_code.ui.rich.markdown import ThinkingMarkdown
8
10
  from klaude_code.ui.rich.theme import ThemeKey
9
11
 
10
-
11
- def thinking_prefix() -> Text:
12
- return Text.from_markup("[not italic]⸫[/not italic] Thinking …", style=ThemeKey.THINKING_BOLD)
12
+ # UI markers
13
+ THINKING_MESSAGE_MARK = "⠶"
13
14
 
14
15
 
15
16
  def normalize_thinking_content(content: str) -> str:
@@ -37,7 +38,7 @@ def normalize_thinking_content(content: str) -> str:
37
38
 
38
39
 
39
40
  def render_thinking(content: str, *, code_theme: str, style: str) -> RenderableType | None:
40
- """Render thinking content as indented markdown.
41
+ """Render thinking content as markdown with left mark.
41
42
 
42
43
  Returns None if content is empty.
43
44
  Note: Caller should push thinking_markdown_theme before printing.
@@ -45,11 +46,16 @@ def render_thinking(content: str, *, code_theme: str, style: str) -> RenderableT
45
46
  if len(content.strip()) == 0:
46
47
  return None
47
48
 
48
- return Padding.indent(
49
- ThinkingMarkdown(
50
- normalize_thinking_content(content),
51
- code_theme=code_theme,
52
- style=style,
49
+ grid = create_grid()
50
+ grid.add_row(
51
+ Text(THINKING_MESSAGE_MARK, style=ThemeKey.THINKING),
52
+ Padding(
53
+ ThinkingMarkdown(
54
+ normalize_thinking_content(content),
55
+ code_theme=code_theme,
56
+ style=style,
57
+ ),
58
+ (0, const.MARKDOWN_RIGHT_MARGIN, 0, 0),
53
59
  ),
54
- level=2,
55
60
  )
61
+ return grid
@@ -2,8 +2,10 @@ import json
2
2
  from pathlib import Path
3
3
  from typing import Any, cast
4
4
 
5
+ from rich import box
5
6
  from rich.console import Group, RenderableType
6
7
  from rich.padding import Padding
8
+ from rich.panel import Panel
7
9
  from rich.text import Text
8
10
 
9
11
  from klaude_code import const
@@ -11,6 +13,7 @@ from klaude_code.protocol import events, model, tools
11
13
  from klaude_code.protocol.sub_agent import is_sub_agent_tool as _is_sub_agent_tool
12
14
  from klaude_code.ui.renderers import diffs as r_diffs
13
15
  from klaude_code.ui.renderers.common import create_grid, truncate_display
16
+ from klaude_code.ui.rich.markdown import NoInsetMarkdown
14
17
  from klaude_code.ui.rich.theme import ThemeKey
15
18
 
16
19
  # Tool markers (Unicode symbols for UI display)
@@ -528,7 +531,23 @@ def _extract_diff(ui_extra: model.ToolResultUIExtra | None) -> model.DiffUIExtra
528
531
  return None
529
532
 
530
533
 
531
- def render_tool_result(e: events.ToolResultEvent) -> RenderableType | None:
534
+ def _extract_markdown_doc(ui_extra: model.ToolResultUIExtra | None) -> model.MarkdownDocUIExtra | None:
535
+ if isinstance(ui_extra, model.MarkdownDocUIExtra):
536
+ return ui_extra
537
+ return None
538
+
539
+
540
+ def render_markdown_doc(md_ui: model.MarkdownDocUIExtra, *, code_theme: str) -> RenderableType:
541
+ """Render markdown document content in a panel."""
542
+ return Panel.fit(
543
+ NoInsetMarkdown(md_ui.content, code_theme=code_theme),
544
+ box=box.SIMPLE,
545
+ border_style=ThemeKey.LINES,
546
+ style=ThemeKey.WRITE_MARKDOWN_PANEL,
547
+ )
548
+
549
+
550
+ def render_tool_result(e: events.ToolResultEvent, *, code_theme: str = "monokai") -> RenderableType | None:
532
551
  """Unified entry point for rendering tool results.
533
552
 
534
553
  Returns a Rich Renderable or None if the tool result should not be rendered.
@@ -549,11 +568,16 @@ def render_tool_result(e: events.ToolResultEvent) -> RenderableType | None:
549
568
  return Group(render_truncation_info(truncation_info), render_generic_tool_result(e.result))
550
569
 
551
570
  diff_ui = _extract_diff(e.ui_extra)
571
+ md_ui = _extract_markdown_doc(e.ui_extra)
552
572
 
553
573
  match e.tool_name:
554
574
  case tools.READ:
555
575
  return None
556
- case tools.EDIT | tools.WRITE:
576
+ case tools.EDIT:
577
+ return Padding.indent(r_diffs.render_structured_diff(diff_ui) if diff_ui else Text(""), level=2)
578
+ case tools.WRITE:
579
+ if md_ui:
580
+ return Padding.indent(render_markdown_doc(md_ui, code_theme=code_theme), level=2)
557
581
  return Padding.indent(r_diffs.render_structured_diff(diff_ui) if diff_ui else Text(""), level=2)
558
582
  case tools.APPLY_PATCH:
559
583
  if diff_ui:
@@ -12,7 +12,7 @@ from rich.live import Live
12
12
  from rich.markdown import CodeBlock, Heading, Markdown, MarkdownElement
13
13
  from rich.rule import Rule
14
14
  from rich.spinner import Spinner
15
- from rich.style import Style
15
+ from rich.style import Style, StyleType
16
16
  from rich.syntax import Syntax
17
17
  from rich.text import Text
18
18
  from rich.theme import Theme
@@ -64,7 +64,7 @@ class LeftHeading(Heading):
64
64
  yield h1_text
65
65
  elif self.tag == "h2":
66
66
  text.stylize(Style(bold=True, underline=False))
67
- yield Rule(title=text, characters="-", style="markdown.h2.border", align="left")
67
+ yield Rule(title=text, characters="·", style="markdown.h2.border", align="left")
68
68
  else:
69
69
  yield text
70
70
 
@@ -108,6 +108,7 @@ class MarkdownStream:
108
108
  console: Console | None = None,
109
109
  spinner: Spinner | None = None,
110
110
  mark: str | None = None,
111
+ mark_style: StyleType | None = None,
111
112
  left_margin: int = 0,
112
113
  right_margin: int = const.MARKDOWN_RIGHT_MARGIN,
113
114
  markdown_class: Callable[..., Markdown] | None = None,
@@ -119,6 +120,7 @@ class MarkdownStream:
119
120
  theme (Theme, optional): Theme for rendering markdown
120
121
  console (Console, optional): External console to use for rendering
121
122
  mark (str | None, optional): Marker shown before the first non-empty line when left_margin >= 2
123
+ mark_style (StyleType | None, optional): Style to apply to the mark
122
124
  left_margin (int, optional): Number of columns to reserve on the left side
123
125
  right_margin (int, optional): Number of columns to reserve on the right side
124
126
  markdown_class: Markdown class to use for rendering (defaults to NoInsetMarkdown)
@@ -142,6 +144,7 @@ class MarkdownStream:
142
144
  self.console = console
143
145
  self.spinner: Spinner | None = spinner
144
146
  self.mark: str | None = mark
147
+ self.mark_style: StyleType | None = mark_style
145
148
 
146
149
  self.left_margin: int = max(left_margin, 0)
147
150
 
@@ -194,12 +197,24 @@ class MarkdownStream:
194
197
  mark_applied = False
195
198
  use_mark = bool(self.mark) and self.left_margin >= 2
196
199
 
200
+ # Pre-render styled mark if needed
201
+ styled_mark: str | None = None
202
+ if use_mark and self.mark:
203
+ if self.mark_style:
204
+ mark_text = Text(self.mark, style=self.mark_style)
205
+ mark_buffer = io.StringIO()
206
+ mark_console = Console(file=mark_buffer, force_terminal=True, theme=self.theme)
207
+ mark_console.print(mark_text, end="")
208
+ styled_mark = mark_buffer.getvalue()
209
+ else:
210
+ styled_mark = self.mark
211
+
197
212
  for line in lines:
198
213
  stripped = line.rstrip()
199
214
 
200
215
  # Apply mark to the first non-empty line only when left_margin is at least 2.
201
216
  if use_mark and not mark_applied and stripped:
202
- stripped = f"{self.mark} {stripped}"
217
+ stripped = f"{styled_mark} {stripped}"
203
218
  mark_applied = True
204
219
  elif indent_prefix:
205
220
  stripped = indent_prefix + stripped
@@ -169,9 +169,19 @@ class ShimmerStatusText:
169
169
  Supports optional right-aligned text that stays fixed at the right edge.
170
170
  """
171
171
 
172
- def __init__(self, main_text: str | Text, main_style: ThemeKey, right_text: Text | None = None) -> None:
173
- self._main_text = main_text if isinstance(main_text, Text) else Text(main_text)
174
- self._main_style = main_style
172
+ def __init__(
173
+ self,
174
+ main_text: str | Text,
175
+ right_text: Text | None = None,
176
+ main_style: ThemeKey = ThemeKey.STATUS_TEXT,
177
+ ) -> None:
178
+ if isinstance(main_text, Text):
179
+ text = main_text.copy()
180
+ if not text.style:
181
+ text.style = str(main_style)
182
+ self._main_text = text
183
+ else:
184
+ self._main_text = Text(main_text, style=main_style)
175
185
  self._hint_text = Text(const.STATUS_HINT_TEXT)
176
186
  self._hint_style = ThemeKey.STATUS_HINT
177
187
  self._right_text = right_text
@@ -193,13 +203,11 @@ class ShimmerStatusText:
193
203
  def _render_left_text(self, console: Console) -> Text:
194
204
  """Render the left part with shimmer effect on main text only."""
195
205
  result = Text()
196
- main_style = console.get_style(str(self._main_style))
197
206
  hint_style = console.get_style(str(self._hint_style))
198
207
 
199
208
  # Apply shimmer only to main text
200
209
  for index, (ch, intensity) in enumerate(_shimmer_profile(self._main_text.plain)):
201
- char_style = self._main_text.get_style_at_offset(console, index)
202
- base_style = main_style + char_style
210
+ base_style = self._main_text.get_style_at_offset(console, index)
203
211
  style = _shimmer_style(console, base_style, intensity)
204
212
  result.append(ch, style=style)
205
213
 
@@ -25,7 +25,18 @@ class Palette:
25
25
  diff_remove: str
26
26
  diff_remove_char: str
27
27
  code_theme: str
28
- text_background: str
28
+ code_background: str
29
+ green_background: str
30
+ blue_grey_background: str
31
+ # Sub-agent backgrounds (corresponding to sub_agent_colors order)
32
+ cyan_background: str
33
+ green_sub_background: str
34
+ blue_sub_background: str
35
+ purple_background: str
36
+ orange_background: str
37
+ red_background: str
38
+ grey_background: str
39
+ yellow_background: str
29
40
 
30
41
 
31
42
  LIGHT_PALETTE = Palette(
@@ -47,7 +58,17 @@ LIGHT_PALETTE = Palette(
47
58
  diff_remove="#82071e on #ffecec",
48
59
  diff_remove_char="#82071e on #ffcfcf",
49
60
  code_theme="ansi_light",
50
- text_background="#e0e0e0",
61
+ code_background="#e0e0e0",
62
+ green_background="#e8f1e9",
63
+ blue_grey_background="#e8e9f1",
64
+ cyan_background="#e0f0f0",
65
+ green_sub_background="#e0f0e0",
66
+ blue_sub_background="#e0e8f5",
67
+ purple_background="#ede0f5",
68
+ orange_background="#f5ebe0",
69
+ red_background="#f5e0e0",
70
+ grey_background="#e8e8e8",
71
+ yellow_background="#f5f5e0",
51
72
  )
52
73
 
53
74
  DARK_PALETTE = Palette(
@@ -69,12 +90,26 @@ DARK_PALETTE = Palette(
69
90
  diff_remove="#ffcdd2 on #3d1f23",
70
91
  diff_remove_char="#ffcdd2 on #7a3a42",
71
92
  code_theme="ansi_dark",
72
- text_background="#2f3440",
93
+ code_background="#2f3440",
94
+ green_background="#23342c",
95
+ blue_grey_background="#313848",
96
+ cyan_background="#1a3333",
97
+ green_sub_background="#1b3928",
98
+ blue_sub_background="#1a2a3d",
99
+ purple_background="#2a2640",
100
+ orange_background="#3d2a1a",
101
+ red_background="#3d1f23",
102
+ grey_background="#2a2d30",
103
+ yellow_background="#3d3a1a",
73
104
  )
74
105
 
75
106
 
76
107
  class ThemeKey(str, Enum):
77
108
  LINES = "lines"
109
+
110
+ # PANEL
111
+ SUB_AGENT_RESULT_PANEL = "panel.sub_agent_result"
112
+ WRITE_MARKDOWN_PANEL = "panel.write_markdown"
78
113
  # DIFF
79
114
  DIFF_FILE_NAME = "diff.file_name"
80
115
  DIFF_REMOVE = "diff.remove"
@@ -92,9 +127,9 @@ class ThemeKey(str, Enum):
92
127
  METADATA_DIM = "metadata.dim"
93
128
  METADATA_BOLD = "metadata.bold"
94
129
  # SPINNER_STATUS
95
- SPINNER_STATUS = "spinner.status"
96
- SPINNER_STATUS_TEXT = "spinner.status.text"
97
- SPINNER_STATUS_TEXT_BOLD = "spinner.status.text.bold"
130
+ STATUS_SPINNER = "spinner.status"
131
+ STATUS_TEXT = "spinner.status.text"
132
+ STATUS_TEXT_BOLD = "spinner.status.text.bold"
98
133
  # STATUS
99
134
  STATUS_HINT = "status.hint"
100
135
  # USER_INPUT
@@ -162,6 +197,7 @@ class Themes:
162
197
  thinking_markdown_theme: Theme
163
198
  code_theme: str
164
199
  sub_agent_colors: list[Style]
200
+ sub_agent_backgrounds: list[Style]
165
201
 
166
202
 
167
203
  def get_theme(theme: str | None = None) -> Themes:
@@ -170,6 +206,9 @@ def get_theme(theme: str | None = None) -> Themes:
170
206
  app_theme=Theme(
171
207
  styles={
172
208
  ThemeKey.LINES.value: palette.grey3,
209
+ # PANEL
210
+ ThemeKey.SUB_AGENT_RESULT_PANEL.value: f"on {palette.blue_grey_background}",
211
+ ThemeKey.WRITE_MARKDOWN_PANEL.value: f"on {palette.green_background}",
173
212
  # DIFF
174
213
  ThemeKey.DIFF_FILE_NAME.value: palette.blue,
175
214
  ThemeKey.DIFF_REMOVE.value: palette.diff_remove,
@@ -183,7 +222,7 @@ def get_theme(theme: str | None = None) -> Themes:
183
222
  ThemeKey.ERROR_BOLD.value: "bold " + palette.red,
184
223
  ThemeKey.INTERRUPT.value: "reverse bold " + palette.red,
185
224
  # USER_INPUT
186
- ThemeKey.USER_INPUT.value: palette.magenta,
225
+ ThemeKey.USER_INPUT.value: "bold " + palette.magenta,
187
226
  ThemeKey.USER_INPUT_PROMPT.value: "bold " + palette.magenta,
188
227
  ThemeKey.USER_INPUT_AT_PATTERN.value: palette.purple,
189
228
  ThemeKey.USER_INPUT_SLASH_COMMAND.value: "bold reverse " + palette.blue,
@@ -192,11 +231,10 @@ def get_theme(theme: str | None = None) -> Themes:
192
231
  ThemeKey.METADATA.value: palette.lavender,
193
232
  ThemeKey.METADATA_DIM.value: "dim " + palette.lavender,
194
233
  ThemeKey.METADATA_BOLD.value: "bold " + palette.lavender,
195
- # SPINNER_STATUS
196
- ThemeKey.SPINNER_STATUS.value: palette.blue,
197
- ThemeKey.SPINNER_STATUS_TEXT.value: palette.blue,
198
- ThemeKey.SPINNER_STATUS_TEXT_BOLD.value: "bold " + palette.blue,
199
234
  # STATUS
235
+ ThemeKey.STATUS_SPINNER.value: palette.blue,
236
+ ThemeKey.STATUS_TEXT.value: palette.blue,
237
+ ThemeKey.STATUS_TEXT_BOLD.value: "bold italic " + palette.blue,
200
238
  ThemeKey.STATUS_HINT.value: palette.grey2,
201
239
  # REMINDER
202
240
  ThemeKey.REMINDER.value: palette.grey1,
@@ -265,7 +303,10 @@ def get_theme(theme: str | None = None) -> Themes:
265
303
  ),
266
304
  thinking_markdown_theme=Theme(
267
305
  styles={
268
- "markdown.code": palette.grey1 + " italic on " + palette.text_background,
306
+ # THINKING (used for left-side mark in thinking output)
307
+ ThemeKey.THINKING.value: "italic " + palette.grey2,
308
+ ThemeKey.THINKING_BOLD.value: "bold italic " + palette.grey1,
309
+ "markdown.code": palette.grey1 + " italic on " + palette.code_background,
269
310
  "markdown.code.block": palette.grey1,
270
311
  "markdown.code.border": palette.grey3,
271
312
  "markdown.h1": "bold reverse",
@@ -292,4 +333,14 @@ def get_theme(theme: str | None = None) -> Themes:
292
333
  Style(color=palette.grey1),
293
334
  Style(color=palette.yellow),
294
335
  ],
336
+ sub_agent_backgrounds=[
337
+ Style(bgcolor=palette.cyan_background),
338
+ Style(bgcolor=palette.green_sub_background),
339
+ Style(bgcolor=palette.blue_sub_background),
340
+ Style(bgcolor=palette.purple_background),
341
+ Style(bgcolor=palette.orange_background),
342
+ Style(bgcolor=palette.red_background),
343
+ Style(bgcolor=palette.grey_background),
344
+ Style(bgcolor=palette.yellow_background),
345
+ ],
295
346
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.23
3
+ Version: 1.2.24
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0