klaude-code 1.2.24__py3-none-any.whl → 1.2.26__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.
@@ -1,4 +1,3 @@
1
- # copy from https://github.com/Aider-AI/aider/blob/main/aider/mdstream.py
2
1
  from __future__ import annotations
3
2
 
4
3
  import contextlib
@@ -7,13 +6,15 @@ import time
7
6
  from collections.abc import Callable
8
7
  from typing import Any, ClassVar
9
8
 
10
- from rich.console import Console, ConsoleOptions, Group, RenderableType, RenderResult
11
- from rich.live import Live
12
- from rich.markdown import CodeBlock, Heading, Markdown, MarkdownElement
9
+ from markdown_it import MarkdownIt
10
+ from markdown_it.token import Token
11
+ from rich import box
12
+ from rich.console import Console, ConsoleOptions, RenderableType, RenderResult
13
+ from rich.markdown import CodeBlock, Heading, Markdown, MarkdownElement, TableElement
13
14
  from rich.rule import Rule
14
- from rich.spinner import Spinner
15
15
  from rich.style import Style, StyleType
16
16
  from rich.syntax import Syntax
17
+ from rich.table import Table
17
18
  from rich.text import Text
18
19
  from rich.theme import Theme
19
20
 
@@ -53,6 +54,24 @@ class Divider(MarkdownElement):
53
54
  yield Rule(style=style, characters="-")
54
55
 
55
56
 
57
+ class MinimalHeavyHeadTable(TableElement):
58
+ """A table element with MINIMAL_HEAVY_HEAD box style."""
59
+
60
+ def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
61
+ table = Table(box=box.MARKDOWN)
62
+
63
+ if self.header is not None and self.header.row is not None:
64
+ for column in self.header.row.cells:
65
+ table.add_column(column.content)
66
+
67
+ if self.body is not None:
68
+ for row in self.body.rows:
69
+ row_content = [element.content for element in row.cells]
70
+ table.add_row(*row_content)
71
+
72
+ yield table
73
+
74
+
56
75
  class LeftHeading(Heading):
57
76
  """A heading class that renders left-justified."""
58
77
 
@@ -64,7 +83,7 @@ class LeftHeading(Heading):
64
83
  yield h1_text
65
84
  elif self.tag == "h2":
66
85
  text.stylize(Style(bold=True, underline=False))
67
- yield Rule(title=text, characters="·", style="markdown.h2.border", align="left")
86
+ yield text
68
87
  else:
69
88
  yield text
70
89
 
@@ -78,6 +97,7 @@ class NoInsetMarkdown(Markdown):
78
97
  "code_block": NoInsetCodeBlock,
79
98
  "heading_open": LeftHeading,
80
99
  "hr": Divider,
100
+ "table_open": MinimalHeavyHeadTable,
81
101
  }
82
102
 
83
103
 
@@ -90,23 +110,28 @@ class ThinkingMarkdown(Markdown):
90
110
  "code_block": ThinkingCodeBlock,
91
111
  "heading_open": LeftHeading,
92
112
  "hr": Divider,
113
+ "table_open": MinimalHeavyHeadTable,
93
114
  }
94
115
 
95
116
 
96
117
  class MarkdownStream:
97
- """Streaming markdown renderer that progressively displays content with a live updating window.
118
+ """Block-based streaming Markdown renderer.
98
119
 
99
- Uses rich.console and rich.live to render markdown content with smooth scrolling
100
- and partial updates. Maintains a sliding window of visible content while streaming
101
- in new markdown text.
120
+ This renderer is optimized for terminal UX:
121
+
122
+ - Stable area: only prints *completed* Markdown blocks to scrollback (append-only).
123
+ - Live area: continuously repaints only the final *possibly incomplete* block.
124
+
125
+ Block boundaries are computed with `MarkdownIt("commonmark")` (token maps / top-level tokens).
126
+ Rendering is done with Rich Markdown (customizable via `markdown_class`).
102
127
  """
103
128
 
104
129
  def __init__(
105
130
  self,
131
+ console: Console,
106
132
  mdargs: dict[str, Any] | None = None,
107
133
  theme: Theme | None = None,
108
- console: Console | None = None,
109
- spinner: Spinner | None = None,
134
+ live_sink: Callable[[RenderableType | None], None] | None = None,
110
135
  mark: str | None = None,
111
136
  mark_style: StyleType | None = None,
112
137
  left_margin: int = 0,
@@ -125,24 +150,23 @@ class MarkdownStream:
125
150
  right_margin (int, optional): Number of columns to reserve on the right side
126
151
  markdown_class: Markdown class to use for rendering (defaults to NoInsetMarkdown)
127
152
  """
128
- self.printed: list[str] = [] # Stores lines that have already been printed
153
+ self._stable_rendered_lines: list[str] = []
154
+ self._stable_source_line_count: int = 0
129
155
 
130
156
  if mdargs:
131
157
  self.mdargs: dict[str, Any] = mdargs
