klaude-code 1.2.3__py3-none-any.whl → 1.2.4__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.
@@ -16,6 +16,7 @@ from .registry import (
16
16
  load_prompt_commands,
17
17
  register_command,
18
18
  )
19
+ from .status_cmd import StatusCommand
19
20
  from .terminal_setup_cmd import TerminalSetupCommand
20
21
 
21
22
  # Dynamically load prompt commands
@@ -28,6 +29,7 @@ __all__ = [
28
29
  "ModelCommand",
29
30
  "ExportCommand",
30
31
  "RefreshTerminalCommand",
32
+ "StatusCommand",
31
33
  "TerminalSetupCommand",
32
34
  "register_command",
33
35
  "CommandABC",
@@ -46,10 +46,12 @@ class ExportCommand(CommandABC):
46
46
  )
47
47
  return CommandResult(events=[event])
48
48
  except Exception as exc: # pragma: no cover - safeguard for unexpected errors
49
+ import traceback
50
+
49
51
  event = events.DeveloperMessageEvent(
50
52
  session_id=agent.session.id,
51
53
  item=model.DeveloperMessageItem(
52
- content=f"Failed to export session: {exc}",
54
+ content=f"Failed to export session: {exc}\n{traceback.format_exc()}",
53
55
  command_output=model.CommandOutput(command_name=self.name, is_error=True),
54
56
  ),
55
57
  )
@@ -0,0 +1,111 @@
1
+ from klaude_code.command.command_abc import CommandABC, CommandResult
2
+ from klaude_code.command.registry import register_command
3
+ from klaude_code.core.agent import Agent
4
+ from klaude_code.protocol import commands, events, model
5
+ from klaude_code.session.session import Session
6
+
7
+
8
+ def accumulate_session_usage(session: Session) -> tuple[model.Usage, int]:
9
+ """Accumulate usage statistics from all ResponseMetadataItems in session history.
10
+
11
+ Returns:
12
+ A tuple of (accumulated_usage, task_count)
13
+ """
14
+ total = model.Usage()
15
+ task_count = 0
16
+
17
+ for item in session.conversation_history:
18
+ if isinstance(item, model.ResponseMetadataItem) and item.usage:
19
+ task_count += 1
20
+ usage = item.usage
21
+ total.input_tokens += usage.input_tokens
22
+ total.cached_tokens += usage.cached_tokens
23
+ total.reasoning_tokens += usage.reasoning_tokens
24
+ total.output_tokens += usage.output_tokens
25
+ total.total_tokens += usage.total_tokens
26
+
27
+ # Accumulate costs
28
+ if usage.input_cost is not None:
29
+ total.input_cost = (total.input_cost or 0.0) + usage.input_cost
30
+ if usage.output_cost is not None:
31
+ total.output_cost = (total.output_cost or 0.0) + usage.output_cost
32
+ if usage.cache_read_cost is not None:
33
+ total.cache_read_cost = (total.cache_read_cost or 0.0) + usage.cache_read_cost
34
+ if usage.total_cost is not None:
35
+ total.total_cost = (total.total_cost or 0.0) + usage.total_cost
36
+
37
+ # Keep the latest context_usage_percent
38
+ if usage.context_usage_percent is not None:
39
+ total.context_usage_percent = usage.context_usage_percent
40
+
41
+ return total, task_count
42
+
43
+
44
+ def _format_tokens(tokens: int) -> str:
45
+ """Format token count with K/M suffix for readability."""
46
+ if tokens >= 1_000_000:
47
+ return f"{tokens / 1_000_000:.2f}M"
48
+ if tokens >= 1_000:
49
+ return f"{tokens / 1_000:.1f}K"
50
+ return str(tokens)
51
+
52
+
53
+ def _format_cost(cost: float | None) -> str:
54
+ """Format cost in USD."""
55
+ if cost is None:
56
+ return "-"
57
+ if cost < 0.01:
58
+ return f"${cost:.4f}"
59
+ return f"${cost:.2f}"
60
+
61
+
62
+ def format_status_content(usage: model.Usage) -> str:
63
+ """Format session status as comma-separated text."""
64
+ parts: list[str] = []
65
+
66
+ parts.append(f"Input: {_format_tokens(usage.input_tokens)}")
67
+ if usage.cached_tokens > 0:
68
+ parts.append(f"Cached: {_format_tokens(usage.cached_tokens)}")
69
+ parts.append(f"Output: {_format_tokens(usage.output_tokens)}")
70
+ parts.append(f"Total: {_format_tokens(usage.total_tokens)}")
71
+
72
+ if usage.total_cost is not None:
73
+ parts.append(f"Cost: {_format_cost(usage.total_cost)}")
74
+
75
+ return ", ".join(parts)
76
+
77
+
78
+ @register_command
79
+ class StatusCommand(CommandABC):
80
+ """Display session usage statistics."""
81
+
82
+ @property
83
+ def name(self) -> commands.CommandName:
84
+ return commands.CommandName.STATUS
85
+
86
+ @property
87
+ def summary(self) -> str:
88
+ return "Show session usage statistics"
89
+
90
+ async def run(self, raw: str, agent: Agent) -> CommandResult:
91
+ session = agent.session
92
+ usage, task_count = accumulate_session_usage(session)
93
+
94
+ event = events.DeveloperMessageEvent(
95
+ session_id=session.id,
96
+ item=model.DeveloperMessageItem(
97
+ content=format_status_content(usage),
98
+ command_output=model.CommandOutput(
99
+ command_name=self.name,
100
+ ui_extra=model.ToolResultUIExtra(
101
+ type=model.ToolResultUIExtraType.SESSION_STATUS,
102
+ session_status=model.SessionStatusUIExtra(
103
+ usage=usage,
104
+ task_count=task_count,
105
+ ),
106
+ ),
107
+ ),
108
+ ),
109
+ )
110
+
111
+ return CommandResult(events=[event])
@@ -11,6 +11,7 @@ class CommandName(str, Enum):
11
11
  CLEAR = "clear"
