klaude-code 1.2.14__py3-none-any.whl → 1.2.15__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.
@@ -142,7 +142,7 @@ def _select_anthropic_thinking_sync() -> llm_param.Thinking | None:
142
142
  use_jk_keys=False,
143
143
  style=SELECT_STYLE,
144
144
  ).ask()
145
- if result is None:
145
+ if not result:
146
146
  return llm_param.Thinking(type="disabled", budget_tokens=0)
147
147
  return llm_param.Thinking(type="enabled", budget_tokens=result or 0)
148
148
  except KeyboardInterrupt:
@@ -149,7 +149,7 @@ def parse_message_groups(history: list[model.ConversationItem]) -> list[MessageG
149
149
  for item in items:
150
150
  if isinstance(item, (model.UserMessageItem, model.DeveloperMessageItem)):
151
151
  if item.content:
152
- group.text_parts.append(item.content)
152
+ group.text_parts.append(item.content + "\n")
153
153
  if item.images:
154
154
  group.images.extend(item.images)
155
155
  groups.append(group)
@@ -9,19 +9,15 @@
9
9
  href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%230851b2%22 stroke-width=%222%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22><polyline points=%2216 18 22 12 16 6%22></polyline><polyline points=%228 6 2 12 8 18%22></polyline></svg>"
10
10
  />
11
11
  <link
12
- href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka/400.css"
12
+ href="https://cdn.jsdelivr.net/npm/@fontsource/geist-sans/latin-400.css"
13
13
  rel="stylesheet"
14
14
  />
15
15
  <link
16
- href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka/500.css"
16
+ href="https://cdn.jsdelivr.net/npm/@fontsource/geist-sans/latin-500.css"
17
17
  rel="stylesheet"
18
18
  />
19
19
  <link
20
- href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka/800.css"
21
- rel="stylesheet"
22
- />
23
- <link
24
- href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=IBM+Plex+Sans:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
20
+ href="https://cdn.jsdelivr.net/npm/@fontsource/geist-sans/latin-700.css"
25
21
  rel="stylesheet"
26
22
  />
27
23
  <style>
@@ -39,9 +35,9 @@
39
35
  --bg-error: #ffebee;
40
36
  --bg-code: #f3f3f3;
41
37
  --fg-inline-code: #4f4fc7;
42
- --font-mono: "Iosevka", "SF Mono", Menlo, monospace;
43
- --font-markdown-mono: "IBM Plex Mono", Menlo, monospace;
44
- --font-markdown: "IBM Plex Sans", system-ui, sans-serif;
38
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
39
+ --font-markdown-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
40
+ --font-markdown: "Geist Sans", system-ui, sans-serif;
45
41
  --font-weight-bold: 800;
46
42
  --font-size-xs: 13px;
47
43
  --font-size-sm: 14px;
@@ -114,7 +110,7 @@
114
110
 
115
111
  .meta-value {
116
112
  font-family: var(--font-mono);
117
- font-size: var(--font-size-base);
113
+ font-size: var(--font-size-xs);
118
114
  color: var(--text);
119
115
  overflow: hidden;
120
116
  text-overflow: ellipsis;
@@ -1199,7 +1195,7 @@
1199
1195
  mermaid.initialize({
1200
1196
  startOnLoad: true,
1201
1197
  theme: "neutral",
1202
- fontFamily: '"Iosevka", "SF Mono", Menlo, monospace',
1198
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace',
1203
1199
  });
1204
1200
  </script>
1205
1201
  <script>
@@ -9,7 +9,7 @@ from klaude_code import const
9
9
  from klaude_code.protocol import events
10
10
  from klaude_code.ui.core.stage_manager import Stage, StageManager
11
11
  from klaude_code.ui.modes.repl.renderer import REPLRenderer
12
- from klaude_code.ui.rich.markdown import MarkdownStream
12
+ from klaude_code.ui.rich.markdown import MarkdownStream, ThinkingMarkdown
13
13
  from klaude_code.ui.rich.theme import ThemeKey
14
14
  from klaude_code.ui.terminal.notifier import Notification, NotificationType, TerminalNotifier
15
15
  from klaude_code.ui.terminal.progress_bar import OSC94States, emit_osc94
@@ -318,6 +318,7 @@ class DisplayEventHandler:
318
318
  console=self.renderer.console,
319
319
  spinner=self.renderer.spinner_renderable(),
320
320
  indent=2,
321
+ markdown_class=ThinkingMarkdown,
321
322
  )
322
323
  self.thinking_stream.start(mdstream)
323
324
  self.renderer.spinner_stop()
@@ -145,9 +145,7 @@ class REPLRenderer:
145
145
  case events.AssistantMessageEvent() as e:
146
146
  if is_sub_agent:
147
147
  continue
148
- renderable = r_assistant.render_assistant_message(
149
- e.content, code_theme=self.themes.code_theme
150
- )
148
+ renderable = r_assistant.render_assistant_message(e.content, code_theme=self.themes.code_theme)
151
149
  if renderable is not None:
152
150
  self.print(renderable)
153
151
  self.print()
@@ -9,6 +9,7 @@ from rich.text import Text
9
9
 
10
10
  from klaude_code.protocol import events, model
11
11
  from klaude_code.trace import is_debug_enabled
12
+ from klaude_code.ui.renderers.common import create_grid
12
13
  from klaude_code.ui.rich.theme import ThemeKey
13
14
  from klaude_code.ui.utils.common import format_number
14
15
 
@@ -24,163 +25,123 @@ def _get_version() -> str:
24
25
  def _render_task_metadata_block(
25
26
  metadata: model.TaskMetadata,
26
27
  *,
27
- indent: int = 0,
28
+ is_sub_agent: bool = False,
28
29
  show_context_and_time: bool = True,
29
- ) -> list[RenderableType]:
30
+ ) -> RenderableType:
30
31
  """Render a single TaskMetadata block.
31
32
 
32
33
  Args:
33
34
  metadata: The TaskMetadata to render.
34
- indent: Number of spaces to indent (0 for main, 2 for sub-agents).
35
+ is_sub_agent: Whether this is a sub-agent block.
35
36
  show_context_and_time: Whether to show context usage percent and time.
36
37
 
37
38
  Returns:
38
- List of renderables for this metadata block.
39
+ A renderable for this metadata block.
39
40
  """