132
158
  else:
133
159
  self.mdargs = {}
134
160
 
135
- # Defer Live creation until the first update.
136
- self.live: Live | None = None
161
+ self._live_sink = live_sink
137
162
 
138
163
  # Streaming control
139
164
  self.when: float = 0.0 # Timestamp of last update
140
165
  self.min_delay: float = 1.0 / 20 # Minimum time between updates (20fps)
141
- self.live_window: int = const.MARKDOWN_STREAM_LIVE_WINDOW
166
+ self._parser: MarkdownIt = MarkdownIt("commonmark")
142
167
 
143
168
  self.theme = theme
144
169
  self.console = console
145
- self.spinner: Spinner | None = spinner
146
170
  self.mark: str | None = mark
147
171
  self.mark_style: StyleType | None = mark_style
148
172
 
@@ -154,9 +178,117 @@ class MarkdownStream:
154
178
  @property
155
179
  def _live_started(self) -> bool:
156
180
  """Check if Live display has been started (derived from self.live)."""
157
- return self.live is not None
181
+ return self._live_sink is not None
182
+
183
+ def _get_base_width(self) -> int:
184
+ return self.console.options.max_width
185
+
186
+ def compute_candidate_stable_line(self, text: str) -> int:
187
+ """Return the start line of the last top-level block, or 0.
188
+
189
+ This value is not monotonic; callers should clamp it (e.g. with the
190
+ previous stable line) before using it to advance state.
191
+ """
192
+
193
+ try:
194
+ tokens = self._parser.parse(text)
195
+ except Exception:
196
+ return 0
197
+
198
+ top_level: list[Token] = [token for token in tokens if token.level == 0 and token.map is not None]
199
+ if len(top_level) < 2:
200
+ return 0
201
+
202
+ last = top_level[-1]
203
+ assert last.map is not None
204
+ start_line = last.map[0]
205
+ return max(start_line, 0)
206
+
207
+ def split_blocks(self, text: str, *, min_stable_line: int = 0, final: bool = False) -> tuple[str, str, int]:
208
+ """Split full markdown into stable and live sources.
209
+
210
+ Returns:
211
+ stable_source: Completed blocks (append-only)
212
+ live_source: Last (possibly incomplete) block
213
+ stable_line: Line index where live starts
214
+ """
215
+
216
+ lines = text.splitlines(keepends=True)
217
+ line_count = len(lines)
218
+
219
+ stable_line = line_count if final else self.compute_candidate_stable_line(text)
220
+
221
+ stable_line = min(stable_line, line_count)
222
+ stable_line = max(stable_line, min_stable_line)
223
+
224
+ stable_source = "".join(lines[:stable_line])
225
+ live_source = "".join(lines[stable_line:])
226
+ return stable_source, live_source, stable_line
227
+
228
+ def render_ansi(self, text: str, *, apply_mark: bool) -> str:
229
+ """Render markdown source to an ANSI string.
230
+
231
+ This is primarily intended for internal debugging and tests.
232
+ """
233
+
234
+ return "".join(self._render_markdown_to_lines(text, apply_mark=apply_mark))
235
+
236
+ def render_stable_ansi(self, stable_source: str, *, has_live_suffix: bool, final: bool) -> str:
237
+ """Render stable prefix to ANSI, preserving inter-block spacing."""
238
+
239
+ if not stable_source:
240
+ return ""
241
+
242
+ render_source = stable_source
243
+ if not final and has_live_suffix:
244
+ render_source = self._append_nonfinal_sentinel(stable_source)
158
245
 