12
12
  TERMINAL_SETUP = "terminal-setup"
13
13
  EXPORT = "export"
14
+ STATUS = "status"
14
15
  # PLAN and DOC are dynamically registered now, but kept here if needed for reference
15
16
  # or we can remove them if no code explicitly imports them.
16
17
  # PLAN = "plan"
@@ -45,6 +45,7 @@ class ToolResultUIExtraType(str, Enum):
45
45
  SESSION_ID = "session_id"
46
46
  MERMAID_LINK = "mermaid_link"
47
47
  TRUNCATION = "truncation"
48
+ SESSION_STATUS = "session_status"
48
49
 
49
50
 
50
51
  class ToolSideEffect(str, Enum):
@@ -62,6 +63,11 @@ class TruncationUIExtra(BaseModel):
62
63
  truncated_length: int
63
64
 
64
65
 
66
+ class SessionStatusUIExtra(BaseModel):
67
+ usage: "Usage"
68
+ task_count: int
69
+
70
+
65
71
  class ToolResultUIExtra(BaseModel):
66
72
  type: ToolResultUIExtraType
67
73
  diff_text: str | None = None
@@ -69,6 +75,7 @@ class ToolResultUIExtra(BaseModel):
69
75
  session_id: str | None = None
70
76
  mermaid_link: MermaidLinkUIExtra | None = None
71
77
  truncation: TruncationUIExtra | None = None
78
+ session_status: SessionStatusUIExtra | None = None
72
79
 
73
80
 
74
81
  class AtPatternParseResult(BaseModel):
@@ -908,9 +908,81 @@
908
908
  font-size: var(--font-size-sm);
909
909
  margin-top: 2px;
910
910
  }
