klaude-code 2.10.0__py3-none-any.whl → 2.10.1__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.
@@ -12,6 +12,7 @@ from klaude_code.core.agent import Agent
12
12
  from klaude_code.core.agent_profile import (
13
13
  DefaultModelProfileProvider,
14
14
  VanillaModelProfileProvider,
15
+ WebModelProfileProvider,
15
16
  )
16
17
  from klaude_code.core.executor import Executor
17
18
  from klaude_code.core.manager import build_llm_clients
@@ -27,6 +28,7 @@ class AppInitConfig:
27
28
  model: str | None
28
29
  debug: bool
29
30
  vanilla: bool
31
+ web: bool = False
30
32
  debug_filters: set[DebugType] | None = None
31
33
 
32
34
 
@@ -74,6 +76,8 @@ async def initialize_app_components(
74
76
 
75
77
  if init_config.vanilla:
76
78
  model_profile_provider = VanillaModelProfileProvider()
79
+ elif init_config.web:
80
+ model_profile_provider = WebModelProfileProvider(config=config)
77
81
  else:
78
82
  model_profile_provider = DefaultModelProfileProvider(config=config)
79
83
 
klaude_code/cli/main.py CHANGED
@@ -200,6 +200,11 @@ def main_callback(
200
200
  help="Image generation mode (alias for --model banana)",
201
201
  rich_help_panel="LLM",
202
202
  ),
203
+ web: bool = typer.Option(
204
+ False,
205
+ "--web",
206
+ help="Enable web tools (WebFetch, WebSearch) for the main agent",
207
+ ),
203
208
  version: bool = typer.Option(
204
209
  False,
205
210
  "--version",
@@ -218,6 +223,10 @@ def main_callback(
218
223
  log(("Error: --banana cannot be combined with --vanilla", "red"))
219
224
  raise typer.Exit(2)
220
225
 
226
+ if vanilla and web:
227
+ log(("Error: --web cannot be combined with --vanilla", "red"))
228
+ raise typer.Exit(2)
229
+
221
230
  resume_by_id_value = resume_by_id.strip() if resume_by_id is not None else None
222
231
  if resume_by_id_value == "":
223
232
  log(("Error: --resume <id> cannot be empty", "red"))
@@ -347,6 +356,7 @@ def main_callback(
347
356
  model=chosen_model,
348
357
  debug=debug_enabled,
349
358
  vanilla=vanilla,
359
+ web=web,
350
360
  debug_filters=debug_filters,
351
361
  )
352
362
 
@@ -57,22 +57,14 @@ provider_list:
57
57
  reasoning_summary: concise
58
58
  cost: {input: 1.75, output: 14, cache_read: 0.17}
59
59
 
60
- - model_name: gpt-5.2-fast
61
- model_id: gpt-5.2
62
- context_limit: 400000
63
- verbosity: low
60
+ - model_name: gpt-5.2-codex
61
+ model_id: gpt-5.2-codex
64
62
  thinking:
65
- reasoning_effort: none
66
- cost: {input: 1.75, output: 14, cache_read: 0.17}
67
-
68
- - model_name: gpt-5.1-codex-max
69
- model_id: gpt-5.1-codex-max
70
- max_tokens: 128000
63
+ reasoning_effort: high
64
+ reasoning_summary: auto
71
65
  context_limit: 400000
72
- thinking:
73
- reasoning_effort: medium
74
- reasoning_summary: concise
75
- cost: {input: 1.25, output: 10, cache_read: 0.13}
66
+ max_tokens: 128000
67
+ cost: {input: 1.75, output: 14, cache_read: 0.17}
76
68
 
77
69
 
78
70
  - provider_name: openrouter
@@ -80,6 +72,15 @@ provider_list:
80
72
  api_key: ${OPENROUTER_API_KEY}
81
73
  model_list:
82
74
 
75
+ - model_name: gpt-5.2-codex
76
+ model_id: gpt-5.2-codex
77
+ thinking:
78
+ reasoning_effort: high
79
+ reasoning_summary: auto
80
+ context_limit: 400000
81
+ max_tokens: 128000
82
+ cost: {input: 1.75, output: 14, cache_read: 0.17}
83
+
83
84
  - model_name: gpt-5.2-high
84
85
  model_id: openai/gpt-5.2
85
86
  max_tokens: 128000
@@ -305,3 +305,26 @@ class VanillaModelProfileProvider(ModelProfileProvider):
305
305
  if output_schema:
306
306
  return with_structured_output(profile, output_schema)
307
307
  return profile
308
+
309
+
310
+ class WebModelProfileProvider(DefaultModelProfileProvider):
311
+ """Provider that adds web tools to the main agent."""
312
+
313
+ def build_profile(
314
+ self,
315
+ llm_client: LLMClientABC,
316
+ sub_agent_type: tools.SubAgentType | None = None,
317
+ *,
318
+ output_schema: dict[str, Any] | None = None,
319
+ ) -> AgentProfile:
320
+ profile = super().build_profile(llm_client, sub_agent_type, output_schema=output_schema)
321
+ # Only add web tools for main agent (not sub-agents)
322
+ if sub_agent_type is None:
323
+ web_tools = get_tool_schemas([tools.WEB_FETCH, tools.WEB_SEARCH])
324
+ return AgentProfile(
325
+ llm_client=profile.llm_client,
326
+ system_prompt=profile.system_prompt,
327
+ tools=[*profile.tools, *web_tools],
328
+ reminders=profile.reminders,
329
+ )
330
+ return profile
@@ -17,7 +17,7 @@ You are a web research subagent that searches and fetches web content to provide
17
17
  - HTML pages are automatically converted to Markdown
18
18
  - JSON responses are auto-formatted with indentation
19
19
  - Other text content returned as-is
20
- - **Content is always saved to a local file** - path shown in `[Web content saved to ...]` at output start
20
+ - **Content is always saved to a local file** - path shown in `[Full content saved to ...]` at output start
21
21
 
22
22
  ## Tool Usage Strategy
23
23
 
@@ -54,7 +54,7 @@ Balance efficiency with thoroughness. For open-ended questions (e.g., "recommend
54
54
  ## Response Guidelines
55
55
 
56
56
  - Only your last message is returned to the main agent
57
- - Include the file path from `[Web content saved to ...]` so the main agent can access full content
57
+ - Include the file path from `[Full content saved to ...]` so the main agent can access full content
58
58
  - **DO NOT copy full web page content** - the main agent can read the saved files directly
59
59
  - Provide a concise summary/analysis of key findings
60
60
  - Lead with the most recent info for evolving topics
@@ -227,11 +227,11 @@ class HeadTailOffloadStrategy(OffloadStrategy):
227
227
  if self._should_offload(needs_truncation):
228
228
  offloaded_path = self._save_to_file(output, tool_call)
229
229
 
230
- # Prefer line-based truncation if line limit exceeded
231
- if needs_line_truncation:
232
- truncated_output, hidden = self._truncate_by_lines(output, lines, offloaded_path)
233
- else:
230
+ # Prefer char-based truncation if char limit exceeded (stricter limit)
231
+ if needs_char_truncation:
234
232
  truncated_output, hidden = self._truncate_by_chars(output, offloaded_path)
233
+ else:
234
+ truncated_output, hidden = self._truncate_by_lines(output, lines, offloaded_path)
235
235
 
236
236
  return OffloadResult(
237
237
  output=truncated_output,
@@ -1,8 +1,9 @@
1
1
  Fetch content from a URL and return it in a readable format.
2
2
 
3
3
  The tool automatically processes the response based on Content-Type:
4
+
4
5
  - HTML pages are converted to Markdown for easier reading
5
6
  - JSON responses are formatted with indentation
6
7
  - Markdown and other text content is returned as-is
7
8
 
8
- Content is always saved to a local file. The file path is shown at the start of the output in `[Web content saved to ...]` format. For large content that gets truncated, you can read the saved file directly.
9
+ Content is always saved to a local file. The file path is shown at the start of the output in `[Full content saved to ...]` format. For large content that gets truncated, you can read the saved file directly.
@@ -235,7 +235,7 @@ class WebFetchTool(ToolABC):
235
235
  text = _decode_content(data, charset)
236
236
  processed = _process_content(content_type, text)
237
237
  saved_path = _save_text_content(url, processed)
238
- output = f"[Web content saved to {saved_path}]\n\n{processed}" if saved_path else processed
238
+ output = f"[Full content saved to {saved_path}]\n\n{processed}" if saved_path else processed
239
239
 
240
240
  return message.ToolResultMessage(
241
241
  status="success",
klaude_code/core/turn.py CHANGED
@@ -196,8 +196,7 @@ class TurnExecutor:
196
196
  ):
197
197
  # Discard partial message if it only contains thinking parts
198
198
  has_non_thinking = any(
199
- not isinstance(part, message.ThinkingTextPart)
200
- for part in self._turn_result.assistant_message.parts
199
+ not isinstance(part, message.ThinkingTextPart) for part in self._turn_result.assistant_message.parts
201
200
  )
202
201
  if has_non_thinking:
203
202
  session_ctx.append_history([self._turn_result.assistant_message])
@@ -539,6 +539,21 @@ __KLAUDE_CODE__</textarea
539
539
  </svg>
540
540
  <span>SVG</span>
541
541
  </button>
542
+ <button class="tool-btn" id="btn-download-png" title="Download PNG">
543
+ <svg
544
+ width="16"
545
+ height="16"
546
+ viewBox="0 0 24 24"
547
+ fill="none"
548
+ stroke="currentColor"
549
+ stroke-width="2"
550
+ >
551
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
552
+ <polyline points="7 10 12 15 17 10"></polyline>
553
+ <line x1="12" y1="15" x2="12" y2="3"></line>
554
+ </svg>
555
+ <span>PNG</span>
556
+ </button>
542
557
  </div>
543
558
  </div>
544
559
 
@@ -570,6 +585,7 @@ __KLAUDE_CODE__</textarea
570
585
  zoomOut: document.getElementById("btn-zoom-out"),
571
586
  reset: document.getElementById("btn-reset"),
572
587
  download: document.getElementById("btn-download"),
588
+ downloadPng: document.getElementById("btn-download-png"),
573
589
  copy: document.getElementById("btn-copy-code"),
574
590
  collapse: document.getElementById("btn-collapse"),
575
591
  expand: document.getElementById("btn-expand"),
@@ -894,6 +910,75 @@ __KLAUDE_CODE__</textarea
894
910
  URL.revokeObjectURL(url);
895
911
  };
896
912
 
913
+ els.btns.downloadPng.onclick = async () => {
914
+ const svg = els.canvas.querySelector("svg");
915
+ if (!svg) return;
916
+
917
+ const clone = svg.cloneNode(true);
918
+
919
+ const bbox = svg.getBBox();
920
+ const width = bbox.width + 40;
921
+ const height = bbox.height + 40;
922
+
923
+ clone.setAttribute("width", width);
924
+ clone.setAttribute("height", height);
925
+ clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
926
+ clone.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
927
+
928
+ // Remove foreignObject elements (they cause tainted canvas)
929
+ clone.querySelectorAll("foreignObject").forEach((fo) => {
930
+ const text = fo.textContent || "";
931
+ const parent = fo.parentNode;
932
+ if (parent) {
933
+ const textEl = document.createElementNS("http://www.w3.org/2000/svg", "text");
934
+ textEl.textContent = text;
935
+ textEl.setAttribute("font-family", "sans-serif");
936
+ textEl.setAttribute("font-size", "14");
937
+ parent.replaceChild(textEl, fo);
938
+ }
939
+ });
940
+
941
+ // Add white background rect
942
+ const bgRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
943
+ bgRect.setAttribute("width", "100%");
944
+ bgRect.setAttribute("height", "100%");
945
+ bgRect.setAttribute("fill", "white");
946
+ clone.insertBefore(bgRect, clone.firstChild);
947
+
948
+ const svgData = new XMLSerializer().serializeToString(clone);
949
+ const svgBase64 = btoa(unescape(encodeURIComponent(svgData)));
950
+ const dataUrl = "data:image/svg+xml;base64," + svgBase64;
951
+
952
+ const img = new Image();
953
+ img.onload = () => {
954
+ const scale = 2;
955
+ const canvas = document.createElement("canvas");
956
+ canvas.width = width * scale;
957
+ canvas.height = height * scale;
958
+
959
+ const ctx = canvas.getContext("2d");
960
+ ctx.fillStyle = "white";
961
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
962
+ ctx.scale(scale, scale);
963
+ ctx.drawImage(img, 0, 0);
964
+
965
+ canvas.toBlob((blob) => {
966
+ const pngUrl = URL.createObjectURL(blob);
967
+ const a = document.createElement("a");
968
+ a.href = pngUrl;
969
+ a.download = "diagram.png";
970
+ document.body.appendChild(a);
971
+ a.click();
972
+ a.remove();
973
+ URL.revokeObjectURL(pngUrl);
974
+ }, "image/png");
975
+ };
976
+ img.onerror = (e) => {
977
+ console.error("PNG export failed:", e);
978
+ };
979
+ img.src = dataUrl;
980
+ };
981
+
897
982
  els.btns.copy.onclick = async () => {
898
983
  try {
899
984
  await navigator.clipboard.writeText(els.textarea.value);
@@ -47,13 +47,16 @@ def _render_task_metadata_block(
47
47
  if metadata.usage is not None:
48
48
  # Tokens: ↑37k ◎5k ↓907 ∿45k ⌗ 100
49
49
  token_text = Text()
50
+ input_tokens = max(metadata.usage.input_tokens - metadata.usage.cached_tokens, 0)
51
+ output_tokens = max(metadata.usage.output_tokens - metadata.usage.reasoning_tokens, 0)
52
+
50
53
  token_text.append("↑", style=ThemeKey.METADATA)
51
- token_text.append(format_number(metadata.usage.input_tokens), style=ThemeKey.METADATA)
54
+ token_text.append(format_number(input_tokens), style=ThemeKey.METADATA)
52
55
  if metadata.usage.cached_tokens > 0:
53
56
  token_text.append(" ◎", style=ThemeKey.METADATA)
54
57
  token_text.append(format_number(metadata.usage.cached_tokens), style=ThemeKey.METADATA)
55
58
  token_text.append(" ↓", style=ThemeKey.METADATA)
56
- token_text.append(format_number(metadata.usage.output_tokens), style=ThemeKey.METADATA)
59
+ token_text.append(format_number(output_tokens), style=ThemeKey.METADATA)
57
60
  if metadata.usage.reasoning_tokens > 0:
58
61
  token_text.append(" ∿", style=ThemeKey.METADATA)
59
62
  token_text.append(format_number(metadata.usage.reasoning_tokens), style=ThemeKey.METADATA)
@@ -609,6 +609,9 @@ class MarkdownStream:
609
609
 
610
610
  live_text_to_set: Text | None = None
611
611
  if not final and MARKDOWN_STREAM_LIVE_REPAINT_ENABLED and self._live_sink is not None:
612
+ # Only update live area after we have rendered at least one stable block
613
+ if not self._stable_rendered_lines:
614
+ return
612
615
  # When nothing is stable yet, we still want to show incremental output.
613
616
  # Apply the mark only for the first (all-live) frame so it stays anchored
614
617
  # to the first visible line of the full message.
@@ -270,10 +270,10 @@ def get_theme(theme: str | None = None) -> Themes:
270
270
  # ASSISTANT
271
271
  ThemeKey.ASSISTANT_MESSAGE_MARK.value: "bold",
272
272
  # METADATA
273
- ThemeKey.METADATA.value: palette.blue,
274
- ThemeKey.METADATA_DIM.value: "dim " + palette.blue,
275
- ThemeKey.METADATA_BOLD.value: "bold " + palette.blue,
276
- ThemeKey.METADATA_ITALIC.value: "italic " + palette.blue,
273
+ ThemeKey.METADATA.value: palette.grey1,
274
+ ThemeKey.METADATA_DIM.value: "dim " + palette.grey1,
275
+ ThemeKey.METADATA_BOLD.value: "bold " + palette.grey1,
276
+ ThemeKey.METADATA_ITALIC.value: "italic " + palette.grey1,
277
277
  # STATUS
278
278
  ThemeKey.STATUS_SPINNER.value: palette.blue,
279
279
  ThemeKey.STATUS_TEXT.value: palette.blue,
@@ -351,8 +351,8 @@ def get_theme(theme: str | None = None) -> Themes:
351
351
  # it is used while rendering assistant output.
352
352
  "markdown.thinking": "italic " + palette.grey2,
353
353
  "markdown.thinking.tag": palette.grey2,
354
- "markdown.code.border": palette.grey3,
355
- "markdown.code.fence": palette.grey3,
354
+ "markdown.code.border": palette.grey2,
355
+ "markdown.code.fence": palette.grey2,
356
356
  "markdown.code.fence.title": palette.grey1,
357
357
  # Used by ThinkingMarkdown when rendering `<thinking>` blocks.
358
358
  "markdown.code.block": palette.grey1,
@@ -379,8 +379,9 @@ def get_theme(theme: str | None = None) -> Themes:
379
379
  "markdown.strong": "italic " + palette.grey1,
380
380
  "markdown.code": palette.grey1 + " italic on " + palette.code_background,
381
381
  "markdown.code.block": palette.grey2,
382
- "markdown.code.fence": palette.grey3,
383
- "markdown.code.border": palette.grey3,
382
+ "markdown.code.fence": palette.grey2,
383
+ "markdown.code.fence.title": palette.grey1,
384
+ "markdown.code.border": palette.grey2,
384
385
  "markdown.thinking.tag": palette.grey2 + " dim",
385
386
  "markdown.h1": "bold reverse",
386
387
  "markdown.h1.border": palette.grey3,
@@ -26,38 +26,3 @@ def normalize_thinking_content(content: str) -> str:
26
26
  text = text.replace("**\n\n", "** \n")
27
27
 
28
28
  return text
29
-
30
-
31
- def extract_last_bold_header(text: str) -> str | None:
32
- """Extract the latest complete bold header ("**…**") from text.
33
-
34
- We treat a bold segment as a "header" only if it appears at the beginning
35
- of a line (ignoring leading whitespace). This avoids picking up incidental
36
- emphasis inside paragraphs.
37
-
38
- Returns None if no complete bold segment is available yet.
39
- """
40
-
41
- last: str | None = None
42
- i = 0
43
- while True:
44
- start = text.find("**", i)
45
- if start < 0:
46
- break
47
-
48
- line_start = text.rfind("\n", 0, start) + 1
49
- if text[line_start:start].strip():
50
- i = start + 2
51
- continue
52
-
53
- end = text.find("**", start + 2)
54
- if end < 0:
55
- break
56
-
57
- inner = " ".join(text[start + 2 : end].split())
58
- if inner and "\n" not in inner:
59
- last = inner
60
-
61
- i = end + 2
62
-
63
- return last
@@ -4,6 +4,7 @@ from typing import Any, cast
4
4
 
5
5
  from rich import box
6
6
  from rich.console import Group, RenderableType
7
+ from rich.padding import Padding
7
8
  from rich.panel import Panel
8
9
  from rich.style import Style
9
10
  from rich.text import Text
@@ -166,7 +167,6 @@ def render_bash_tool_call(arguments: str) -> RenderableType:
166
167
  if isinstance(command, str) and command.strip():
167
168
  cmd_str = command.strip()
168
169
  highlighted = highlight_bash_command(cmd_str)
169
- highlighted.stylize(ThemeKey.CODE_BACKGROUND)
170
170
 
171
171
  display_line_count = len(highlighted.plain.splitlines())
172
172
 
@@ -189,7 +189,8 @@ def render_bash_tool_call(arguments: str) -> RenderableType:
189
189
  highlighted.append(f" {timeout_ms // 1000}s", style=ThemeKey.TOOL_TIMEOUT)
190
190
  else:
191
191
  highlighted.append(f" {timeout_ms}ms", style=ThemeKey.TOOL_TIMEOUT)
192
- return _render_tool_call_tree(mark=MARK_BASH, tool_name=tool_name, details=highlighted)
192
+ padded = Padding(highlighted, pad=0, style=ThemeKey.CODE_BACKGROUND, expand=False)
193
+ return _render_tool_call_tree(mark=MARK_BASH, tool_name=tool_name, details=padded)
193
194
  else:
194
195
  summary = Text("", ThemeKey.TOOL_PARAM)
195
196
  if isinstance(timeout_ms, int):
@@ -25,7 +25,7 @@ def render_at_and_skill_patterns(
25
25
  available_skill_names: set[str] | None = None,
26
26
  ) -> Text:
27
27
  """Render text with highlighted @file and $skill patterns."""
28
- result = Text(text, style=other_style)
28
+ result = Text(text, style=other_style, overflow="fold")
29
29
  for match in INLINE_RENDER_PATTERN.finditer(text):
30
30
  skill_name = match.group(1)
31
31
  if skill_name is None:
@@ -79,6 +79,7 @@ def render_user_input(content: str) -> RenderableType:
79
79
  render_at_and_skill_patterns(splits[1], available_skill_names=available_skill_names)
80
80
  if len(splits) > 1
81
81
  else Text(""),
82
+ overflow="fold",
82
83
  )
83
84
  renderables.append(line_text)
84
85
  continue
@@ -100,4 +100,4 @@ class TUIDisplay(DisplayABC):
100
100
  with contextlib.suppress(Exception):
101
101
  self._renderer.spinner_stop()
102
102
  with contextlib.suppress(Exception):
103
- self._renderer.stop_bottom_live()
103
+ self._renderer.stop_bottom_live()
@@ -358,7 +358,6 @@ class PromptToolkitInput(InputProviderABC):
358
358
  return []
359
359
  return [
360
360
  ("fg:ansigreen", " bash mode"),
361
- ("fg:ansibrightblack", " (type ! at start; backspace first char to exit)"),
362
361
  ]
363
362
 
364
363
  def _setup_model_picker(self) -> None:
@@ -50,7 +50,6 @@ from klaude_code.tui.commands import (
50
50
  )
51
51
  from klaude_code.tui.components.rich import status as r_status
52
52
  from klaude_code.tui.components.rich.theme import ThemeKey
53
- from klaude_code.tui.components.thinking import extract_last_bold_header, normalize_thinking_content
54
53
  from klaude_code.tui.components.tools import get_task_active_form, get_tool_active_form, is_sub_agent_tool
55
54
 
56
55
  # Tools that complete quickly and don't benefit from streaming activity display.
@@ -293,7 +292,6 @@ class _SessionState:
293
292
  assistant_stream_active: bool = False
294
293
  thinking_stream_active: bool = False
295
294
  assistant_char_count: int = 0
296
- thinking_tail: str = ""
297
295
  task_active: bool = False
298
296
 
299
297
  @property
@@ -304,15 +302,6 @@ class _SessionState:
304
302
  def should_show_sub_agent_thinking_header(self) -> bool:
305
303
  return bool(self.sub_agent_state and self.sub_agent_state.sub_agent_type == tools.IMAGE_GEN)
306
304
 
307
- @property
308
- def should_extract_reasoning_header(self) -> bool:
309
- """Gemini and GPT-5 models use markdown bold headers in thinking."""
310
- return False # Temporarily disabled for all models
311
- if self.model_id is None:
312
- return False
313
- model_lower = self.model_id.lower()
314
- return "gemini" in model_lower or "gpt-5" in model_lower
315
-
316
305
  def should_skip_tool_activity(self, tool_name: str) -> bool:
317
306
  """Check if tool activity should be skipped for non-streaming models."""
318
307
  if self.model_id is None:
@@ -335,6 +324,11 @@ class DisplayStateMachine:
335
324
  self._primary_session_id: str | None = None
336
325
  self._spinner = SpinnerStatusState()
337
326
 
327
+ def _reset_sessions(self) -> None:
328
+ self._sessions = {}
329
+ self._primary_session_id = None
330
+ self._spinner.reset()
331
+
338
332
  def _session(self, session_id: str) -> _SessionState:
339
333
  existing = self._sessions.get(session_id)
340
334
  if existing is not None:
@@ -367,7 +361,9 @@ class DisplayStateMachine:
367
361
  return self._spinner_update_commands()
368
362
 
369
363
  def begin_replay(self) -> list[RenderCommand]:
370
- self._spinner.reset()
364
+ # Replay is a full rebuild of the terminal view; clear session state so primary-session
365
+ # routing is recalculated from the replayed TaskStartEvent.
366
+ self._reset_sessions()
371
367
  return [SpinnerStop(), PrintBlankLine()]
372
368
 
373
369
  def end_replay(self) -> list[RenderCommand]:
@@ -386,6 +382,13 @@ class DisplayStateMachine:
386
382
 
387
383
  match event:
388
384
  case events.WelcomeEvent() as e:
385
+ # WelcomeEvent marks (or reaffirms) the current interactive session.
386
+ # If the session id changes (e.g., /clear creates a new session), clear
387
+ # routing state so subsequent streamed events are not dropped.
388
+ if self._primary_session_id is not None and self._primary_session_id != e.session_id:
389
+ self._reset_sessions()
390
+ s = self._session(e.session_id)
391
+ self._primary_session_id = e.session_id
389
392
  cmds.append(RenderWelcome(e))
390
393
  return cmds
391
394
 
@@ -431,7 +434,12 @@ class DisplayStateMachine:
431
434
  s.model_id = e.model_id
432
435
  s.task_active = True
433
436
  if not s.is_sub_agent:
434
- self._set_primary_if_needed(e.session_id)
437
+ # Keep primary session tracking in sync even if the session id changes
438
+ # during the process lifetime (e.g., /clear).
439
+ if is_replay:
440
+ self._set_primary_if_needed(e.session_id)
441
+ else:
442
+ self._primary_session_id = e.session_id
435
443
  if not is_replay:
436
444
  cmds.append(TaskClockStart())
437
445
 
@@ -487,9 +495,8 @@ class DisplayStateMachine:
487
495
  if not self._is_primary(e.session_id):
488
496
  return []
489
497
  s.thinking_stream_active = True
490
- s.thinking_tail = ""
491
498
  # Ensure the status reflects that reasoning has started even
492
- # before we receive any deltas (or a bold header).
499
+ # before we receive any deltas.
493
500
  if not is_replay:
494
501
  self._spinner.set_reasoning_status(STATUS_THINKING_TEXT)
495
502
  cmds.append(StartThinkingStream(session_id=e.session_id))
@@ -507,16 +514,6 @@ class DisplayStateMachine:
507
514
  if not self._is_primary(e.session_id):
508
515
  return []
509
516
  cmds.append(AppendThinking(session_id=e.session_id, content=e.content))
510
-
511
- # Update reasoning status for spinner (based on bounded tail).
512
- # Only extract headers for models that use markdown bold headers in thinking.
513
- if not is_replay and s.should_extract_reasoning_header:
514
- s.thinking_tail = (s.thinking_tail + e.content)[-8192:]
515
- header = extract_last_bold_header(normalize_thinking_content(s.thinking_tail))
516
- if header:
517
- self._spinner.set_reasoning_status(header)
518
- cmds.extend(self._spinner_update_commands())
519
-
520
517
  return cmds
521
518
 
522
519
  case events.ThinkingEndEvent() as e:
@@ -721,6 +718,29 @@ class DisplayStateMachine:
721
718
  case events.TaskFinishEvent() as e:
722
719
  s.task_active = False
723
720
  cmds.append(RenderTaskFinish(e))
721
+
722
+ # Defensive: finalize any open streams so buffered markdown is flushed.
723
+ if s.thinking_stream_active:
724
+ s.thinking_stream_active = False
725
+ cmds.append(EndThinkingStream(session_id=e.session_id))
726
+ if s.assistant_stream_active:
727
+ s.assistant_stream_active = False
728
+ cmds.append(EndAssistantStream(session_id=e.session_id))
729
+
730
+ # Rare providers / edge cases may complete a turn without emitting any
731
+ # assistant deltas (or without the display consuming them). In that case,
732
+ # fall back to rendering the final task result to avoid a "blank" turn.
733
+ if (
734
+ not is_replay
735
+ and not s.is_sub_agent
736
+ and not e.has_structured_output
737
+ and s.assistant_char_count == 0
738
+ and e.task_result.strip()
739
+ ):
740
+ cmds.append(StartAssistantStream(session_id=e.session_id))
741
+ cmds.append(AppendAssistant(session_id=e.session_id, content=e.task_result))
742
+ cmds.append(EndAssistantStream(session_id=e.session_id))
743
+
724
744
  if not s.is_sub_agent and not is_replay:
725
745
  cmds.append(TaskClockClear())
726
746
  self._spinner.reset()
@@ -349,7 +349,11 @@ class TUICommandRenderer:
349
349
  if pad_lines:
350
350
  stream = Padding(stream, (0, 0, pad_lines, 0))
351
351
  stream_part = stream
352
- gap_part = Text(" ") if (self._spinner_visible and self._bash_stream_active) else Group()
352
+ gap_part = (
353
+ Text(" ")
354
+ if (self._spinner_visible and (self._bash_stream_active or self._stream_renderable))
355
+ else Group()
356
+ )
353
357
 
354
358
  status_part: RenderableType = SingleLine(self._status_spinner) if self._spinner_visible else Group()
355
359
  return Group(stream_part, gap_part, status_part)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 2.10.0
3
+ Version: 2.10.1
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -1,7 +1,7 @@
1
1
  klaude_code/.DS_Store,sha256=cLWFbSgdN0bXEd3_tz93BJSposEPafUBqSr7t-3lPbA,6148
2
2
  klaude_code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  klaude_code/app/__init__.py,sha256=7mgWpN9SFDqe8AW44bBn9M19nVsBcZURrsGB_8l2hrU,264
4
- klaude_code/app/runtime.py,sha256=MEfD6asbwRpZLyf0jUXAenDPufBZEnA3Trh6QnEUniQ,6031
4
+ klaude_code/app/runtime.py,sha256=d06L6O0uyExL-_qEVSKqekk_tUBr6hAzV9jT8As6eSY,6180
5
5
  klaude_code/auth/AGENTS.md,sha256=5ObIfgMfUDuNBKykK6kikRSEvCxDt5fO0-ySVaLVDW0,8467
6
6
  klaude_code/auth/__init__.py,sha256=LhGS2P80Ci_DeaqxVueknDIj-Ded4OFQdNmFHekXNY8,1106
7
7
  klaude_code/auth/antigravity/__init__.py,sha256=Lv37yKg7CLzoQss2Jho-jtrGiU-zUCa7W1w3eDWmR0o,610
@@ -26,11 +26,11 @@ klaude_code/cli/config_cmd.py,sha256=7BmZpKeiO24mKKLKGO46WvSQzSaNwuZ3KtCV4GH-Yh0
26
26
  klaude_code/cli/cost_cmd.py,sha256=PofksXj7ZmalaRfxAHCxtUBxEc7tfI-sIER_9GRA1CU,16604
27
27
  klaude_code/cli/debug.py,sha256=vEHOjObhrIHDAXk3q6cOgeW2NZxCx5AWM1rJ6FiJnVU,1901
28
28
  klaude_code/cli/list_model.py,sha256=GYznb88rvubnUCMvW-D1r3aGVWQB4-DzvsTjBSHjOUw,16168
29
- klaude_code/cli/main.py,sha256=Z0jCfGvMH7iIlmpjcPsCOHgqDFEcEl3LkzIQr9fUHNM,12772
29
+ klaude_code/cli/main.py,sha256=bQijkLDTYtjFUdU1t-dGCzOilo7mcotIQefleaF9or8,13072
30
30
  klaude_code/cli/self_update.py,sha256=1xdG9ifvRZQDSx6RAtSSgXmw9hZNXMLvqC2zu4bS-GY,2622
31
31
  klaude_code/config/__init__.py,sha256=Qe1BeMekBfO2-Zd30x33lB70hdM1QQZGrp4DbWSQ-II,353
32
32
  klaude_code/config/assets/__init__.py,sha256=uMUfmXT3I-gYiI-HVr1DrE60mx5cY1o8V7SYuGqOmvY,32
33
- klaude_code/config/assets/builtin_config.yaml,sha256=9ozI1jwqXExq48Trs0ayVNX8WAAkOh3qC5R1kUkP_Rw,9093
33
+ klaude_code/config/assets/builtin_config.yaml,sha256=EYGgBMAVtgUKGHZcfkm4sCfSB1-fBx83q10MGVnNz8I,9121
34
34
  klaude_code/config/builtin_config.py,sha256=OG5VERUHo3tSojgFXfNDV6pAHNOh3kO-xFHpvTr-cpc,1786
35
35
  klaude_code/config/config.py,sha256=otBvsUkvI-2fpZzx9fO6SPnCek7FI7kufvAnGIQqTz8,27084
36
36
  klaude_code/config/model_matcher.py,sha256=3IlLU5h3NDh_bURbCW-PV027C3irG3hyitwj1cj99Ig,6179
@@ -39,7 +39,7 @@ klaude_code/config/thinking.py,sha256=5uVM0cFUJZBBsBGGdPG-tjdiNwZ-GFeWOBBWIdSPFv
39
39
  klaude_code/const.py,sha256=VCK3HgZJZO6jcYz6U2rcHS7W-n4oyKYg9AC6eTB4HIQ,11575
40
40
  klaude_code/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  klaude_code/core/agent.py,sha256=GrIg22nfoq1c90UHyEfU_bh46vtXTCo4bLezb-3mGNo,4120
42
- klaude_code/core/agent_profile.py,sha256=AoBpOC8rGqyJW4DGCzejQAq3P1497n3NrCayIGIOQBY,10632
42
+ klaude_code/core/agent_profile.py,sha256=8fEiRI2emEFVlwsCEtNaZ90UUp1A7MKhzOnzQK1IOGI,11507
43
43
  klaude_code/core/bash_mode.py,sha256=BUy2_uOcJ8bO89t_QCwtw6GlHt7vd1t62sN5iWk-UuQ,9250
44
44
  klaude_code/core/compaction/AGENTS.md,sha256=KZR5lxe4jVAbT5K9PxbZcHWI1UwsppbGmxIfCdHYr7Q,3684
45
45
  klaude_code/core/compaction/__init__.py,sha256=CvidYx3sX0IZAa4pifX9jrQSkg4Nib7PKrcaOHswF60,329
@@ -62,7 +62,7 @@ klaude_code/core/prompts/prompt-gemini.md,sha256=JjE1tHSByGKJzjn4Gpj1zekT7ry1Yqb
62
62
  klaude_code/core/prompts/prompt-minimal.md,sha256=6-ZmQQkE3f92W_3V2wS7ocB13wLog1_UojCjZG0K4v8,1559
63
63
  klaude_code/core/prompts/prompt-sub-agent-explore.md,sha256=21kFodjhvN0L-c_ZFo4yVhJOyzfgES-Dty9Vz_Ew9q8,2629
64
64
  klaude_code/core/prompts/prompt-sub-agent-image-gen.md,sha256=tXYKSzFd04OiC0dmVO9suMKeD5f9qo_4NsvqGo7irfI,78
65
- klaude_code/core/prompts/prompt-sub-agent-web.md,sha256=UwrO5M_jPUbee_8lL7gB-2VFFLxvzEejluXDkMzmR5A,3625
65
+ klaude_code/core/prompts/prompt-sub-agent-web.md,sha256=xi9nyk8k0_64muL2RBMkrCdli5elXALjhKAsRO3qr-U,3627
66
66
  klaude_code/core/prompts/prompt-sub-agent.md,sha256=dmmdsOenbAOfqG6FmdR88spOLZkXmntDBs-cmZ9DN_g,897
67
67
  klaude_code/core/reminders.py,sha256=Dar0GqyOgiZiv0VzrzYOGM22ViSWJUaV12Ssdtcdjlo,21720
68
68
  klaude_code/core/task.py,sha256=uXNg_SxVnp6nFwDmWl8LjhG0HDv7_3P83zAV6dR2gcQ,20125
@@ -80,7 +80,7 @@ klaude_code/core/tool/file/read_tool.md,sha256=_0yftoexOCwdJBKKUxNfxuEXixJipmhtT
80
80
  klaude_code/core/tool/file/read_tool.py,sha256=JOcARJqZ5RQGFGBtBAzDTzFOCXnR8PXkHg04I3-yacc,14262
81
81
  klaude_code/core/tool/file/write_tool.md,sha256=CNnYgtieUasuHdpXLDpTEsqe492Pf7v75M4RQ3oIer8,613
82
82
  klaude_code/core/tool/file/write_tool.py,sha256=R2gWJp8kDOm_gUMbb8F6Z-SrEf8-8Y__9KaMmaQaQVg,5674
83
- klaude_code/core/tool/offload.py,sha256=hxc-up--3KdIvjoslg7FvUek-8wUUSHr3QcGfyJaSQg,11557
83
+ klaude_code/core/tool/offload.py,sha256=5-Th1CXRhRTaysOyvfoi9bpOVjZT1EMn3uwqieyDFZY,11574
84
84
  klaude_code/core/tool/report_back_tool.py,sha256=SkuRhfLpVwTOSpIj7XwYfGDNBp8YsCUNXieXDkafS2E,3381
85
85
  klaude_code/core/tool/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
86
  klaude_code/core/tool/shell/bash_tool.md,sha256=VqDfwZOy3Ok1t1rEPKEEkN4Rf_1ZFZzDFzpmOstH2Xo,52
@@ -103,11 +103,11 @@ klaude_code/core/tool/tool_runner.py,sha256=yj9DpXSMd-u8BOAiFsVVxUbB-CEFS8D_Vcv3
103
103
  klaude_code/core/tool/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
104
  klaude_code/core/tool/web/mermaid_tool.md,sha256=vvPSWxbY3P_cBpHh6AM8Je9JJoMY4FBTJzoteEkwuDU,2095
105
105
  klaude_code/core/tool/web/mermaid_tool.py,sha256=FELwyLBzFdHhkimGee31_qZlrZq2vTzIaFTsp6qeGus,2715
106
- klaude_code/core/tool/web/web_fetch_tool.md,sha256=i0IwsZ6r9vAQeCpwDBtEGrWmHPzZk_XE_CsqvjE4aUA,498
107
- klaude_code/core/tool/web/web_fetch_tool.py,sha256=jXbJTgpI_RvyXy5ac8qIrC-AKOUX1fJ3TpqXq_BfkS4,9596
106
+ klaude_code/core/tool/web/web_fetch_tool.md,sha256=tpLnWd9miepnS1E3vUumaEHLrUoVgZpbEAocuPvFt7M,499
107
+ klaude_code/core/tool/web/web_fetch_tool.py,sha256=THMbzs-aHI6ST9NU0kNUtJCz9uhclDB7v8S9814dwnI,9597
108
108
  klaude_code/core/tool/web/web_search_tool.md,sha256=l5gGPx-fXHFel1zLBljm8isy9pwEYXGrq5cFzzw1VBw,1135
109
109
  klaude_code/core/tool/web/web_search_tool.py,sha256=ljkgXxP6L5nJnbYB_IOUtPUN9zA_h5hBD55lhNAja08,4293
110
- klaude_code/core/turn.py,sha256=YKzjlaKggN9NdSvPvrWfVvR84mI8PXofzeqC_fmnrCs,18902
110
+ klaude_code/core/turn.py,sha256=TK4-ZGmRo_qa21XRklGfEMnfhFGR20wnKjnvlf31HBQ,18882
111
111
  klaude_code/llm/__init__.py,sha256=b4AsqnrMIs0a5qR_ti6rZcHwFzAReTwOW96EqozEoSo,287
112
112
  klaude_code/llm/anthropic/__init__.py,sha256=PWETvaeNAAX3ue0ww1uRUIxTJG0RpWiutkn7MlwKxBs,67
113
113
  klaude_code/llm/anthropic/client.py,sha256=RpYw4UQnhLzAsp6i-FU7cDW4deqngdAoQaTPGnCeO5U,17346
@@ -167,7 +167,7 @@ klaude_code/session/selector.py,sha256=snBpnz9UQCe_0K8HttSGCJECCE4YEzpWs_Fdmk2P9
167
167
  klaude_code/session/session.py,sha256=AL-2oNggPf7PTnNthFdyiI233ySWdCcOqcxufkqrvwE,29373
168
168
  klaude_code/session/store.py,sha256=f_Ve6uMX1s-yH3jqiDWPULoLnab07QcFA04b3PD0ehE,6306
169
169
  klaude_code/session/templates/export_session.html,sha256=ekRt1zGePqT2lOYSPgdNlDjsOemM2r7FVB6X8nBrC00,137452
170
- klaude_code/session/templates/mermaid_viewer.html,sha256=Y_wEWFm4mKWpfAz3YMis5DdLEkhw_2d8CpU6jbvGZow,27842
170
+ klaude_code/session/templates/mermaid_viewer.html,sha256=2e5q0YpKpqB2FeFdH5t-BxJKtDDGrKKz8z1hmKSZ93M,30991
171
171
  klaude_code/skill/.DS_Store,sha256=zy9qIqi2YLGzlZwHNM4oAX8rDoNTg9yxdo22PJOwupg,6148
172
172
  klaude_code/skill/__init__.py,sha256=yeWeCfRGPOhT4mx_pjdo4fLondQ_Vx0edBtnFusLhls,839
173
173
  klaude_code/skill/assets/.DS_Store,sha256=1lFlJ5EFymdzGAUAaI30vcaaLHt3F1LwpG7xILf9jsM,6148
@@ -208,21 +208,21 @@ klaude_code/tui/components/developer.py,sha256=m6gcnLyLoSSw3wpwYQZ_yzaT9zgXRgNzT
208
208
  klaude_code/tui/components/diffs.py,sha256=vwllnYBxC5xGjfKU3uIkCjcupr9nrjRjvvj0tg0_MQA,3085
209
209
  klaude_code/tui/components/errors.py,sha256=fSojNfRceB6eE7cyJHfwGt5Ru0OYp63fCJ-W6-3SSYs,799
210
210
  klaude_code/tui/components/mermaid_viewer.py,sha256=zI1FBuX6Ionx38KqkzhOIQ9tFzd7REPbjW1iqSiNrec,3086
211
- klaude_code/tui/components/metadata.py,sha256=iG6V3-rHj7eKACMa57-zORIy0FJfhAKLVXgfmGoZI6A,7130
211
+ klaude_code/tui/components/metadata.py,sha256=JzHMi3fr_YWQmachSRukBTYO3iHvPFAXaA3f2SRyD54,7286
212
212
  klaude_code/tui/components/rich/__init__.py,sha256=zEZjnHR3Fnv_sFMxwIMjoJfwDoC4GRGv3lHJzAGRq_o,236
213
213
  klaude_code/tui/components/rich/cjk_wrap.py,sha256=eMqBxftUtll7zrytUb9WtJ6naYLyax0W4KJRpGwWulM,7602
214
214
  klaude_code/tui/components/rich/code_panel.py,sha256=SOdyfHBZNB4gAWIbnN_enhHB1EWxw8Hxiafx6yjwdJo,5544
215
215
  klaude_code/tui/components/rich/live.py,sha256=xiMT6dPsxM_jaazddKrV9CMJQWwpe2t9OdjffHvo1JU,2821
216
- klaude_code/tui/components/rich/markdown.py,sha256=Ps6KaSwArqY5IVW8J2ShkqYg9vOGMnlfTJyZQOkXmo8,25120
216
+ klaude_code/tui/components/rich/markdown.py,sha256=vas08cxz8fEU2PlTUNrgmF-zIXtFoMxP-Jefc8FSGuE,25276
217
217
  klaude_code/tui/components/rich/quote.py,sha256=u6sBmGdp0ckaZLw_XgJk7iHW4zxnWikUaB3GX2tkhlM,5375
218
218
  klaude_code/tui/components/rich/status.py,sha256=hSvMwEguF2DfHH3ISR0bmDg58zAnM3CTJLcRff_rtrg,14791
219
- klaude_code/tui/components/rich/theme.py,sha256=Bioy3rbR_6M5XJFg3sHD_aNuwF7eJtZWHLij0-8tDQU,17020
219
+ klaude_code/tui/components/rich/theme.py,sha256=cp7PrhxIgOLu_AjHBOf3wCZewzngOAZDFQQmiO0sAbY,17084
220
220
  klaude_code/tui/components/sub_agent.py,sha256=8XTWsTi9mfbNLMD8SZ__nZQmBf81rW-NWpuOT-sFbv8,4723
221
- klaude_code/tui/components/thinking.py,sha256=zxeELXVoU0zgN_IrRHSNqjCHfpt5uX7_U-rXpd3RktI,1857
222
- klaude_code/tui/components/tools.py,sha256=Zdfj1HLFjGnFtQOWcb4W4zyR3AI5h9QUd4om116uL6M,27262
223
- klaude_code/tui/components/user_input.py,sha256=U4gdkCqV886PSBJ0KBqc3a_8FXdpEBAXUZEF1_123Dw,3609
221
+ klaude_code/tui/components/thinking.py,sha256=yVzY7BbcdDwB4XKi9i2sp3cKREirvmlMiEID74b-5_0,955
222
+ klaude_code/tui/components/tools.py,sha256=MqW-_a4gtMnCR5N8APJYtN2TfSvuUdvo2WFEGm3Qa9A,27327
223
+ klaude_code/tui/components/user_input.py,sha256=fYvdoc3gMyv90l2sQvSs4ha0wILu71rBAcwbzQPMMVc,3659
224
224
  klaude_code/tui/components/welcome.py,sha256=Ahkhg0dsSqy17pKLOp_5UZWn9vysr68T3Y-jB40yWsA,5303
225
- klaude_code/tui/display.py,sha256=bPWhDNZ3R5InQIz0yThLRKi7RJvLx8zcmJoJgyzG5MM,3932
225
+ klaude_code/tui/display.py,sha256=VbBmNjGxp6R4oLjC0FrjXkr0INWSjfXlWq1mSVFGyMU,3933
226
226
  klaude_code/tui/input/AGENTS.md,sha256=2RBLz7H0JbUJv6OBzeadLOlGUF5EBqvtwTGBf6nZuN0,1633
227
227
  klaude_code/tui/input/__init__.py,sha256=wLbjqBrvP6fmbGtbKe9Wp12yxhse0faVLOxtoWua_1E,353
228
228
  klaude_code/tui/input/completers.py,sha256=MJO1nBq0V5jDbGw_o4Ab5WLVD1ns5plJRI3cIYnGfHs,33154
@@ -230,9 +230,9 @@ klaude_code/tui/input/drag_drop.py,sha256=oyKtrHCyUiGiMLEXpsDTnTnAKJ1_xrvVkrASOi
230
230
  klaude_code/tui/input/images.py,sha256=ft2AaOg1Figdm1t_NNoBCGdp20silYXGw-m9XKDd9GU,6996
231
231
  klaude_code/tui/input/key_bindings.py,sha256=Gpc-VhQh-h431cnetheV0HF9QGcFyy82QrHWUAYF-LA,26633
232
232
  klaude_code/tui/input/paste.py,sha256=kELg5jC0WdBXWHJUsEjIhZ67KCvHMbN1XzyGmevVSNM,1888
233
- klaude_code/tui/input/prompt_toolkit.py,sha256=eftqR8T8bVVv40m_UnjymFl_uzA8mLzeMy4t89MIZKY,30751
234
- klaude_code/tui/machine.py,sha256=qSxVAYFXhNbwBjgCDYwdvARu2rP17L5aQ4oPqvWtSGA,31311
235
- klaude_code/tui/renderer.py,sha256=ylkCiBbL4H9WXZqRcuEwn5lYRH7fXJ5KweyXrPR8rgk,34543
233
+ klaude_code/tui/input/prompt_toolkit.py,sha256=aE1pVK1G96DWERc2APIXq4WmSPOdJDRHTgnyyZXp_u4,30663
234
+ klaude_code/tui/machine.py,sha256=iRTBNx22eozmT9gyya9QbpDDcmqst07bUAa2vWMDZAA,32482
235
+ klaude_code/tui/renderer.py,sha256=E9SSuxWlQDMA2_4ENZHpwfB54ZVpkFMJYPe_WQSzq0E,34652
236
236
  klaude_code/tui/runner.py,sha256=ZADAH28Iu1DU-KDCggEyvJiM_LTbN1sjPEaQsuBNTbc,13111
237
237
  klaude_code/tui/terminal/__init__.py,sha256=GIMnsEcIAGT_vBHvTlWEdyNmAEpruyscUA6M_j3GQZU,1412
238
238
  klaude_code/tui/terminal/color.py,sha256=6SJR2RA8cqJINNoRz65w0HL3x9g46ydIvDOGWMeNnQU,7195
@@ -250,7 +250,7 @@ klaude_code/ui/debug_mode.py,sha256=ZvqbOx4c_rUerMbEZzOfcbNf9leqEDFjqJUlALtzF9Y,
250
250
  klaude_code/ui/terminal/__init__.py,sha256=5OeAzr994r8-peWsLON0iXsAvJ2pexwMp36JY7FKGDc,179
251
251
  klaude_code/ui/terminal/title.py,sha256=lCk1dKk7fIe5Fb-FRU9P4ktVEfBmT3ac3wICYmC4mGE,1229
252
252
  klaude_code/update.py,sha256=QER816AZe9u3RhRvP0Z37Jh2Ch5RLy9PREyDsI0e1dA,4480
253
- klaude_code-2.10.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
254
- klaude_code-2.10.0.dist-info/entry_points.txt,sha256=kkXIXedaTOtjXPr2rVjRVVXZYlFUcBHELaqmyVlWUFA,92
255
- klaude_code-2.10.0.dist-info/METADATA,sha256=K0AELbdxgcZPuvXZFY2xXqA6__nkIV_NzF7NXfhMUSU,10120
256
- klaude_code-2.10.0.dist-info/RECORD,,
253
+ klaude_code-2.10.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
254
+ klaude_code-2.10.1.dist-info/entry_points.txt,sha256=kkXIXedaTOtjXPr2rVjRVVXZYlFUcBHELaqmyVlWUFA,92
255
+ klaude_code-2.10.1.dist-info/METADATA,sha256=zM4Cjq5SylCPMJsKpmsr0b0eIknIojYMQPSE3ypB_6U,10120
256
+ klaude_code-2.10.1.dist-info/RECORD,,