159
- def _render_markdown_to_lines(self, text: str) -> list[str]:
246
+ return self.render_ansi(render_source, apply_mark=True)
247
+
248
+ @staticmethod
249
+ def normalize_live_ansi_for_boundary(*, stable_ansi: str, live_ansi: str) -> str:
250
+ """Normalize whitespace at the stable/live boundary.
251
+
252
+ Some Rich Markdown blocks (e.g. lists) render with a leading blank line.
253
+ If the stable prefix already renders a trailing blank line, rendering the
254
+ live suffix separately may introduce an extra blank line that wouldn't
255
+ appear when rendering the full document.
256
+
257
+ This function removes leading blank lines from the live ANSI when the
258
+ stable ANSI already ends with a blank line.
259
+ """
260
+
261
+ stable_lines = stable_ansi.splitlines(keepends=True)
262
+ stable_ends_blank = bool(stable_lines) and not stable_lines[-1].strip()
263
+ if not stable_ends_blank:
264
+ return live_ansi
265
+
266
+ live_lines = live_ansi.splitlines(keepends=True)
267
+ while live_lines and not live_lines[0].strip():
268
+ live_lines.pop(0)
269
+ return "".join(live_lines)
270
+
271
+ def _append_nonfinal_sentinel(self, stable_source: str) -> str:
272
+ """Make Rich render stable content as if it isn't the last block.
273
+
274
+ Rich Markdown may omit trailing spacing for the last block in a document.
275
+ When we render only the stable prefix (without the live suffix), we still
276
+ need the *inter-block* spacing to match the full document.
277
+
278
+ A harmless HTML comment block causes Rich Markdown to emit the expected
279
+ spacing while rendering no visible content.
280
+ """
281
+
282
+ if not stable_source:
283
+ return stable_source
284
+
285
+ if stable_source.endswith("\n\n"):
286
+ return stable_source + "<!-- -->"
287
+ if stable_source.endswith("\n"):
288
+ return stable_source + "\n<!-- -->"
289
+ return stable_source + "\n\n<!-- -->"
290
+
291
+ def _render_markdown_to_lines(self, text: str, *, apply_mark: bool) -> list[str]:
160
292
  """Render markdown text to a list of lines.
161
293
 
162
294
  Args:
@@ -168,13 +300,8 @@ class MarkdownStream:
168
300
  # Render the markdown to a string buffer
169
301
  string_io = io.StringIO()
170
302
 
171
- # Determine console width and adjust for left margin so that
172
- # the rendered content plus margins does not exceed the available width.
173
- if self.console is not None:
174
- base_width = self.console.options.max_width
175
- else:
176
- probe_console = Console(theme=self.theme)
177
- base_width = probe_console.options.max_width
303
+ # Keep width stable across frames to prevent reflow/jitter.
304
+ base_width = self._get_base_width()
178
305
 
179
306
  effective_width = max(base_width - self.left_margin - self.right_margin, 1)
180
307
 
@@ -195,7 +322,7 @@ class MarkdownStream:
195
322
  indent_prefix = " " * self.left_margin if self.left_margin > 0 else ""
196
323
  processed_lines: list[str] = []
197
324
  mark_applied = False
198
- use_mark = bool(self.mark) and self.left_margin >= 2
325
+ use_mark = apply_mark and bool(self.mark) and self.left_margin >= 2
199
326
 
200
327
  # Pre-render styled mark if needed
201
328
  styled_mark: str | None = None
@@ -227,102 +354,58 @@ class MarkdownStream:
227
354
 
228
355
  def __del__(self) -> None:
229
356
  """Destructor to ensure Live display is properly cleaned up."""
230
- if self.live:
231
- # Ignore any errors during cleanup
232
- with contextlib.suppress(Exception):
233
- self.live.stop()
357
+ if self._live_sink is None:
358
+ return
359
+ with contextlib.suppress(Exception):
360
+ self._live_sink(None)
234
361
 
235
362
  def update(self, text: str, final: bool = False) -> None:
236
- """Update the displayed markdown content.
237
-
238
- Args:
239
- text (str): The markdown text received so far
240
- final (bool): If True, this is the final update and we should clean up
241
-
242
- Splits the output into "stable" older lines and the "last few" lines
243
- which aren't considered stable. They may shift around as new chunks
244
- are appended to the markdown text.
245
-
246
- The stable lines emit to the console above the Live window.
247
- The unstable lines emit into the Live window so they can be repainted.
248
-
249
- Markdown going to the console works better in terminal scrollback buffers.
250
- The live window doesn't play nice with terminal scrollback.
251
- """
252
- if not self._live_started:
253
- initial_content = self._live_renderable(Text(""), final=False)
254
- # transient=False keeps final frame on screen after stop()
255
- self.live = Live(
256
- initial_content,
257
- refresh_per_second=1.0 / self.min_delay,
258
- console=self.console,
259
- )
260
- self.live.start()
261
-
262
- if self.live is None:
263
- return
363
+ """Update the display with the latest full markdown buffer."""
264
364
 
265
365
  now = time.time()
266
- # Throttle updates to maintain smooth rendering
267
366
  if not final and now - self.when < self.min_delay:
268
367
  return
269
368
  self.when = now
270
369
 
271
- # Measure render time and adjust min_delay to maintain smooth rendering
272
- start = time.time()
273
- lines = self._render_markdown_to_lines(text)
274
- render_time = time.time() - start
275
-
276
- # Set min_delay to render time plus a small buffer
277
- self.min_delay = min(max(render_time * 10, 1.0 / 20), 2)
370
+ previous_stable_line = self._stable_source_line_count
278
371
 
279
- num_lines = len(lines)
280
-
281
- # Reserve last live_window lines for Live area to keep height stable
282
- num_lines = max(num_lines - self.live_window, 0)
283
-
284
- # Print new stable lines above Live window
285
- if num_lines > 0:
286
- num_printed = len(self.printed)
287
- to_append_count = num_lines - num_printed
372
+ stable_source, live_source, stable_line = self.split_blocks(
373
+ text,
374
+ min_stable_line=previous_stable_line,
375
+ final=final,
376
+ )
288
377
 
289
- if to_append_count > 0:
290
- append_chunk = lines[num_printed:num_lines]
291
- append_chunk_text = Text.from_ansi("".join(append_chunk))
292
- live = self.live
293
- assert live is not None
294
- live.console.print(append_chunk_text)
295
- self.printed = lines[:num_lines]
378
+ start = time.time()
296
379
 
297
- rest_lines = lines[num_lines:]
380
+ stable_changed = final or stable_line > self._stable_source_line_count
381
+ if stable_changed and stable_source:
382
+ stable_ansi = self.render_stable_ansi(stable_source, has_live_suffix=bool(live_source), final=final)
383
+ stable_lines = stable_ansi.splitlines(keepends=True)
384
+ new_lines = stable_lines[len(self._stable_rendered_lines) :]
385
+ if new_lines:
386
+ stable_chunk = "".join(new_lines)
387
+ self.console.print(Text.from_ansi(stable_chunk), end="\n")
388
+ self._stable_rendered_lines = stable_lines
389
+ self._stable_source_line_count = stable_line
390
+ elif final and not stable_source:
391
+ self._stable_rendered_lines = []
392
+ self._stable_source_line_count = stable_line
298
393
 
299
- # Final: render remaining lines without spinner, then stop Live
300
394
  if final:
301
- live = self.live
302
- assert live is not None
303
- rest = "".join(rest_lines)
304
- rest_text = Text.from_ansi(rest)
305
- final_renderable = self._live_renderable(rest_text, final=True)
306
- live.update(final_renderable)
307
- live.stop()
308
- self.live = None
395
+ if self._live_sink is not None:
396
+ self._live_sink(None)
309
397
  return
310
398
 
311
- rest = "".join(rest_lines)
312
- rest = Text.from_ansi(rest)
313
- live = self.live
314
- assert live is not None
315
- live_renderable = self._live_renderable(rest, final)
316
- live.update(live_renderable)
399
+ if const.MARKDOWN_STREAM_LIVE_REPAINT_ENABLED and self._live_sink is not None:
400
+ apply_mark_live = self._stable_source_line_count == 0
401
+ live_lines = self._render_markdown_to_lines(live_source, apply_mark=apply_mark_live)
317
402
 
318
- def _live_renderable(self, rest: Text, final: bool) -> RenderableType:
319
- if final or not self.spinner:
320
- return rest
321
- else:
322
- return Group(rest, Text(), self.spinner)
403
+ if self._stable_rendered_lines and not self._stable_rendered_lines[-1].strip():
404
+ while live_lines and not live_lines[0].strip():
405
+ live_lines.pop(0)
323
406
 
324
- def find_minimal_suffix(self, text: str, match_lines: int = 50) -> None:
325
- """
326
- Splits text into chunks on blank lines "\n\n".
327
- """
328
- return None
407
+ live_text = Text.from_ansi("".join(live_lines))
408
+ self._live_sink(live_text)
409
+
410
+ elapsed = time.time() - start
411
+ self.min_delay = min(max(elapsed * 6, 1.0 / 30), 0.5)
@@ -22,7 +22,7 @@ BREATHING_SPINNER_NAME = "dots"
22
22
 
23
23
  # Alternating glyphs for the breathing spinner - switches at each "transparent" point
24
24
  _BREATHING_SPINNER_GLYPHS_BASE = [
25
- "",
25
+ "",
26
26
  ]
27
27
 
28
28
  # Shuffle glyphs on module load for variety across sessions
@@ -56,18 +56,12 @@ def _shimmer_profile(main_text: str) -> list[tuple[str, float]]:
56
56
  char_count = len(chars)
57
57
  period = char_count + padding * 2
58
58
 
59
- # Keep a roughly constant shimmer speed (characters per second)
60
- # regardless of text length by deriving a character velocity from a
61
- # baseline text length and the configured sweep duration.
62
- # The baseline is chosen to be close to the default
63
- # "Thinking … (esc to interrupt)" status line.
64
- baseline_chars = 30
65
- base_period = baseline_chars + padding * 2
66
- sweep_seconds = const.STATUS_SHIMMER_SWEEP_SECONDS
67
- char_speed = base_period / sweep_seconds if sweep_seconds > 0 else base_period
59
+ # Use same period as breathing spinner for visual consistency
60
+ sweep_seconds = max(const.SPINNER_BREATH_PERIOD_SECONDS, 0.1)
68
61
 
69
62
  elapsed = _elapsed_since_start()
70
- pos_f = (elapsed * char_speed) % float(period)
63
+ # Complete one full sweep in sweep_seconds, regardless of text length
64
+ pos_f = (elapsed / sweep_seconds % 1.0) * period
71
65
  pos = int(pos_f)
72
66
  band_half_width = const.STATUS_SHIMMER_BAND_HALF_WIDTH
73
67
 
@@ -291,7 +291,7 @@ def get_theme(theme: str | None = None) -> Themes:
291
291
  "markdown.code.border": palette.grey3,
292
292
  "markdown.h1": "bold reverse",
293
293
  "markdown.h1.border": palette.grey3,
294
- "markdown.h2.border": palette.grey3,
294
+ "markdown.h2": "bold underline",
295
295
  "markdown.h3": "bold " + palette.grey1,
296
296
  "markdown.h4": "bold " + palette.grey2,
297
297
  "markdown.hr": palette.grey3,
@@ -311,7 +311,6 @@ def get_theme(theme: str | None = None) -> Themes:
311
311
  "markdown.code.border": palette.grey3,
312
312
  "markdown.h1": "bold reverse",
313
313
  "markdown.h1.border": palette.grey3,
314
- "markdown.h2.border": palette.grey3,
315
314
  "markdown.h3": "bold " + palette.grey1,
316
315
  "markdown.h4": "bold " + palette.grey2,
317
316
  "markdown.hr": palette.grey3,
@@ -329,7 +328,6 @@ def get_theme(theme: str | None = None) -> Themes:
329
328
  Style(color=palette.blue),
330
329
  Style(color=palette.purple),
331
330
  Style(color=palette.orange),
332
- Style(color=palette.red),
333
331
  Style(color=palette.grey1),
334
332
  Style(color=palette.yellow),
335
333
  ],
@@ -339,7 +337,6 @@ def get_theme(theme: str | None = None) -> Themes:
339
337
  Style(bgcolor=palette.blue_sub_background),
340
338
  Style(bgcolor=palette.purple_background),
341
339
  Style(bgcolor=palette.orange_background),
342
- Style(bgcolor=palette.red_background),
343
340
  Style(bgcolor=palette.grey_background),
344
341
  Style(bgcolor=palette.yellow_background),
345
342
  ],
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.24
3
+ Version: 1.2.26
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
7
7
  Requires-Dist: ddgs>=9.9.3
8
8
  Requires-Dist: diff-match-patch>=20241021
9
+ Requires-Dist: markdown-it-py>=4.0.0
9
10
  Requires-Dist: openai>=1.102.0
10
11
  Requires-Dist: pillow>=12.0.0
11
12
  Requires-Dist: prompt-toolkit>=3.0.52
@@ -11,7 +11,7 @@ klaude_code/cli/config_cmd.py,sha256=SBFmBnHvkf5IJtpsDDuHsHWQCmYd2i4PtIMBOKpxmOM
11
11
  klaude_code/cli/debug.py,sha256=vizBXc3648vBZQonreMqvv_b5UdRgcQoOIT-iEIx1G4,2318
12
12
  klaude_code/cli/list_model.py,sha256=9YOxhWE0J59NaY-SrgPA9_jA1A8rlOGwWmzK0TRuos4,8011
13
13
  klaude_code/cli/main.py,sha256=pyU2W2X3lg7Z-4adiOzA9_2l-5QSejYm68HrhAiu470,10469
14
- klaude_code/cli/runtime.py,sha256=0qYbtTP41m0K8eA2de_VFuERTV1NHn265O1-BMcdrw0,14238
14
+ klaude_code/cli/runtime.py,sha256=XqF1d53UnIgnmnlqKGR3YBdBNlBFuoyc7BvUfr22CGw,14824
15
15
  klaude_code/cli/self_update.py,sha256=fekLNRm3ivZ-Xbc-79rcgDBXbq-Zb-BkSQOGMRLeTAs,7986
16
16
  klaude_code/cli/session_cmd.py,sha256=jAopkqq_DGgoDIcGxT-RSzn9R4yqBC8NCaNgK1GLqnQ,2634
17
17
  klaude_code/command/__init__.py,sha256=B39fxrrvxb51B6qeQJoh3lXWCsPoI81BJvdSLb-8CYg,3117
@@ -30,14 +30,14 @@ klaude_code/command/registry.py,sha256=avTjsoyLv11SsLsY_qb3OpsRjsSyxIlu7uwJI0Nq6
30
30
  klaude_code/command/release_notes_cmd.py,sha256=FIrBRfKTlXEp8mBh15buNjgOrl_GMX7FeeMWxYYBn1o,2674
31
31
  klaude_code/command/status_cmd.py,sha256=sYmzfex7RVhgrBCjRyD8fsZ6ioZvjVzQ_-FvmcsA7fo,5365
32
32
  klaude_code/command/terminal_setup_cmd.py,sha256=SivM1gX_anGY_8DCQNFZ5VblFqt4sVgCMEWPRlo6K5w,10911
33
- klaude_code/command/thinking_cmd.py,sha256=XDyq0q8eb3Os4FyWjr-moiKjmzGIaNhOC9h89y1AZ84,8854
33
+ klaude_code/command/thinking_cmd.py,sha256=8EdSN6huXihM5NHJEryZLA7CkgRT7mZgMVTJsT1-x8U,9108
34
34
  klaude_code/config/__init__.py,sha256=Qrqvi8nizkj6N77h2vDj0r4rbgCiqxvz2HLBPFuWulA,120
35
35
  klaude_code/config/config.py,sha256=2jvM6a8zoC-TdRFaLIw3OW5paxxeXC6l-o05ds4RysA,7263
36
36
  klaude_code/config/select_model.py,sha256=KCdFjaoHXyO9QidNna_OGdDrvlEXtRUXKfG-F8kdNLk,5188
37
- klaude_code/const.py,sha256=H6CDlh1-AkV3TUe7pDOBA6VaS-81uuWG12NmqERetaA,4483
37
+ klaude_code/const.py,sha256=Xc6UKku2sGQE05mvPNCpBbKK205vJrS9CaNAeKvu1AA,4612
38
38
  klaude_code/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  klaude_code/core/agent.py,sha256=bWm-UFX_0-KAy5j_YHH8X8o3MJT4-40Ni2EaDP2SL5k,5819
40
- klaude_code/core/executor.py,sha256=E8IdgNEzcHnWoN9q9VMZljcXoCqWWRU7XzleCZ7jhtA,24907
40
+ klaude_code/core/executor.py,sha256=MkfKPOZWknjyQzSUl_qCGRxsyYY9zetQVnerO_dWqx4,26827
41
41
  klaude_code/core/manager/__init__.py,sha256=hdIbpnYj6i18byiWjtJIm5l7NYYDQMvafw8fePVPydc,562
42
42
  klaude_code/core/manager/llm_clients.py,sha256=X2oMFWgJcP0tK8GEtMMDYR3HyR6_H8FuyCqpzWF5x2k,871
43
43
  klaude_code/core/manager/llm_clients_builder.py,sha256=pPZ_xBh-_ipV66L-9a1fnwNos4iik82Zkq0E0y3WrfI,1521
@@ -60,7 +60,7 @@ klaude_code/core/tool/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
60
60
  klaude_code/core/tool/file/_utils.py,sha256=OG4BE9WyJqzH8ilVCL3D9yvAcHk-r-L9snd-E8gO_io,967
61
61
  klaude_code/core/tool/file/apply_patch.py,sha256=LZd3pYQ9ow_TxiFnqYuzD216HmvkLX6lW6BoMd9iQRs,17080
62
62
  klaude_code/core/tool/file/apply_patch_tool.md,sha256=KVDsjUiLDa97gym0NrZNVG4jA1_zN-2i-B3upVQyOhU,59
63
- klaude_code/core/tool/file/apply_patch_tool.py,sha256=Wp5x3auJZx99am4NiR4daRj1XJJtDpfBcsRlNXgucCE,6974
63
+ klaude_code/core/tool/file/apply_patch_tool.py,sha256=LGH0vfKAEGy91Q-quo75JQERUGeoojOao7NvEdQONTI,8059
64
64
  klaude_code/core/tool/file/diff_builder.py,sha256=b53S4Ebw7aPmd9AZ97Pxu6MRcnUIdVD36MJ2yTDrAjI,5872
65
65
  klaude_code/core/tool/file/edit_tool.md,sha256=rEcUjJuPC46t1nXWjTDxplDcxWDbzTWsr6_bYt5_aRI,1110
66
66
  klaude_code/core/tool/file/edit_tool.py,sha256=wuXISJRTWobNCKjkQ01UpoA13I0Zxcg1r7hXErAQxnQ,10897
@@ -122,9 +122,9 @@ klaude_code/protocol/__init__.py,sha256=aGUgzhYqvhuT3Mk2vj7lrHGriH4h9TSbqV1RsRFA
122
122
  klaude_code/protocol/commands.py,sha256=GN6GX9fo7YYtfumrBTpOmOvZofsnzZN2SAxP2X0BjTk,644
123
123
  klaude_code/protocol/events.py,sha256=KUMf1rLNdHQO9cZiQ9Pa1VsKkP1PTMbUkp18bu_jGy8,3935
124
124
  klaude_code/protocol/llm_param.py,sha256=cb4ubLq21PIsMOC8WJb0aid12z_sT1b7FsbNJMr-jLg,4255
125
- klaude_code/protocol/model.py,sha256=aJUavwtGWY-XiDF6qk2ZV6FwEfjTqOnXZeznB7_zc_4,13606
126
- klaude_code/protocol/op.py,sha256=X3UeXxBOLf_jkEaYXhQSTpjtUV2u1Ot5f4bbPWNdQp4,4241
127
- klaude_code/protocol/op_handler.py,sha256=qaWrm2rlskSyF7ukPtxFAKf8brgLsUaVzg6035N-7w0,1565
125
+ klaude_code/protocol/model.py,sha256=bHTSVKwkEBlMELtPEANzxu2c_GvOSZOCk9AP6mpronY,14128
126
+ klaude_code/protocol/op.py,sha256=zG8AGFcTx1vIZFN0lNZjIjucjmDYM4eVOR7tRiLofF4,4589
127
+ klaude_code/protocol/op_handler.py,sha256=feTMdrz2QBwnjdv6ndizTinbBA9HFeH4oiBDeQBRKoY,1749
128
128
  klaude_code/protocol/sub_agent/__init__.py,sha256=Abap5lPLgnSCQsVD3axfeqnj2UtxOcDLGX8e9HugfSU,3964
129
129
  klaude_code/protocol/sub_agent/explore.py,sha256=Z4M7i98XBLew38ClXiW-hJteSYjMUu2b548rkR7JW3A,2579
130
130
  klaude_code/protocol/sub_agent/oracle.py,sha256=0cbuutKQcvwaM--Q15mbkCdbpZMF4YjxDN1jkuGVKp4,3344
@@ -162,11 +162,11 @@ klaude_code/ui/modes/exec/display.py,sha256=m2kkgaUoGD9rEVUmcm7Vs_PyAI2iruKCJYRh
162
162
  klaude_code/ui/modes/repl/__init__.py,sha256=35a6SUiL1SDi2i43X2VjHQw97rR7yhbLBzkGI5aC6Bc,1526
163
163
  klaude_code/ui/modes/repl/clipboard.py,sha256=ZCpk7kRSXGhh0Q_BWtUUuSYT7ZOqRjAoRcg9T9n48Wo,5137
164
164
  klaude_code/ui/modes/repl/completers.py,sha256=GIvUS9TAFMMPDpoXLuIupEccoqIMEpSEw4IZmKjVo4c,28560
165
- klaude_code/ui/modes/repl/display.py,sha256=0u4ISeOoYjynF7InYyV-PMOZqP44QBbjYOLOL18V0c0,2245
166
- klaude_code/ui/modes/repl/event_handler.py,sha256=UUJYhNRSTFj7CVi_IG-fe3B5-pv9odcBvqgbJxeoQp0,25161
167
- klaude_code/ui/modes/repl/input_prompt_toolkit.py,sha256=Jbpk-jOmBNBhw3hKkB8YzGSXRduIH9YOGMhMIPzF3gk,8564
165
+ klaude_code/ui/modes/repl/display.py,sha256=06wawOHWO2ItEA9EIEh97p3GDID7TJhAtpaA03nPQXs,2335
166
+ klaude_code/ui/modes/repl/event_handler.py,sha256=bX8QFE9nccpe6DP8bGXUi9gcSxcYHK5cb6hliwg_hyM,25530
167
+ klaude_code/ui/modes/repl/input_prompt_toolkit.py,sha256=F1p4JZp-KjDvTEZVR6bC0nb4ayd2VaEYsLmEA0KJOUM,9054
168
168
  klaude_code/ui/modes/repl/key_bindings.py,sha256=Fxz9Ey2SnOHvfleMeSYVduxuofY0Yo-97hMRs-OMe-o,7800
169
- klaude_code/ui/modes/repl/renderer.py,sha256=Apg_z6D7JTmzxGN9os64bjlG9LxfOAgqjAAmiXA8fMc,12247
169
+ klaude_code/ui/modes/repl/renderer.py,sha256=XcBztFI3ZfbuzWuqjRTVzAWbGKSY8F6uCmzZblU3vPM,15981
170
170
  klaude_code/ui/renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
171
171
  klaude_code/ui/renderers/assistant.py,sha256=nO_QNJ2e9TwtU2IlojO9lCMWNFUNmcE9Ezz-WW748_w,743
172
172
  klaude_code/ui/renderers/common.py,sha256=5RdXC3ngtlhfmxRlbwOPtHtbXhAoWwbHoGX78tZcaTc,2284
@@ -174,19 +174,19 @@ klaude_code/ui/renderers/developer.py,sha256=CawltuPSt_8s5lLoYKWYD9htwORbjgHeb4A
174
174
  klaude_code/ui/renderers/diffs.py,sha256=A37Wuz1_UIg0-st5le68-DRGz4-kot6N-wy9xEMKdz0,10403
175
175
  klaude_code/ui/renderers/errors.py,sha256=o9pOHRqZ0nxMPwkmV4CG81X7taW1-izvga6RY3fFRMI,516
176
176
  klaude_code/ui/renderers/metadata.py,sha256=b1aNqLjyaqErP4O5YSEXg7ychJcNTKpZ6hTmdcNJX84,8190
177
- klaude_code/ui/renderers/sub_agent.py,sha256=-8aDIIG4vmqwSSJepYy_tn2vmChAHOLjwmPWN2o_B_Y,5728
178
- klaude_code/ui/renderers/thinking.py,sha256=y5ICt0eJvpn2rtv5-_x6FDWyOYAnJHkfTdBWCr4Y6Yk,1946
179
- klaude_code/ui/renderers/tools.py,sha256=W24deCM4GhZT69gzo3FwZ0QVYbQ-x5Bo2-y5nFkOsdE,22268
177
+ klaude_code/ui/renderers/sub_agent.py,sha256=g8QCFXTtFX_w8oTaGMYGuy6u5KqbFMlvzWofER0hGKk,5946
178
+ klaude_code/ui/renderers/thinking.py,sha256=nwKotPFS3WInsdrHFquqOHyvR8dTEKZ0JS5SMKJ_GgA,1946
179
+ klaude_code/ui/renderers/tools.py,sha256=x4L9880HZAwXnr89M4GxbMybhwXjs6jWA7QVcI3n4_c,23524
180
180
  klaude_code/ui/renderers/user_input.py,sha256=e2hZS7UUnzQuQ6UqzSKRDkFJMkKTLUoub1JclHMX40g,3941
181
181
  klaude_code/ui/rich/__init__.py,sha256=zEZjnHR3Fnv_sFMxwIMjoJfwDoC4GRGv3lHJzAGRq_o,236
182
182
  klaude_code/ui/rich/cjk_wrap.py,sha256=ncmifgTwF6q95iayHQyazGbntt7BRQb_Ed7aXc8JU6Y,7551
183
- klaude_code/ui/rich/code_panel.py,sha256=MdUP4QSaQJQxX0MQJT0pvrkhpGYZx3gWdIRbZT_Uj_I,3938
184
- klaude_code/ui/rich/live.py,sha256=Uid0QAZG7mHb4KrCF8p9c9n1nHLHzW75xSqcLZ4bLWY,2098
185
- klaude_code/ui/rich/markdown.py,sha256=_B7yWgBpSY8I8MBTX1_qvDCmyIZY0I-EnPrmoShQ2iQ,12126
183
+ klaude_code/ui/rich/code_panel.py,sha256=ZKuJHh-kh-hIkBXSGLERLaDbJ7I9hvtvmYKocJn39_w,4744
184
+ klaude_code/ui/rich/live.py,sha256=qiBLPSE4KW_Dpemy5MZ5BKhkFWEN2fjXBiQHmhJrPSM,2722
185
+ klaude_code/ui/rich/markdown.py,sha256=bZqnhJ_NvJ4d4G4IfXMn8XacJ_cPoRC-qhRvFaimZn8,15297
186
186
  klaude_code/ui/rich/quote.py,sha256=tZcxN73SfDBHF_qk0Jkh9gWBqPBn8VLp9RF36YRdKEM,1123
187
187
  klaude_code/ui/rich/searchable_text.py,sha256=DCVZgEFv7_ergAvT2v7XrfQAUXUzhmAwuVAchlIx8RY,2448
188
- klaude_code/ui/rich/status.py,sha256=JOB-Yb3_HBwKb8K-NHFVkjxCPLkDuAJYboS6JzNqMVc,9590
189
- klaude_code/ui/rich/theme.py,sha256=GpPd_BD7rkCpmWDjdOYoW65UgJSMxAjA28Sgv5GbUNg,13291
188
+ klaude_code/ui/rich/status.py,sha256=QHg4oWmPSQH19H81vOFpImEqWyDtAbIXjuCGsuDjBPA,9278
189
+ klaude_code/ui/rich/theme.py,sha256=AKgl84dsn-xV8R7V6_lXllf2HAoRenc6SgM_sdbvjxk,13145
190
190
  klaude_code/ui/terminal/__init__.py,sha256=GIMnsEcIAGT_vBHvTlWEdyNmAEpruyscUA6M_j3GQZU,1412
191
191
  klaude_code/ui/terminal/color.py,sha256=M-i09DVlLAhAyhQjfeAi7OipoGi1p_OVkaZxeRfykY0,7135
192
192
  klaude_code/ui/terminal/control.py,sha256=6SGNwxorP3jMW9xqnZy2BC0OsJd4DSrS13O3t6YlZzs,4916
@@ -194,7 +194,7 @@ klaude_code/ui/terminal/notifier.py,sha256=wkRM66d98Oh6PujnN4bB7NiQxIYEHqQXverMK
194
194
  klaude_code/ui/terminal/progress_bar.py,sha256=MDnhPbqCnN4GDgLOlxxOEVZPDwVC_XL2NM5sl1MFNcQ,2133
195
195
  klaude_code/ui/utils/__init__.py,sha256=YEsCLjbCPaPza-UXTPUMTJTrc9BmNBUP5CbFWlshyOQ,15
196
196
  klaude_code/ui/utils/common.py,sha256=tqHqwgLtAyP805kwRFyoAL4EgMutcNb3Y-GAXJ4IeuM,2263
197
- klaude_code-1.2.24.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
198
- klaude_code-1.2.24.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
199
- klaude_code-1.2.24.dist-info/METADATA,sha256=2hkiGL2H3Kze2MNzy6FcrtEG0KSh-t6tPBpgwjJreDk,7725
200
- klaude_code-1.2.24.dist-info/RECORD,,
197
+ klaude_code-1.2.26.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
198
+ klaude_code-1.2.26.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
199
+ klaude_code-1.2.26.dist-info/METADATA,sha256=CI9hiFD-OVRxM4BY8dohWKSA-skNFZ4bfpW5jpdzwwQ,7762
200
+ klaude_code-1.2.26.dist-info/RECORD,,