911
+ /* TOC Sidebar */
912
+ .toc-sidebar {
913
+ position: fixed;
914
+ top: 33vh;
915
+ left: 20px;
916
+ width: 220px;
917
+ bottom: 33vh;
918
+ overflow-y: auto;
919
+ padding-right: 12px;
920
+ /* Vertical padding to offset mask */
921
+ padding-top: 30px;
922
+ padding-bottom: 30px;
923
+ display: none;
924
+ scrollbar-width: none;
925
+ z-index: 100;
926
+ /* Linear mask for fading edges */
927
+ -webkit-mask-image: linear-gradient(
928
+ to bottom,
929
+ transparent 0%,
930
+ black 30px,
931
+ black calc(100% - 30px),
932
+ transparent 100%
933
+ );
934
+ mask-image: linear-gradient(
935
+ to bottom,
936
+ transparent 0%,
937
+ black 30px,
938
+ black calc(100% - 30px),
939
+ transparent 100%
940
+ );
941
+ }
942
+
943
+ .toc-sidebar::-webkit-scrollbar {
944
+ display: none;
945
+ }
946
+
947
+ /* Show TOC on wide screens */
948
+ @media (min-width: 1400px) {
949
+ .toc-sidebar {
950
+ display: block;
951
+ }
952
+ }
953
+
954
+ .toc-item {
955
+ display: block;
956
+ padding: 3px 10px;
957
+ margin-bottom: 1px;
958
+ font-family: var(--font-mono);
959
+ font-size: 12px;
960
+ line-height: 1.3;
961
+ color: var(--text-dim);
962
+ text-decoration: none;
963
+ cursor: pointer;
964
+ transition: all 0.2s;
965
+ white-space: nowrap;
966
+ overflow: hidden;
967
+ text-overflow: ellipsis;
968
+ border-radius: 4px;
969
+ }
970
+
971
+ .toc-item:hover {
972
+ color: var(--text);
973
+ background: rgba(0, 0, 0, 0.03);
974
+ }
975
+
976
+ .toc-item.active {
977
+ color: var(--text);
978
+ background: var(--bg-card);
979
+ font-weight: bold;
980
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
981
+ }
911
982
  </style>
912
983
  </head>
913
984
  <body>
985
+ <div id="toc-sidebar" class="toc-sidebar"></div>
914
986
  <div class="container">
915
987
  <div class="header">
916
988
  <h1>Klaude Code</h1>
@@ -941,7 +1013,9 @@
941
1013
  <div
942
1014
  class="details-content system-prompt-content"
943
1015
  style="font-family: var(--font-mono); white-space: pre-wrap"
944
- >$system_prompt</div>
1016
+ >
1017
+ $system_prompt
1018
+ </div>
945
1019
  </details>
946
1020
 
947
1021
  <details class="collapsible-section">
@@ -1215,6 +1289,138 @@
1215
1289
  behavior: "smooth",
1216
1290
  });
1217
1291
  });