41
+ grid = create_grid()
42
+
40
43
  # Get currency symbol
41
44
  currency = metadata.usage.currency if metadata.usage else "USD"
42
45
  currency_symbol = "¥" if currency == "CNY" else "$"
43
46
 
44
- # Line 1: Model and Provider
45
- prefix = (
46
- Text(" " * indent + "• ", style=ThemeKey.METADATA_BOLD)
47
- if indent == 0
48
- else Text(" " * indent + "└ ", style=ThemeKey.METADATA_DIM)
49
- )
50
- model_text = Text()
51
- model_text.append_text(prefix).append_text(Text(metadata.model_name, style=ThemeKey.METADATA_BOLD))
47
+ # First column: mark only
48
+ mark = Text("└", style=ThemeKey.METADATA_DIM) if is_sub_agent else Text("•", style=ThemeKey.METADATA_BOLD)
49
+
50
+ # Second column: model@provider / tokens / cost / ...
51
+ content = Text()
52
+ content.append_text(Text(metadata.model_name, style=ThemeKey.METADATA_BOLD))
52
53
  if metadata.provider is not None:
53
- model_text.append_text(Text("@", style=ThemeKey.METADATA)).append_text(
54
+ content.append_text(Text("@", style=ThemeKey.METADATA)).append_text(
54
55
  Text(metadata.provider.lower().replace(" ", "-"), style=ThemeKey.METADATA)
55
56
  )
56
57
 
57
- renderables: list[RenderableType] = [model_text]
58
-
59
- # Line 2: Token consumption, Context, TPS, Cost
60
- parts2: list[Text] = []
58
+ # All info parts (tokens, cost, context, etc.)
59
+ parts: list[Text] = []
61
60
 
62
61
  if metadata.usage is not None:
63
- # Input
64
- input_parts: list[tuple[str, str]] = [
65
- ("input:", ThemeKey.METADATA_DIM),
66
- (format_number(metadata.usage.input_tokens), ThemeKey.METADATA_DIM),
62
+ # Tokens: ↑37k c5k ↓907 r45k
63
+ token_parts: list[tuple[str, str]] = [
64
+ ("", ThemeKey.METADATA_DIM),
65
+ (format_number(metadata.usage.input_tokens), ThemeKey.METADATA),
67
66
  ]
68
- if metadata.usage.input_cost is not None:
69
- input_parts.append((f"({currency_symbol}{metadata.usage.input_cost:.4f})", ThemeKey.METADATA_DIM))
70
- parts2.append(Text.assemble(*input_parts))
71
-
72
- # Cached
73
67
  if metadata.usage.cached_tokens > 0:
74
- cached_parts: list[tuple[str, str]] = [
75
- ("cached:", ThemeKey.METADATA_DIM),
76
- (format_number(metadata.usage.cached_tokens), ThemeKey.METADATA_DIM),
77
- ]
78
- if metadata.usage.cache_read_cost is not None:
79
- cached_parts.append((f"({currency_symbol}{metadata.usage.cache_read_cost:.4f})", ThemeKey.METADATA_DIM))
80
- parts2.append(Text.assemble(*cached_parts))
81
-
82
- # Output
83
- output_parts: list[tuple[str, str]] = [
84
- ("output:", ThemeKey.METADATA_DIM),
85
- (format_number(metadata.usage.output_tokens), ThemeKey.METADATA_DIM),
86
- ]
87
- if metadata.usage.output_cost is not None:
88
- output_parts.append((f"({currency_symbol}{metadata.usage.output_cost:.4f})", ThemeKey.METADATA_DIM))
89
- parts2.append(Text.assemble(*output_parts))
90
-
91
- # Reasoning
68
+ token_parts.append((" c", ThemeKey.METADATA_DIM))
69
+ token_parts.append((format_number(metadata.usage.cached_tokens), ThemeKey.METADATA))
70
+ token_parts.append((" ↓", ThemeKey.METADATA_DIM))
71
+ token_parts.append((format_number(metadata.usage.output_tokens), ThemeKey.METADATA))
92
72
  if metadata.usage.reasoning_tokens > 0:
93
- parts2.append(
94
- Text.assemble(
95
- ("thinking", ThemeKey.METADATA_DIM),
96
- (":", ThemeKey.METADATA_DIM),
97
- (
98
- format_number(metadata.usage.reasoning_tokens),
99
- ThemeKey.METADATA_DIM,
100
- ),
101
- )
102
- )
73
+ token_parts.append((" r", ThemeKey.METADATA_DIM))
74
+ token_parts.append((format_number(metadata.usage.reasoning_tokens), ThemeKey.METADATA))
75
+ parts.append(Text.assemble(*token_parts))
103
76
 
104
77
  # Cost
105
78
  if metadata.usage is not None and metadata.usage.total_cost is not None:
106
- parts2.append(
79
+ parts.append(
107
80
  Text.assemble(
108
- ("cost", ThemeKey.METADATA_DIM),
109
- (":", ThemeKey.METADATA_DIM),
110
- (f"{currency_symbol}{metadata.usage.total_cost:.4f}", ThemeKey.METADATA_DIM),
81
+ (currency_symbol, ThemeKey.METADATA_DIM),
82
+ (f"{metadata.usage.total_cost:.4f}", ThemeKey.METADATA),
111
83
  )
112
84
  )
113
- if parts2:
114
- line2 = Text(" / ", style=ThemeKey.METADATA_DIM).join(parts2)
115
- renderables.append(Padding(line2, (0, 0, 0, indent + 2)))
116
-
117
- parts3: list[Text] = []
118
85
  if metadata.usage is not None:
119
86
  # Context (only for main agent)
120
87
  if show_context_and_time and metadata.usage.context_usage_percent is not None:
121
88
  context_size = format_number(metadata.usage.context_size or 0)
122
- parts3.append(
89
+ parts.append(
123
90
  Text.assemble(
124
- ("context", ThemeKey.METADATA_DIM),
125
- (":", ThemeKey.METADATA_DIM),
126
- (
127
- f"{context_size}({metadata.usage.context_usage_percent:.1f}%)",
128
- ThemeKey.METADATA_DIM,
129
- ),
91
+ (context_size, ThemeKey.METADATA),
92
+ (f" ({metadata.usage.context_usage_percent:.1f}%)", ThemeKey.METADATA_DIM),
130
93
  )
131
94
  )
132
95
 
133
96
  # TPS
134
97
  if metadata.usage.throughput_tps is not None:
135
- parts3.append(
98
+ parts.append(
136
99
  Text.assemble(
100
+ (f"{metadata.usage.throughput_tps:.1f} ", ThemeKey.METADATA),
137
101
  ("tps", ThemeKey.METADATA_DIM),
138
- (":", ThemeKey.METADATA_DIM),
139
- (f"{metadata.usage.throughput_tps:.1f}", ThemeKey.METADATA_DIM),
140
102
  )
141
103
  )
142
104
 
143
105
  # Duration
144
106
  if show_context_and_time and metadata.task_duration_s is not None:
145
- parts3.append(
107
+ parts.append(
146
108
  Text.assemble(
147
- ("time", ThemeKey.METADATA_DIM),
148
- (":", ThemeKey.METADATA_DIM),
149
- (f"{metadata.task_duration_s:.1f}s", ThemeKey.METADATA_DIM),
109
+ (f"{metadata.task_duration_s:.1f}", ThemeKey.METADATA),
110
+ ("s", ThemeKey.METADATA_DIM),
150
111
  )
151
112
  )
152
113
 
153
114
  # Turn count
154
115
  if show_context_and_time and metadata.turn_count > 0:
155
- parts3.append(
116
+ parts.append(
156
117
  Text.assemble(
157
- ("turns", ThemeKey.METADATA_DIM),
158
- (":", ThemeKey.METADATA_DIM),
159
- (str(metadata.turn_count), ThemeKey.METADATA_DIM),
118
+ (str(metadata.turn_count), ThemeKey.METADATA),
119
+ (" turns", ThemeKey.METADATA_DIM),
160
120
  )
161
121
  )
162
122
 
163
- if parts3:
164
- line2 = Text(" / ", style=ThemeKey.METADATA_DIM).join(parts3)
165
- renderables.append(Padding(line2, (0, 0, 0, indent + 2)))
123
+ if parts:
124
+ content.append_text(Text(" · ", style=ThemeKey.METADATA_DIM))
125
+ content.append_text(Text(" · ", style=ThemeKey.METADATA_DIM).join(parts))
166
126
 
167
- return renderables
127
+ grid.add_row(mark, content)
128
+ return grid if not is_sub_agent else Padding(grid, (0, 0, 0, 2))
168
129
 
169
130
 
170
131
  def render_task_metadata(e: events.TaskMetadataEvent) -> RenderableType:
171
132
  """Render task metadata including main agent and sub-agents, aggregated by model+provider."""
172
133
  renderables: list[RenderableType] = []
173
134
 
174
- renderables.extend(_render_task_metadata_block(e.metadata.main, indent=0, show_context_and_time=True))
135
+ renderables.append(_render_task_metadata_block(e.metadata.main, is_sub_agent=False, show_context_and_time=True))
175
136
 
176
137
  # Aggregate by (model_name, provider), sorted by total_cost descending
177
138
  sorted_items = model.TaskMetadata.aggregate_by_model(e.metadata.sub_agent_task_metadata)
178
139
 
179
140
  # Render each aggregated model block
180
141
  for meta in sorted_items:
181
- renderables.extend(_render_task_metadata_block(meta, indent=2, show_context_and_time=False))
142
+ renderables.append(_render_task_metadata_block(meta, is_sub_agent=True, show_context_and_time=False))
182
143
 
183
- return Group(*renderables)
144
+ return Padding(Group(*renderables), (0, 0, 0, 1))
184
145
 
185
146
 
186
147
  def render_welcome(e: events.WelcomeEvent, *, box_style: Box | None = None) -> RenderableType:
@@ -2,7 +2,7 @@ from rich.console import RenderableType
2
2
  from rich.padding import Padding
3
3
  from rich.text import Text
4
4
 
5
- from klaude_code.ui.rich.markdown import NoInsetMarkdown
5
+ from klaude_code.ui.rich.markdown import ThinkingMarkdown
6
6
  from klaude_code.ui.rich.theme import ThemeKey
7
7
 
8
8
 
@@ -30,7 +30,7 @@ def render_thinking(content: str, *, code_theme: str, style: str) -> RenderableT
30
30
  return None
31
31
 
32
32
  return Padding.indent(
33
- NoInsetMarkdown(
33
+ ThinkingMarkdown(
34
34
  _normalize_thinking_content(content),
35
35
  code_theme=code_theme,
36
36
  style=style,
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
+ from typing import Any, cast
3
4
 
4
5
  from rich.console import RenderableType
5
6
  from rich.padding import Padding
@@ -58,6 +59,49 @@ def render_generic_tool_call(tool_name: str, arguments: str, markup: str = "•"
58
59
  return grid
59
60
 
60
61
 
62
+ def render_bash_tool_call(arguments: str) -> RenderableType:
63
+ grid = create_grid()
64
+ tool_name_column = Text.assemble((">", ThemeKey.TOOL_MARK), " ", ("Bash", ThemeKey.TOOL_NAME))
65
+
66
+ try:
67
+ payload_raw: Any = json.loads(arguments) if arguments else {}
68
+ except json.JSONDecodeError:
69
+ summary = Text(
70
+ arguments.strip()[: const.INVALID_TOOL_CALL_MAX_LENGTH],
71
+ style=ThemeKey.INVALID_TOOL_CALL_ARGS,
72
+ )
73
+ grid.add_row(tool_name_column, summary)
74
+ return grid
75
+
76
+ if not isinstance(payload_raw, dict):
77
+ summary = Text(
78
+ str(payload_raw)[: const.INVALID_TOOL_CALL_MAX_LENGTH],
79
+ style=ThemeKey.INVALID_TOOL_CALL_ARGS,
80
+ )
81
+ grid.add_row(tool_name_column, summary)
82
+ return grid
83
+
84
+ payload: dict[str, object] = cast(dict[str, object], payload_raw)
85
+
86
+ summary = Text("", ThemeKey.TOOL_PARAM)
87
+ command = payload.get("command")
88
+ timeout_ms = payload.get("timeout_ms")
89
+
90
+ if isinstance(command, str) and command.strip():
91
+ summary.append(command.strip(), style=ThemeKey.TOOL_PARAM)
92
+
93
+ if isinstance(timeout_ms, int):
94
+ if summary:
95
+ summary.append(" ")
96
+ if timeout_ms >= 1000 and timeout_ms % 1000 == 0:
97
+ summary.append(f"{timeout_ms // 1000}s", style=ThemeKey.TOOL_TIMEOUT)
98
+ else:
99
+ summary.append(f"{timeout_ms}ms", style=ThemeKey.TOOL_TIMEOUT)
100
+
101
+ grid.add_row(tool_name_column, summary)
102
+ return grid
103
+
104
+
61
105
  def render_update_plan_tool_call(arguments: str) -> RenderableType:
62
106
  grid = create_grid()
63
107
  tool_name_column = Text.assemble(("◎", ThemeKey.TOOL_MARK), " ", ("Update Plan", ThemeKey.TOOL_NAME))
@@ -461,7 +505,7 @@ def render_tool_call(e: events.ToolCallEvent) -> RenderableType | None:
461
505
  case tools.MULTI_EDIT:
462
506
  return render_multi_edit_tool_call(e.arguments)
463
507
  case tools.BASH:
464
- return render_generic_tool_call(e.tool_name, e.arguments, ">")
508
+ return render_bash_tool_call(e.arguments)
465
509
  case tools.APPLY_PATCH:
466
510
  return render_apply_patch_tool_call(e.arguments)
467
511
  case tools.TODO_WRITE:
@@ -4,8 +4,10 @@ from __future__ import annotations
4
4
  import contextlib
5
5
  import io
6
6
  import time
7
+ from collections.abc import Callable
7
8
  from typing import Any, ClassVar
8
9
 
10
+ from rich import box
9
11
  from rich.console import Console, ConsoleOptions, Group, RenderableType, RenderResult
10
12
  from rich.live import Live
11
13
  from rich.markdown import CodeBlock, Heading, Markdown
@@ -32,7 +34,16 @@ class NoInsetCodeBlock(CodeBlock):
32
34
  word_wrap=True,
33
35
  padding=(0, 1),
34
36
  )
35
- yield Panel.fit(syntax, padding=0, border_style="markdown.code.panel")
37
+ yield Panel.fit(syntax, padding=(0, 0), style="markdown.code.block", box=box.SIMPLE)
38
+
39
+
40
+ class ThinkingCodeBlock(CodeBlock):
41
+ """A code block for thinking content that uses grey styling instead of syntax highlighting."""
42
+
43
+ def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
44
+ code = str(self.text).rstrip()
45
+ text = Text("```\n" + code + "\n```")
46
+ yield text
36
47
 
37
48
 
38
49
  class LeftHeading(Heading):
@@ -41,15 +52,6 @@ class LeftHeading(Heading):
41
52
  def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
42
53
  text = self.text
43
54
  text.justify = "left" # Override justification
44
- # if self.tag == "h1":
45
- # from rich.panel import Panel
46
- # from rich import box
47
- # # Draw a border around h1s, but keep text left-aligned
48
- # yield Panel(
49
- # text,
50
- # box=box.SQUARE,
51
- # style="markdown.h1.border",
52
- # )
53
55
  if self.tag == "h2":
54
56
  text.stylize(Style(bold=True, underline=False))
55
57
  yield Rule(title=text, characters="-", style="markdown.h2.border", align="left")
@@ -68,6 +70,17 @@ class NoInsetMarkdown(Markdown):
68
70
  }
69
71
 
70
72
 
73
+ class ThinkingMarkdown(Markdown):
74
+ """Markdown for thinking content with grey-styled code blocks and left-justified headings."""
75
+
76
+ elements: ClassVar[dict[str, type[Any]]] = {
77
+ **Markdown.elements,
78
+ "fence": ThinkingCodeBlock,
79
+ "code_block": ThinkingCodeBlock,
80
+ "heading_open": LeftHeading,
81
+ }
82
+
83
+
71
84
  class MarkdownStream:
72
85
  """Streaming markdown renderer that progressively displays content with a live updating window.
73
86
 
@@ -84,6 +97,7 @@ class MarkdownStream:
84
97
  spinner: Spinner | None = None,
85
98
  mark: str | None = None,
86
99
  indent: int = 0,
100
+ markdown_class: Callable[..., Markdown] | None = None,
87
101
  ) -> None:
88
102
  """Initialize the markdown stream.
89
103
 
@@ -93,6 +107,7 @@ class MarkdownStream:
93
107
  console (Console, optional): External console to use for rendering
94
108
  mark (str | None, optional): Marker shown before the first non-empty line when indent >= 2
95
109
  indent (int, optional): Number of spaces to indent all rendered lines on the left
110
+ markdown_class: Markdown class to use for rendering (defaults to NoInsetMarkdown)
96
111
  """
97
112
  self.printed: list[str] = [] # Stores lines that have already been printed
98
113
 
@@ -118,6 +133,7 @@ class MarkdownStream:
118
133
  self.spinner: Spinner | None = spinner
119
134
  self.mark: str | None = mark
120
135
  self.indent: int = max(indent, 0)
136
+ self.markdown_class: Callable[..., Markdown] = markdown_class or NoInsetMarkdown
121
137
 
122
138
  @property
123
139
  def _live_started(self) -> bool:
@@ -154,7 +170,7 @@ class MarkdownStream:
154
170
  width=effective_width,
155
171
  )
156
172
 
157
- markdown = NoInsetMarkdown(text, **self.mdargs)
173
+ markdown = self.markdown_class(text, **self.mdargs)
158
174
  temp_console.print(markdown)
159
175
  output = string_io.getvalue()
160
176
 
@@ -14,12 +14,12 @@ class Palette:
14
14
  blue: str
15
15
  orange: str
16
16
  magenta: str
17
- grey_blue: str
18
17
  grey1: str
19
18
  grey2: str
20
19
  grey3: str
21
20
  grey_green: str
22
21
  purple: str
22
+ lavender: str
23
23
  diff_add: str
24
24
  diff_remove: str
25
25
  code_theme: str
@@ -31,15 +31,15 @@ LIGHT_PALETTE = Palette(
31
31
  yellow="yellow",
32
32
  green="spring_green4",
33
33
  cyan="cyan",
34
- blue="#3678b7",
34
+ blue="#3078C5",
35
35
  orange="#d77757",
36
36
  magenta="magenta",
37
- grey_blue="steel_blue",
38
37
  grey1="#667e90",
39
38
  grey2="#93a4b1",
40
39
  grey3="#c4ced4",
41
- grey_green="#96a696",
40
+ grey_green="#96a096",
42
41
  purple="slate_blue3",
42
+ lavender="steel_blue",
43
43
  diff_add="#2e5a32 on #e8f5e9",
44
44
  diff_remove="#5a2e32 on #ffebee",
45
45
  code_theme="ansi_light",
@@ -54,12 +54,12 @@ DARK_PALETTE = Palette(
54
54
  blue="deep_sky_blue1",
55
55
  orange="#e6704e",
56
56
  magenta="magenta",
57
- grey_blue="steel_blue",
58
57
  grey1="#99aabb",
59
58
  grey2="#778899",
60
59
  grey3="#646464",
61
60
  grey_green="#6d8672",
62
61
  purple="#afbafe",
62
+ lavender="#9898b8",
63
63
  diff_add="#c8e6c9 on #2e4a32",
64
64
  diff_remove="#ffcdd2 on #4a2e32",
65
65
  code_theme="ansi_dark",
@@ -107,6 +107,7 @@ class ThemeKey(str, Enum):
107
107
  TOOL_MARK = "tool.mark"
108
108
  TOOL_APPROVED = "tool.approved"
109
109
  TOOL_REJECTED = "tool.rejected"
110
+ TOOL_TIMEOUT = "tool.timeout"
110
111
  # THINKING
111
112
  THINKING = "thinking"
112
113
  THINKING_BOLD = "thinking.bold"
@@ -174,9 +175,9 @@ def get_theme(theme: str | None = None) -> Themes:
174
175
  ThemeKey.USER_INPUT_AT_PATTERN.value: palette.purple,
175
176
  ThemeKey.USER_INPUT_SLASH_COMMAND.value: "bold reverse " + palette.blue,
176
177
  # METADATA
177
- ThemeKey.METADATA.value: palette.grey_blue,
178
- ThemeKey.METADATA_DIM.value: "dim " + palette.grey_blue,
179
- ThemeKey.METADATA_BOLD.value: "bold " + palette.grey_blue,
178
+ ThemeKey.METADATA.value: palette.lavender,
179
+ ThemeKey.METADATA_DIM.value: "dim " + palette.lavender,
180
+ ThemeKey.METADATA_BOLD.value: "bold " + palette.lavender,
180
181
  # SPINNER_STATUS
181
182
  ThemeKey.SPINNER_STATUS.value: palette.blue,
182
183
  ThemeKey.SPINNER_STATUS_TEXT.value: palette.blue,
@@ -196,6 +197,7 @@ def get_theme(theme: str | None = None) -> Themes:
196
197
  ThemeKey.TOOL_MARK.value: "bold",
197
198
  ThemeKey.TOOL_APPROVED.value: palette.green + " bold reverse",
198
199
  ThemeKey.TOOL_REJECTED.value: palette.red + " bold reverse",
200
+ ThemeKey.TOOL_TIMEOUT.value: palette.yellow,
199
201
  # THINKING
200
202
  ThemeKey.THINKING.value: "italic " + palette.grey2,
201
203
  ThemeKey.THINKING_BOLD.value: "bold italic " + palette.grey1,
@@ -232,7 +234,7 @@ def get_theme(theme: str | None = None) -> Themes:
232
234
  markdown_theme=Theme(
233
235
  styles={
234
236
  "markdown.code": palette.purple,
235
- "markdown.code.panel": palette.grey3,
237
+ "markdown.code.block": "on " + palette.text_background,
236
238
  "markdown.h1": "bold reverse",
237
239
  "markdown.h1.border": palette.grey3,
238
240
  "markdown.h2.border": palette.grey3,
@@ -245,8 +247,7 @@ def get_theme(theme: str | None = None) -> Themes:
245
247
  ),
246
248
  thinking_markdown_theme=Theme(
247
249
  styles={
248
- "markdown.code": palette.grey1 + " on " + palette.text_background,
249
- "markdown.code.panel": palette.grey3,
250
+ "markdown.code": palette.grey1 + " italic on " + palette.text_background,
250
251
  "markdown.h1": "bold reverse",
251
252
  "markdown.h1.border": palette.grey3,
252
253
  "markdown.h2.border": palette.grey3,
@@ -265,7 +266,6 @@ def get_theme(theme: str | None = None) -> Themes:
265
266
  Style(color=palette.blue),
266
267
  Style(color=palette.purple),
267
268
  Style(color=palette.orange),
268
- Style(color=palette.grey_blue),
269
269
  Style(color=palette.red),
270
270
  Style(color=palette.grey1),
271
271
  Style(color=palette.yellow),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.14
3
+ Version: 1.2.15
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: openai>=1.102.0
@@ -29,7 +29,7 @@ klaude_code/command/registry.py,sha256=Vy2WL1M35LL3aLkidXa2QGgGBFBKHQe_S93TZcH55
29
29
  klaude_code/command/release_notes_cmd.py,sha256=lDeAjuMDOSUISM0yYKZKbkjrYvFmvA5_fylkalTPaBU,2707
30
30
  klaude_code/command/status_cmd.py,sha256=F7XgfivBm80kJEsCgRHGXWOALAT_Y2QyLQ38ooc_ZSE,5393
31
31
  klaude_code/command/terminal_setup_cmd.py,sha256=iSYGZlflj_i-7i-9FhfhtbyyIe3UNkhPeehZezi-ULM,10944
32
- klaude_code/command/thinking_cmd.py,sha256=rdPUHEGkHeth7dRS8B9F7Ryu5x4vQ7IIKxEr39STpfA,8001
32
+ klaude_code/command/thinking_cmd.py,sha256=pvCxyfDuF1aWJuYaRkVkDmuc0JkJUGBHJR2gNHt8PMQ,7997
33
33
  klaude_code/config/__init__.py,sha256=Qrqvi8nizkj6N77h2vDj0r4rbgCiqxvz2HLBPFuWulA,120
34
34
  klaude_code/config/config.py,sha256=2tSf6x88vuPfMMWcKlckXPoEjnxzFCtw2g_gbDjzK90,7268
35
35
  klaude_code/config/list_model.py,sha256=Uthp0nHaENBgD6l_a6wG0RFkRHQhLvIyjHPsP55Kazw,8010
@@ -104,7 +104,7 @@ klaude_code/llm/anthropic/input.py,sha256=qPo4nmhnhSfLqef4UUVoIz8EjoXTxvlsrfsc_6
104
104
  klaude_code/llm/client.py,sha256=FbFnzLUAKM61goiYNdKi8-D4rBfu_ksaxjJtmJn0w_4,960
105
105
  klaude_code/llm/codex/__init__.py,sha256=8vN2j2ezWB_UVpfqQ8ooStsBeLL5SY4SUMXOXdWiMaI,132
106
106
  klaude_code/llm/codex/client.py,sha256=0BAOiLAdk2PxBEYuC_TGOs4_h6yfNZr1YWuf1lzkBxM,5329
107
- klaude_code/llm/input_common.py,sha256=-tvMg7QNkyy8EJ_ZTQ-V9ei6-VdD06zCBXQuFSNRa3o,8526
107
+ klaude_code/llm/input_common.py,sha256=NxiYlhGRFntiLiKm5sKLCF0xGYW6DwcyvIhj6KAZoeU,8533
108
108
  klaude_code/llm/openai_compatible/__init__.py,sha256=ACGpnki7k53mMcCl591aw99pm9jZOZk0ghr7atOfNps,81
109
109
  klaude_code/llm/openai_compatible/client.py,sha256=DD1tnVqPIicmlG4tK0dlYgLkY_7vaZL8OvqYNRK6fu0,7846
110
110
  klaude_code/llm/openai_compatible/input.py,sha256=rtWVjpwb9tLrinucezmncQXet8MerUxE5Gxc32sfDr4,3750
@@ -132,7 +132,7 @@ klaude_code/session/__init__.py,sha256=oXcDA5w-gJCbzmlF8yuWy3ezIW9DgFBNUs-gJHUJ-
132
132
  klaude_code/session/export.py,sha256=yoRvIfEehjwHL9qNNd6kJWhXLdXTsQlpf8KCoR_tjkI,26512
133
133
  klaude_code/session/selector.py,sha256=gijwWQkSV20XYP3Fxr27mFXuqP4ChY2DQm_YuBOTQKw,2888
134
134
  klaude_code/session/session.py,sha256=w9ei9kkgT7-C4hlToQm0Cd35HTTOSPYkIGnrtaoJg6Q,21386
135
- klaude_code/session/templates/export_session.html,sha256=iCvsxq7ZMnh7W-bK3S8UFSNQO46Hy7sIdavAYxSZhp4,47744
135
+ klaude_code/session/templates/export_session.html,sha256=BKFn1_EHg0vsF0g2J0sWoe0efF6eNk9loaPYEG8p3GQ,47705
136
136
  klaude_code/trace/__init__.py,sha256=cETWJZZJaJ8_kA5Uki0om5n-ZpBxO9ph6YGYsJDXOEk,234
137
137
  klaude_code/trace/log.py,sha256=0H_RqkytSpt6AAIFDg-MV_8vA9zsR9BB1UqT6moTTTg,9134
138
138
  klaude_code/ui/__init__.py,sha256=XuEQsFUkJet8HI04cRmNLwnHOUqaPCRy4hF7PJnIfCY,2737
@@ -149,28 +149,28 @@ klaude_code/ui/modes/repl/__init__.py,sha256=35a6SUiL1SDi2i43X2VjHQw97rR7yhbLBzk
149
149
  klaude_code/ui/modes/repl/clipboard.py,sha256=ZCpk7kRSXGhh0Q_BWtUUuSYT7ZOqRjAoRcg9T9n48Wo,5137
150
150
  klaude_code/ui/modes/repl/completers.py,sha256=RyxvbOwVXTa4PTl1thVz6YbBhXhCZa7ZX87eiGRHGp4,18224
151
151
  klaude_code/ui/modes/repl/display.py,sha256=0u4ISeOoYjynF7InYyV-PMOZqP44QBbjYOLOL18V0c0,2245
152
- klaude_code/ui/modes/repl/event_handler.py,sha256=-dr1eNavx-19RxXdqdvNy3TFzf4KED9Sp2DRGMuoT5o,21153
152
+ klaude_code/ui/modes/repl/event_handler.py,sha256=j24Q-ygfI2RHuYj2Atg_1vrzW7fT6lx-jww11Uzs25g,21220
153
153
  klaude_code/ui/modes/repl/input_prompt_toolkit.py,sha256=EAIAtcL9EHVPmVK6oOHg0xCeZ0IOnG5S5KsaL85OHOk,6368
154
154
  klaude_code/ui/modes/repl/key_bindings.py,sha256=Fxz9Ey2SnOHvfleMeSYVduxuofY0Yo-97hMRs-OMe-o,7800
155
- klaude_code/ui/modes/repl/renderer.py,sha256=tOGYTMwBCAG25466ne37subthdv7FPxlY8ZKN-NwwcA,11460
155
+ klaude_code/ui/modes/repl/renderer.py,sha256=M0Fhj_mQXyjHnKDzrmZ0mnPk7L6IFIU4wCgHSsffmAQ,11406
156
156
  klaude_code/ui/renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
157
157
  klaude_code/ui/renderers/assistant.py,sha256=Dxy6v4pX28RyWhnrjBteY8_NvDIi_jQa-j0mWt-eqWY,569
158
158
  klaude_code/ui/renderers/common.py,sha256=TPH7LCbeJGqB8ArTsVitqJHEyOxHU6nwnRtvF04nLJ4,184
159
159
  klaude_code/ui/renderers/developer.py,sha256=fE-9LRzVLiKnK3ctFcuDDP_eehohhsgPCH_tYaOp-xs,6378
160
160
  klaude_code/ui/renderers/diffs.py,sha256=iPQxxZW1JGPwtTdCKMEkDlNb5trLm9tdWjfMRmtj6yQ,7616
161
161
  klaude_code/ui/renderers/errors.py,sha256=c_fbnoNOnvuI3Bb24IujwV8Mpes-qWS_xCWfAcBvg6A,517
162
- klaude_code/ui/renderers/metadata.py,sha256=QQev-3S3AS7GuWUhekjbnFJj3cFcbNxNtEYxzAl1Xm8,9121
162
+ klaude_code/ui/renderers/metadata.py,sha256=gnnIEs7iFiWNCADKa7N9FtDxvVZKtVo-6JuT2I9sIhA,7760
163
163
  klaude_code/ui/renderers/sub_agent.py,sha256=3cyn95pu4IniOJyWW4vfQ-X72iLufQ3LT9CkAQMuF4k,2686
164
- klaude_code/ui/renderers/thinking.py,sha256=jzDfvYuwpafndmBMMb6UumGxur9iFi_X0LYIo08eDlw,1179
165
- klaude_code/ui/renderers/tools.py,sha256=wPABeq1OMJOvKu2aZOFaPN9LHgEt0jd9LG9_KkVGz-M,20129
164
+ klaude_code/ui/renderers/thinking.py,sha256=rYc7KttyEW7r3133dFLofpiQCYH-NiZolexYo-N8Vfs,1181
165
+ klaude_code/ui/renderers/tools.py,sha256=d-8udsM-81P6rwQhJgmN_J93Kj8KVvrUBbcH86PmTRc,21619
166
166
  klaude_code/ui/renderers/user_input.py,sha256=rDdOYvbgJ6oePQAtyTCK-KhARfLKytpTZboZ-cFIuJQ,2603
167
167
  klaude_code/ui/rich/__init__.py,sha256=olvMm2SteyKioOqUJbEoav2TsDr_mtKqkSaifNumjwc,27
168
168
  klaude_code/ui/rich/live.py,sha256=Uid0QAZG7mHb4KrCF8p9c9n1nHLHzW75xSqcLZ4bLWY,2098
169
- klaude_code/ui/rich/markdown.py,sha256=itfqiiS3ysxtt22hYJtHIlmAWay1F8TmlQhZexiQ4F8,11684
169
+ klaude_code/ui/rich/markdown.py,sha256=k5Kx5SSoSMnVW-35dZw6Yp26ahPErDYVpKPI6wpXP8c,12347
170
170
  klaude_code/ui/rich/quote.py,sha256=tZcxN73SfDBHF_qk0Jkh9gWBqPBn8VLp9RF36YRdKEM,1123
171
171
  klaude_code/ui/rich/searchable_text.py,sha256=DCVZgEFv7_ergAvT2v7XrfQAUXUzhmAwuVAchlIx8RY,2448
172
172
  klaude_code/ui/rich/status.py,sha256=r5KmymTKo-FsOVBJxp8orhqFT8GP8Mf1DHkw1icnuOA,8522
173
- klaude_code/ui/rich/theme.py,sha256=o6NMPXaHu2CGW2XfeQrlTd8ErgKdxjD2MdiKo2kP13Y,10127
173
+ klaude_code/ui/rich/theme.py,sha256=yMGWoVzG9leHB3eR4ufFzW2nAhXOtiYEwwn0kvCtr4E,10140
174
174
  klaude_code/ui/terminal/__init__.py,sha256=GIMnsEcIAGT_vBHvTlWEdyNmAEpruyscUA6M_j3GQZU,1412
175
175
  klaude_code/ui/terminal/color.py,sha256=M-i09DVlLAhAyhQjfeAi7OipoGi1p_OVkaZxeRfykY0,7135
176
176
  klaude_code/ui/terminal/control.py,sha256=6SGNwxorP3jMW9xqnZy2BC0OsJd4DSrS13O3t6YlZzs,4916
@@ -180,7 +180,7 @@ klaude_code/ui/utils/__init__.py,sha256=YEsCLjbCPaPza-UXTPUMTJTrc9BmNBUP5CbFWlsh
180
180
  klaude_code/ui/utils/common.py,sha256=UCQMun23l-EREr3xkl-Bjx67yfi9ctRTw2gcGPsOM2c,2881
181
181
  klaude_code/ui/utils/debouncer.py,sha256=x8AYxf48Xd6tabBvH8cVl1bIV8FzyeDo3HswDjtNfwU,1266
182
182
  klaude_code/version.py,sha256=x2OeiACPdzS87EWtaSi_UP13htm81Uq7mlV3kFy5jko,4815
183
- klaude_code-1.2.14.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
184
- klaude_code-1.2.14.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
185
- klaude_code-1.2.14.dist-info/METADATA,sha256=Bx4DAWQQ-v48v-cgJOFPe8511dvLjfEkFihxlQLeGms,5067
186
- klaude_code-1.2.14.dist-info/RECORD,,
183
+ klaude_code-1.2.15.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
184
+ klaude_code-1.2.15.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
185
+ klaude_code-1.2.15.dist-info/METADATA,sha256=r1bX2TVm7kMRX4v3YEHPbhn7P954cykmgxHvQFZG2o4,5067
186
+ klaude_code-1.2.15.dist-info/RECORD,,