1292
+
1293
+ // TOC Logic
1294
+ document.addEventListener("DOMContentLoaded", () => {
1295
+ const tocSidebar = document.getElementById("toc-sidebar");
1296
+ if (!tocSidebar) return;
1297
+
1298
+ const sections = [];
1299
+ let userCount = 0;
1300
+ let assistantCount = 0;
1301
+
1302
+ // 1. System Prompt
1303
+ const sysPrompt = document.querySelector(
1304
+ ".collapsible-section summary"
1305
+ );
1306
+ if (sysPrompt && sysPrompt.textContent.includes("System Prompt")) {
1307
+ const details = sysPrompt.parentElement;
1308
+ details.id = details.id || "section-system-prompt";
1309
+ sections.push({
1310
+ id: details.id,
1311
+ label: "System Prompt",
1312
+ el: details,
1313
+ });
1314
+ }
1315
+
1316
+ // 2. Messages and Tools
1317
+ const stream = document.querySelector(".message-stream");
1318
+ if (stream) {
1319
+ // Use a Walker to find top-level relevant items if structure is complex
1320
+ // But assuming flat children of message-stream based on CSS
1321
+ Array.from(stream.children).forEach((child) => {
1322
+ let label = null;
1323
+ let idPrefix = "section";
1324
+
1325
+ if (child.classList.contains("message-group")) {
1326
+ const roleLabel = child.querySelector(".role-label");
1327
+ if (roleLabel) {
1328
+ if (roleLabel.classList.contains("user")) {
1329
+ userCount++;
1330
+ label = `USER $${userCount}`;
1331
+ idPrefix = "user";
1332
+ } else if (roleLabel.classList.contains("assistant")) {
1333
+ assistantCount++;
1334
+ label = `ASSISTANT $${assistantCount}`;
1335
+ idPrefix = "assistant";
1336
+ } else {
1337
+ label = roleLabel.textContent.trim();
1338
+ }
1339
+ }
1340
+ } else if (child.classList.contains("tool-call")) {
1341
+ const toolName = child.querySelector(".tool-name");
1342
+ if (toolName) {
1343
+ label = toolName.textContent.trim();
1344
+ idPrefix = "tool";
1345
+ } else {
1346
+ label = "Tool";
1347
+ }
1348
+ }
1349
+
1350
+ if (label) {
1351
+ child.id =
1352
+ child.id ||
1353
+ `$${idPrefix}-$${Math.random().toString(36).substr(2, 9)}`;
1354
+ sections.push({ id: child.id, label: label, el: child });
1355
+ }
1356
+ });
1357
+ }
1358
+
1359
+ // Render TOC
1360
+ sections.forEach((section) => {
1361
+ const item = document.createElement("div");
1362
+ item.className = "toc-item";
1363
+ item.textContent = section.label;
1364
+ item.dataset.target = section.id;
1365
+ item.addEventListener("click", () => {
1366
+ section.el.scrollIntoView({ behavior: "smooth", block: "start" });
1367
+ });
1368
+ tocSidebar.appendChild(item);
1369
+ });
1370
+
1371
+ // Scroll Spy with throttling
1372
+ let ticking = false;
1373
+ const offset = 150; // Pixel offset for "active" area
1374
+
1375
+ function updateActiveSection() {
1376
+ let currentId = sections.length > 0 ? sections[0].id : null;
1377
+ const scrollY = window.scrollY;
1378
+
1379
+ // We look for the last section that has passed the top threshold (+ offset)
1380
+ for (let i = 0; i < sections.length; i++) {
1381
+ const el = sections[i].el;
1382
+ // If element top is above the "active line" (scrollY + offset)
1383
+ if (el.offsetTop <= scrollY + offset) {
1384
+ currentId = sections[i].id;
1385
+ } else {
1386
+ // Since sections are ordered by position, we can stop once we find one below the line
1387
+ break;
1388
+ }
1389
+ }
1390
+
1391
+ // Update UI
1392
+ document.querySelectorAll(".toc-item").forEach((item) => {
1393
+ const isActive = item.dataset.target === currentId;
1394
+ if (item.classList.contains("active") !== isActive) {
1395
+ item.classList.toggle("active", isActive);
1396
+ if (isActive) {
1397
+ // Auto-scroll sidebar to visible
1398
+ const sidebarRect = tocSidebar.getBoundingClientRect();
1399
+ const itemRect = item.getBoundingClientRect();
1400
+ // Check if item is out of view in sidebar (accounting for mask)
1401
+ if (
1402
+ itemRect.top < sidebarRect.top + 40 ||
1403
+ itemRect.bottom > sidebarRect.bottom - 40
1404
+ ) {
1405
+ item.scrollIntoView({ behavior: "smooth", block: "center" });
1406
+ }
1407
+ }
1408
+ }
1409
+ });
1410
+
1411
+ ticking = false;
1412
+ }
1413
+
1414
+ window.addEventListener("scroll", () => {
1415
+ if (!ticking) {
1416
+ window.requestAnimationFrame(updateActiveSection);
1417
+ ticking = true;
1418
+ }
1419
+ });
1420
+
1421
+ // Initial update
1422
+ updateActiveSection();
1423
+ });
1218
1424
  </script>
1219
1425
  </body>
1220
1426
  </html>
@@ -1,8 +1,9 @@
1
1
  from rich.console import Group, RenderableType
2
2
  from rich.padding import Padding
3
+ from rich.table import Table
3
4
  from rich.text import Text
4
5
 
5
- from klaude_code.protocol import commands, events
6
+ from klaude_code.protocol import commands, events, model
6
7
  from klaude_code.ui.renderers import diffs as r_diffs
7
8
  from klaude_code.ui.renderers.common import create_grid
8
9
  from klaude_code.ui.renderers.tools import render_path
@@ -97,7 +98,61 @@ def render_command_output(e: events.DeveloperMessageEvent) -> RenderableType:
97
98
  return r_diffs.render_diff_panel(e.item.content, show_file_name=True)
98
99
  case commands.CommandName.HELP:
99
100
  return Padding.indent(Text.from_markup(e.item.content or ""), level=2)
101
+ case commands.CommandName.STATUS:
102
+ return _render_status_output(e.item.command_output)
100
103
  case _:
101
104
  content = e.item.content or "(no content)"
102
105
  style = ThemeKey.TOOL_RESULT if not e.item.command_output.is_error else ThemeKey.ERROR
103
106
  return Padding.indent(Text(truncate_display(content), style=style), level=2)
107
+
108
+
109
+ def _format_tokens(tokens: int) -> str:
110
+ """Format token count with K/M suffix for readability."""
111
+ if tokens >= 1_000_000:
112
+ return f"{tokens / 1_000_000:.2f}M"
113
+ if tokens >= 1_000:
114
+ return f"{tokens / 1_000:.1f}K"
115
+ return str(tokens)
116
+
117
+
118
+ def _format_cost(cost: float | None) -> str:
119
+ """Format cost in USD."""
120
+ if cost is None:
121
+ return "-"
122
+ if cost < 0.01:
123
+ return f"${cost:.4f}"
124
+ return f"${cost:.2f}"
125
+
126
+
127
+ def _render_status_output(command_output: model.CommandOutput) -> RenderableType:
128
+ """Render session status as a two-column table with sections."""
129
+ if not command_output.ui_extra or not command_output.ui_extra.session_status:
130
+ return Text("(no status data)", style=ThemeKey.TOOL_RESULT)
131
+
132
+ status = command_output.ui_extra.session_status
133
+ usage = status.usage
134
+
135
+ table = Table.grid(padding=(0, 2))
136
+ table.add_column(style=ThemeKey.TOOL_RESULT, no_wrap=True)
137
+ table.add_column(style=ThemeKey.TOOL_RESULT, no_wrap=True)
138
+ # Token Usage section
139
+ table.add_row(Text("Token Usage", style="bold"), "")
140
+ table.add_row("Input Tokens", _format_tokens(usage.input_tokens))
141
+ if usage.cached_tokens > 0:
142
+ table.add_row("Cached Tokens", _format_tokens(usage.cached_tokens))
143
+ if usage.reasoning_tokens > 0:
144
+ table.add_row("Reasoning Tokens", _format_tokens(usage.reasoning_tokens))
145
+ table.add_row("Output Tokens", _format_tokens(usage.output_tokens))
146
+ table.add_row("Total Tokens", _format_tokens(usage.total_tokens))
147
+
148
+ # Cost section
149
+ if usage.total_cost is not None:
150
+ table.add_row("", "") # Empty line
151
+ table.add_row(Text("Cost", style="bold"), "")
152
+ table.add_row("Input Cost", _format_cost(usage.input_cost))
153
+ if usage.cache_read_cost is not None and usage.cache_read_cost > 0:
154
+ table.add_row("Cache Read Cost", _format_cost(usage.cache_read_cost))
155
+ table.add_row("Output Cost", _format_cost(usage.output_cost))
156
+ table.add_row("Total Cost", _format_cost(usage.total_cost))
157
+
158
+ return Padding.indent(table, level=2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.3
3
+ Version: 1.2.4
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: openai>=1.102.0
@@ -3,11 +3,11 @@ klaude_code/cli/__init__.py,sha256=YzlAoWAr5rx5oe6B_4zPxRFS4QaZauuy1AFwampP5fg,4
3
3
  klaude_code/cli/main.py,sha256=vQt1jZVX4pxQUYceWQcXkRO3w0glOUIhazI7uDex2fE,9279
4
4
  klaude_code/cli/runtime.py,sha256=jipzUciIlY-w0hlUsid8HfSZuf_xCH23XoOuByJijU8,12288
5
5
  klaude_code/cli/session_cmd.py,sha256=cIBm3uUurke-TfBvQHz9mGW29LOAh22FIpXVyypnwDo,2549
6
- klaude_code/command/__init__.py,sha256=Ec3QVR3bw3vlvaExwrXzBIXBEMfxPDeuygd8hv0e1jM,1066
6
+ klaude_code/command/__init__.py,sha256=ApRFYqzmDxXe-jJ0tHg4qe4XsJ4QSICu8ICQcmwxQ1Y,1125
7
7
  klaude_code/command/clear_cmd.py,sha256=ojsDdZnv_-bDYBPecpdY85DfGicst9Jf9j7esg2z2hE,674
8
8
  klaude_code/command/command_abc.py,sha256=WWY9qi7SILttPl6fJNi9ThevsqpGFoQJ1ecgoosd_Ms,2547
9
9
  klaude_code/command/diff_cmd.py,sha256=306PcTeKokLmchp6mIWeZ2rokINsU5-2f4iGrjEbkCE,5269
10
- klaude_code/command/export_cmd.py,sha256=xLZCWb377REO2iFFzYX76kpZWUDiJN10x18k22gELGs,3442
10
+ klaude_code/command/export_cmd.py,sha256=lsnBwxjiHyxgU7TPmT038ZVsOVqNxV2l-6U9T-dxI1g,3498
11
11
  klaude_code/command/help_cmd.py,sha256=VddWegAJS5OjbAZ35c9Pb0SSDZpPH5PqRyQ--sdseII,1709
12
12
  klaude_code/command/model_cmd.py,sha256=EApytBR6gl1Po9Mi7YVvDWgV-0ivgw-RQTnQ__EIvFQ,1510
13
13
  klaude_code/command/prompt-dev-docs-update.md,sha256=g1IWIWIa-3qlNOw5mBA4N9H1_nvYcw8AKo7XoQw_AZQ,1855
@@ -16,6 +16,7 @@ klaude_code/command/prompt-init.md,sha256=a4_FQ3gKizqs2vl9oEY5jtG6HNhv3f-1b5RSCF
16
16
  klaude_code/command/prompt_command.py,sha256=cDdLAyGk3JFS-nRlNzTnT8T35QQ-FC6RT0fD5ELZGO4,2405
17
17
  klaude_code/command/refresh_cmd.py,sha256=kgpbcnqf1n_ihMW99AfTXeZEkE2_MNwgQ9DbNfl2jqY,1288
18
18
  klaude_code/command/registry.py,sha256=OZhQqoLfWjqojJauemc8L2rnwPhYoAh2Kjx3HSAz_ZE,3554
19
+ klaude_code/command/status_cmd.py,sha256=mVGxyaqaP2qgjdjQ5BhweUb-Cc0VpsK8-7Pab92kKJg,3961
19
20
  klaude_code/command/terminal_setup_cmd.py,sha256=bQfMDZIzak8emkmuaY43_2YaS7t908sUJ_orYwccTtY,10957
20
21
  klaude_code/config/__init__.py,sha256=9XVCYYqzJtCi46I94hbUmJ2yTFuZ-UlH-QTx7OpLAkQ,292
21
22
  klaude_code/config/config.py,sha256=Vc9u7-40T81Rbx1OdMqSWZLh3vf9aj4wmBUnIOH7jAw,6526
@@ -95,10 +96,10 @@ klaude_code/llm/responses/client.py,sha256=laNTjJ7WJ8hooqZ55XPfAkrurKKryMJTx4xz0
95
96
  klaude_code/llm/responses/input.py,sha256=NtJhWyzg6XzHKuplgvta0ubzqA1u33gfgjL7X6xNeIw,6011
96
97
  klaude_code/llm/usage.py,sha256=zDW47J-sxHhRJqDZihXeW2eyxpZS6F39qLsB8K0cua0,4240
97
98
  klaude_code/protocol/__init__.py,sha256=aGUgzhYqvhuT3Mk2vj7lrHGriH4h9TSbqV1RsRFAZjQ,194
98
- klaude_code/protocol/commands.py,sha256=O1miI3GyCTLG_u3wS4CtQsmztP-nlGrjyO-k4ADYHH0,522
99
+ klaude_code/protocol/commands.py,sha256=zoqyBSpFZI8q8LP3rlr1mR-ekCufx-DfPGbzqsgx7X8,544
99
100
  klaude_code/protocol/events.py,sha256=Pw8lY7rJLwk-FjKWtX8C_-Op7p0KWLaI-PH1_U7Uoyg,3290
100
101
  klaude_code/protocol/llm_param.py,sha256=8_B8e83iPQs62CyVicTKlEKWBoOmRMlOOWkKBK__R58,4337
101
- klaude_code/protocol/model.py,sha256=tC86xQm4YpweD4PazYRCH2UF1ZgB7IdIJAhCB7Pi3B0,7582
102
+ klaude_code/protocol/model.py,sha256=op7xqxF8S8L1xwtI4-DWnZgUVW-9q0OUlTc_-suzuY8,7755
102
103
  klaude_code/protocol/op.py,sha256=rkPvDRsOgPyibMI1n0pDO7ghFWJBfDGas9BnACtmfO4,2654
103
104
  klaude_code/protocol/op_handler.py,sha256=_lnv3-RxKkrTfGTNBlQ23gbHJBEtMLC8O48SYWDtPjE,843
104
105
  klaude_code/protocol/sub_agent.py,sha256=rD4nDX3jBp1HIseQTjd83I4VJ_fFcJ9NzkKCWO6JGsk,13351
@@ -107,7 +108,7 @@ klaude_code/session/__init__.py,sha256=oXcDA5w-gJCbzmlF8yuWy3ezIW9DgFBNUs-gJHUJ-
107
108
  klaude_code/session/export.py,sha256=NDUZwjV6niQcZk2H4IRv9REviDGmw8ZmvGqko6TTjbA,23675
108
109
  klaude_code/session/selector.py,sha256=HTboyzih7V8zbZoSsArJ-GVC1EnXTGocHJwFmZfbeSg,2567
109
110
  klaude_code/session/session.py,sha256=KLE3QUNvt8d7Zu_Mj2x6rdHygzsUtLsvMzQbsiIOrKg,19195
110
- klaude_code/session/templates/export_session.html,sha256=_0bzEMKhBcc-K9o8cDEMSqTJpkH0UBYovTKlgrD2ODg,34247
111
+ klaude_code/session/templates/export_session.html,sha256=obRJtqmGEkSu2urixX4AeYlPTSEr9788omU---3PvkU,40850
111
112
  klaude_code/trace/__init__.py,sha256=B-S4qdCj8W88AaC_gVmhTaejH6eLYClBVh2Q6aGAVBk,184
112
113
  klaude_code/trace/log.py,sha256=0K0uek2KWq0zkUZijcO-TBM6STLe-h_8IIW0lx7V7ZA,4865
113
114
  klaude_code/ui/__init__.py,sha256=AL1Ro0u8ObNPMj4sci_U4zakG7IpnI3bie-C63E2QPI,2873
@@ -131,7 +132,7 @@ klaude_code/ui/modes/repl/renderer.py,sha256=o1QubSm9lej-bVZ1G3ie-5qRxgPMDUo42kC
131
132
  klaude_code/ui/renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
133
  klaude_code/ui/renderers/assistant.py,sha256=Dxy6v4pX28RyWhnrjBteY8_NvDIi_jQa-j0mWt-eqWY,569
133
134
  klaude_code/ui/renderers/common.py,sha256=TPH7LCbeJGqB8ArTsVitqJHEyOxHU6nwnRtvF04nLJ4,184
134
- klaude_code/ui/renderers/developer.py,sha256=EzB-FltePb8dxMQOCNYFftHtVwWoLDI5k4uyHtKEMOI,3792
135
+ klaude_code/ui/renderers/developer.py,sha256=-pyy3Fj3M-Agsv3YsqGa6mMru1IoEQa40n6YkLJ4fqs,6019
135
136
  klaude_code/ui/renderers/diffs.py,sha256=P--aLjvZy4z77FDx6uM9LlIYVjYlyZwj0MncdJTO2AA,7691
136
137
  klaude_code/ui/renderers/errors.py,sha256=c_fbnoNOnvuI3Bb24IujwV8Mpes-qWS_xCWfAcBvg6A,517
137
138
  klaude_code/ui/renderers/metadata.py,sha256=KSF6z4LHM_eBtaSPTLSIMK7GI-1MU6FUHaT2Hv4z8tk,6985
@@ -155,7 +156,7 @@ klaude_code/ui/utils/__init__.py,sha256=YEsCLjbCPaPza-UXTPUMTJTrc9BmNBUP5CbFWlsh
155
156
  klaude_code/ui/utils/common.py,sha256=xzw-Mgj0agxrf22QxpH7YzVIpkMXIRY6SgXWtLYF0yU,2881
156
157
  klaude_code/ui/utils/debouncer.py,sha256=TFF1z7B7-FxONEigkYohhShDlqo4cOcqydE9zz7JBHc,1270
157
158
  klaude_code/version.py,sha256=QDgEqSFhyTSiABQFQc9VfujMPQcdjgoCaYTQsr94x0Q,4752
158
- klaude_code-1.2.3.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
159
- klaude_code-1.2.3.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
160
- klaude_code-1.2.3.dist-info/METADATA,sha256=mFJJzpWRIVjD_XvooIx7XApSLrjVo0j4AkpbYq5AVWM,5140
161
- klaude_code-1.2.3.dist-info/RECORD,,
159
+ klaude_code-1.2.4.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
160
+ klaude_code-1.2.4.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
161
+ klaude_code-1.2.4.dist-info/METADATA,sha256=O_BGmrEiCeeUj6RdP0wUe-zbPATYRKWa5fx2HJHk9JY,5140
162
+ klaude_code-1.2.4.dist-info/RECORD,,