klaude-code 1.2.1__py3-none-any.whl → 1.2.3__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.
- klaude_code/cli/main.py +9 -4
- klaude_code/cli/runtime.py +42 -43
- klaude_code/command/__init__.py +7 -5
- klaude_code/command/clear_cmd.py +6 -29
- klaude_code/command/command_abc.py +44 -8
- klaude_code/command/diff_cmd.py +33 -27
- klaude_code/command/export_cmd.py +18 -26
- klaude_code/command/help_cmd.py +10 -8
- klaude_code/command/model_cmd.py +11 -40
- klaude_code/command/{prompt-update-dev-doc.md → prompt-dev-docs-update.md} +3 -2
- klaude_code/command/{prompt-dev-doc.md → prompt-dev-docs.md} +3 -2
- klaude_code/command/prompt-init.md +2 -5
- klaude_code/command/prompt_command.py +6 -6
- klaude_code/command/refresh_cmd.py +4 -5
- klaude_code/command/registry.py +16 -19
- klaude_code/command/terminal_setup_cmd.py +12 -11
- klaude_code/config/__init__.py +4 -0
- klaude_code/config/config.py +25 -26
- klaude_code/config/list_model.py +8 -3
- klaude_code/config/select_model.py +1 -1
- klaude_code/const/__init__.py +1 -1
- klaude_code/core/__init__.py +0 -3
- klaude_code/core/agent.py +25 -50
- klaude_code/core/executor.py +268 -101
- klaude_code/core/prompt.py +12 -12
- klaude_code/core/{prompt → prompts}/prompt-gemini.md +1 -1
- klaude_code/core/reminders.py +76 -95
- klaude_code/core/task.py +21 -14
- klaude_code/core/tool/__init__.py +45 -11
- klaude_code/core/tool/file/apply_patch.py +5 -1
- klaude_code/core/tool/file/apply_patch_tool.py +11 -13
- klaude_code/core/tool/file/edit_tool.py +27 -23
- klaude_code/core/tool/file/multi_edit_tool.py +15 -17
- klaude_code/core/tool/file/read_tool.py +41 -36
- klaude_code/core/tool/file/write_tool.py +13 -15
- klaude_code/core/tool/memory/memory_tool.py +85 -68
- klaude_code/core/tool/memory/skill_tool.py +10 -12
- klaude_code/core/tool/shell/bash_tool.py +24 -22
- klaude_code/core/tool/shell/command_safety.py +12 -1
- klaude_code/core/tool/sub_agent_tool.py +11 -12
- klaude_code/core/tool/todo/todo_write_tool.py +21 -28
- klaude_code/core/tool/todo/update_plan_tool.py +14 -24
- klaude_code/core/tool/tool_abc.py +3 -4
- klaude_code/core/tool/tool_context.py +7 -7
- klaude_code/core/tool/tool_registry.py +30 -47
- klaude_code/core/tool/tool_runner.py +35 -43
- klaude_code/core/tool/truncation.py +14 -20
- klaude_code/core/tool/web/mermaid_tool.py +12 -14
- klaude_code/core/tool/web/web_fetch_tool.py +15 -17
- klaude_code/core/turn.py +19 -7
- klaude_code/llm/__init__.py +3 -4
- klaude_code/llm/anthropic/client.py +30 -46
- klaude_code/llm/anthropic/input.py +4 -11
- klaude_code/llm/client.py +29 -8
- klaude_code/llm/input_common.py +66 -36
- klaude_code/llm/openai_compatible/client.py +42 -84
- klaude_code/llm/openai_compatible/input.py +11 -16
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +2 -2
- klaude_code/llm/openrouter/client.py +40 -289
- klaude_code/llm/openrouter/input.py +13 -35
- klaude_code/llm/openrouter/reasoning_handler.py +209 -0
- klaude_code/llm/registry.py +5 -75
- klaude_code/llm/responses/client.py +34 -55
- klaude_code/llm/responses/input.py +24 -26
- klaude_code/llm/usage.py +109 -0
- klaude_code/protocol/__init__.py +4 -0
- klaude_code/protocol/events.py +3 -2
- klaude_code/protocol/{llm_parameter.py → llm_param.py} +12 -32
- klaude_code/protocol/model.py +49 -4
- klaude_code/protocol/op.py +18 -16
- klaude_code/protocol/op_handler.py +28 -0
- klaude_code/{core → protocol}/sub_agent.py +7 -0
- klaude_code/session/export.py +150 -70
- klaude_code/session/session.py +28 -14
- klaude_code/session/templates/export_session.html +180 -42
- klaude_code/trace/__init__.py +2 -2
- klaude_code/trace/log.py +11 -5
- klaude_code/ui/__init__.py +91 -8
- klaude_code/ui/core/__init__.py +1 -0
- klaude_code/ui/core/display.py +103 -0
- klaude_code/ui/core/input.py +71 -0
- klaude_code/ui/modes/__init__.py +1 -0
- klaude_code/ui/modes/debug/__init__.py +1 -0
- klaude_code/ui/{base/debug_event_display.py → modes/debug/display.py} +9 -5
- klaude_code/ui/modes/exec/__init__.py +1 -0
- klaude_code/ui/{base/exec_display.py → modes/exec/display.py} +28 -2
- klaude_code/ui/{repl → modes/repl}/__init__.py +5 -6
- klaude_code/ui/modes/repl/clipboard.py +152 -0
- klaude_code/ui/modes/repl/completers.py +429 -0
- klaude_code/ui/modes/repl/display.py +60 -0
- klaude_code/ui/modes/repl/event_handler.py +375 -0
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +198 -0
- klaude_code/ui/modes/repl/key_bindings.py +170 -0
- klaude_code/ui/{repl → modes/repl}/renderer.py +109 -132
- klaude_code/ui/renderers/assistant.py +21 -0
- klaude_code/ui/renderers/common.py +0 -16
- klaude_code/ui/renderers/developer.py +18 -18
- klaude_code/ui/renderers/diffs.py +36 -14
- klaude_code/ui/renderers/errors.py +1 -1
- klaude_code/ui/renderers/metadata.py +50 -27
- klaude_code/ui/renderers/sub_agent.py +43 -9
- klaude_code/ui/renderers/thinking.py +33 -1
- klaude_code/ui/renderers/tools.py +212 -20
- klaude_code/ui/renderers/user_input.py +19 -23
- klaude_code/ui/rich/__init__.py +1 -0
- klaude_code/ui/{rich_ext → rich}/searchable_text.py +3 -1
- klaude_code/ui/{renderers → rich}/status.py +29 -18
- klaude_code/ui/{base → rich}/theme.py +8 -2
- klaude_code/ui/terminal/__init__.py +1 -0
- klaude_code/ui/{base/terminal_color.py → terminal/color.py} +4 -1
- klaude_code/ui/{base/terminal_control.py → terminal/control.py} +1 -0
- klaude_code/ui/{base/terminal_notifier.py → terminal/notifier.py} +5 -2
- klaude_code/ui/utils/__init__.py +1 -0
- klaude_code/ui/{base/utils.py → utils/common.py} +35 -3
- {klaude_code-1.2.1.dist-info → klaude_code-1.2.3.dist-info}/METADATA +1 -1
- klaude_code-1.2.3.dist-info/RECORD +161 -0
- klaude_code/core/clipboard_manifest.py +0 -124
- klaude_code/llm/openrouter/tool_call_accumulator.py +0 -80
- klaude_code/ui/base/__init__.py +0 -1
- klaude_code/ui/base/display_abc.py +0 -36
- klaude_code/ui/base/input_abc.py +0 -20
- klaude_code/ui/repl/display.py +0 -36
- klaude_code/ui/repl/event_handler.py +0 -247
- klaude_code/ui/repl/input.py +0 -773
- klaude_code/ui/rich_ext/__init__.py +0 -1
- klaude_code-1.2.1.dist-info/RECORD +0 -151
- /klaude_code/core/{prompt → prompts}/prompt-claude-code.md +0 -0
- /klaude_code/core/{prompt → prompts}/prompt-codex.md +0 -0
- /klaude_code/core/{prompt → prompts}/prompt-subagent-explore.md +0 -0
- /klaude_code/core/{prompt → prompts}/prompt-subagent-oracle.md +0 -0
- /klaude_code/core/{prompt → prompts}/prompt-subagent-webfetch.md +0 -0
- /klaude_code/core/{prompt → prompts}/prompt-subagent.md +0 -0
- /klaude_code/ui/{base → core}/stage_manager.py +0 -0
- /klaude_code/ui/{rich_ext → rich}/live.py +0 -0
- /klaude_code/ui/{rich_ext → rich}/markdown.py +0 -0
- /klaude_code/ui/{rich_ext → rich}/quote.py +0 -0
- /klaude_code/ui/{base → terminal}/progress_bar.py +0 -0
- /klaude_code/ui/{base → utils}/debouncer.py +0 -0
- {klaude_code-1.2.1.dist-info → klaude_code-1.2.3.dist-info}/WHEEL +0 -0
- {klaude_code-1.2.1.dist-info → klaude_code-1.2.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Awaitable, Callable
|
|
4
|
-
|
|
5
|
-
from klaude_code.const import UI_REFRESH_RATE_FPS
|
|
6
|
-
from klaude_code.protocol import events
|
|
7
|
-
from klaude_code.ui.base.debouncer import Debouncer
|
|
8
|
-
from klaude_code.ui.base.progress_bar import OSC94States, emit_osc94
|
|
9
|
-
from klaude_code.ui.base.stage_manager import Stage, StageManager
|
|
10
|
-
from klaude_code.ui.base.terminal_notifier import Notification, NotificationType, TerminalNotifier
|
|
11
|
-
from klaude_code.ui.base.theme import ThemeKey
|
|
12
|
-
from klaude_code.ui.renderers import errors as r_errors
|
|
13
|
-
from klaude_code.ui.renderers import metadata as r_metadata
|
|
14
|
-
from klaude_code.ui.renderers import status as r_status
|
|
15
|
-
from klaude_code.ui.renderers import sub_agent as r_sub_agent
|
|
16
|
-
from klaude_code.ui.renderers import thinking as r_thinking
|
|
17
|
-
from klaude_code.ui.renderers import user_input as r_user_input
|
|
18
|
-
from klaude_code.ui.renderers.common import truncate_display
|
|
19
|
-
from klaude_code.ui.repl.renderer import REPLRenderer
|
|
20
|
-
from klaude_code.ui.rich_ext.markdown import MarkdownStream, NoInsetMarkdown
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class StreamState:
|
|
24
|
-
def __init__(self, interval: float, flush_handler: Callable[["StreamState"], Awaitable[None]]):
|
|
25
|
-
self.buffer: str = ""
|
|
26
|
-
self.mdstream: MarkdownStream | None = None
|
|
27
|
-
self._flush_handler = flush_handler
|
|
28
|
-
self.debouncer = Debouncer(interval=interval, callback=self._debounced_flush)
|
|
29
|
-
|
|
30
|
-
async def _debounced_flush(self) -> None:
|
|
31
|
-
await self._flush_handler(self)
|
|
32
|
-
|
|
33
|
-
def append(self, content: str) -> None:
|
|
34
|
-
self.buffer += content
|
|
35
|
-
|
|
36
|
-
def clear(self) -> None:
|
|
37
|
-
self.buffer = ""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class DisplayEventHandler:
|
|
41
|
-
"""Handle REPL events, buffering and delegating rendering work."""
|
|
42
|
-
|
|
43
|
-
def __init__(self, renderer: REPLRenderer, notifier: TerminalNotifier | None = None):
|
|
44
|
-
self.renderer = renderer
|
|
45
|
-
self.notifier = notifier
|
|
46
|
-
self.assistant_stream = StreamState(
|
|
47
|
-
interval=1 / UI_REFRESH_RATE_FPS, flush_handler=self._flush_assistant_buffer
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
self.stage_manager = StageManager(
|
|
51
|
-
finish_assistant=self.finish_assistant_stream,
|
|
52
|
-
on_enter_thinking=self._print_thinking_prefix,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
async def consume_event(self, event: events.Event) -> None:
|
|
56
|
-
match event:
|
|
57
|
-
case events.ReplayHistoryEvent() as replay_event:
|
|
58
|
-
await self.renderer.replay_history(replay_event)
|
|
59
|
-
self.renderer.spinner.stop()
|
|
60
|
-
case events.WelcomeEvent() as welcome_event:
|
|
61
|
-
self.renderer.print(r_metadata.render_welcome(welcome_event, box_style=self.renderer.box_style()))
|
|
62
|
-
case events.UserMessageEvent() as user_event:
|
|
63
|
-
self.renderer.print(r_user_input.render_user_input(user_event.content))
|
|
64
|
-
case events.TaskStartEvent() as task_event:
|
|
65
|
-
self.renderer.spinner.start()
|
|
66
|
-
self.renderer.register_session(task_event.session_id, task_event.sub_agent_state)
|
|
67
|
-
if task_event.sub_agent_state is not None:
|
|
68
|
-
# Print sub-agent task call
|
|
69
|
-
with self.renderer.session_print_context(task_event.session_id):
|
|
70
|
-
self.renderer.print(
|
|
71
|
-
r_sub_agent.render_sub_agent_call(
|
|
72
|
-
task_event.sub_agent_state,
|
|
73
|
-
self.renderer.get_session_sub_agent_color(task_event.session_id),
|
|
74
|
-
)
|
|
75
|
-
)
|
|
76
|
-
emit_osc94(OSC94States.INDETERMINATE)
|
|
77
|
-
case events.DeveloperMessageEvent() as developer_event:
|
|
78
|
-
self.renderer.display_developer_message(developer_event)
|
|
79
|
-
self.renderer.display_command_output(developer_event)
|
|
80
|
-
case events.TurnStartEvent() as turn_start_event:
|
|
81
|
-
emit_osc94(OSC94States.INDETERMINATE)
|
|
82
|
-
if not self.renderer.is_sub_agent_session(turn_start_event.session_id):
|
|
83
|
-
self.renderer.print()
|
|
84
|
-
case events.ThinkingEvent() as thinking_event:
|
|
85
|
-
if self.renderer.is_sub_agent_session(thinking_event.session_id):
|
|
86
|
-
return
|
|
87
|
-
await self.stage_manager.enter_thinking_stage()
|
|
88
|
-
self.renderer.display_thinking(thinking_event.content)
|
|
89
|
-
case events.AssistantMessageDeltaEvent() as assistant_delta:
|
|
90
|
-
if self.renderer.is_sub_agent_session(assistant_delta.session_id):
|
|
91
|
-
return
|
|
92
|
-
if len(assistant_delta.content.strip()) == 0 and self.stage_manager.current_stage != Stage.ASSISTANT:
|
|
93
|
-
return
|
|
94
|
-
first_delta = self.assistant_stream.mdstream is None
|
|
95
|
-
if first_delta:
|
|
96
|
-
self.assistant_stream.mdstream = MarkdownStream(
|
|
97
|
-
mdargs={"code_theme": self.renderer.themes.code_theme},
|
|
98
|
-
theme=self.renderer.themes.markdown_theme,
|
|
99
|
-
console=self.renderer.console,
|
|
100
|
-
spinner=self.renderer.spinner.renderable,
|
|
101
|
-
mark="➤",
|
|
102
|
-
indent=2,
|
|
103
|
-
)
|
|
104
|
-
self.assistant_stream.append(assistant_delta.content)
|
|
105
|
-
if first_delta and self.assistant_stream.mdstream is not None:
|
|
106
|
-
# Stop spinner and immediately start MarkdownStream's Live
|
|
107
|
-
# to avoid flicker. The update() call starts the Live with
|
|
108
|
-
# the spinner embedded, providing seamless transition.
|
|
109
|
-
self.renderer.spinner.stop()
|
|
110
|
-
self.assistant_stream.mdstream.update(self.assistant_stream.buffer)
|
|
111
|
-
await self.stage_manager.transition_to(Stage.ASSISTANT)
|
|
112
|
-
self.assistant_stream.debouncer.schedule()
|
|
113
|
-
case events.AssistantMessageEvent() as assistant_event:
|
|
114
|
-
if self.renderer.is_sub_agent_session(assistant_event.session_id):
|
|
115
|
-
return
|
|
116
|
-
await self.stage_manager.transition_to(Stage.ASSISTANT)
|
|
117
|
-
if self.assistant_stream.mdstream is not None:
|
|
118
|
-
self.assistant_stream.debouncer.cancel()
|
|
119
|
-
self.assistant_stream.mdstream.update(assistant_event.content.strip(), final=True)
|
|
120
|
-
else:
|
|
121
|
-
content = assistant_event.content.strip()
|
|
122
|
-
if content:
|
|
123
|
-
self.renderer.print(
|
|
124
|
-
NoInsetMarkdown(
|
|
125
|
-
content,
|
|
126
|
-
code_theme=self.renderer.themes.code_theme,
|
|
127
|
-
)
|
|
128
|
-
)
|
|
129
|
-
self.renderer.print()
|
|
130
|
-
self.assistant_stream.clear()
|
|
131
|
-
self.assistant_stream.mdstream = None
|
|
132
|
-
await self.stage_manager.transition_to(Stage.WAITING)
|
|
133
|
-
self.renderer.spinner.start()
|
|
134
|
-
case events.TurnToolCallStartEvent():
|
|
135
|
-
pass
|
|
136
|
-
case events.ToolCallEvent() as tool_call_event:
|
|
137
|
-
await self.stage_manager.transition_to(Stage.TOOL_CALL)
|
|
138
|
-
with self.renderer.session_print_context(tool_call_event.session_id):
|
|
139
|
-
self.renderer.display_tool_call(tool_call_event)
|
|
140
|
-
case events.ToolResultEvent() as tool_result_event:
|
|
141
|
-
if self.renderer.is_sub_agent_session(tool_result_event.session_id):
|
|
142
|
-
return
|
|
143
|
-
await self.stage_manager.transition_to(Stage.TOOL_RESULT)
|
|
144
|
-
self.renderer.display_tool_call_result(tool_result_event)
|
|
145
|
-
case events.ResponseMetadataEvent() as metadata_event:
|
|
146
|
-
with self.renderer.session_print_context(metadata_event.session_id):
|
|
147
|
-
self.renderer.print(r_metadata.render_response_metadata(metadata_event))
|
|
148
|
-
self.renderer.print()
|
|
149
|
-
case events.TodoChangeEvent() as todo_event:
|
|
150
|
-
active_form_status_text = self._extract_active_form_text(todo_event)
|
|
151
|
-
if len(active_form_status_text) > 0:
|
|
152
|
-
self.renderer.spinner.update(
|
|
153
|
-
r_status.render_status_text(active_form_status_text, ThemeKey.SPINNER_STATUS_TEXT)
|
|
154
|
-
)
|
|
155
|
-
else:
|
|
156
|
-
self.renderer.spinner.update(
|
|
157
|
-
r_status.render_status_text("Thinking …", ThemeKey.SPINNER_STATUS_TEXT)
|
|
158
|
-
)
|
|
159
|
-
case events.TurnEndEvent():
|
|
160
|
-
pass
|
|
161
|
-
case events.TaskFinishEvent() as task_finish_event:
|
|
162
|
-
if self.renderer.is_sub_agent_session(task_finish_event.session_id):
|
|
163
|
-
with self.renderer.session_print_context(task_finish_event.session_id):
|
|
164
|
-
self.renderer.print(
|
|
165
|
-
r_sub_agent.render_sub_agent_result(
|
|
166
|
-
task_finish_event.task_result,
|
|
167
|
-
code_theme=self.renderer.themes.code_theme,
|
|
168
|
-
)
|
|
169
|
-
)
|
|
170
|
-
else:
|
|
171
|
-
emit_osc94(OSC94States.HIDDEN)
|
|
172
|
-
self.renderer.spinner.stop()
|
|
173
|
-
await self.stage_manager.transition_to(Stage.WAITING)
|
|
174
|
-
self._maybe_notify_task_finish(task_finish_event)
|
|
175
|
-
case events.InterruptEvent():
|
|
176
|
-
self.renderer.spinner.stop()
|
|
177
|
-
await self.stage_manager.transition_to(Stage.WAITING)
|
|
178
|
-
emit_osc94(OSC94States.HIDDEN)
|
|
179
|
-
self.renderer.print(r_user_input.render_interrupt())
|
|
180
|
-
case events.ErrorEvent() as error_event:
|
|
181
|
-
emit_osc94(OSC94States.ERROR)
|
|
182
|
-
await self.stage_manager.transition_to(Stage.WAITING)
|
|
183
|
-
self.renderer.print(
|
|
184
|
-
r_errors.render_error(
|
|
185
|
-
self.renderer.console.render_str(truncate_display(error_event.error_message)),
|
|
186
|
-
indent=0,
|
|
187
|
-
)
|
|
188
|
-
)
|
|
189
|
-
if not error_event.can_retry:
|
|
190
|
-
self.renderer.spinner.stop()
|
|
191
|
-
case events.EndEvent():
|
|
192
|
-
emit_osc94(OSC94States.HIDDEN)
|
|
193
|
-
await self.stage_manager.transition_to(Stage.WAITING)
|
|
194
|
-
self.renderer.spinner.stop()
|
|
195
|
-
|
|
196
|
-
async def stop(self) -> None:
|
|
197
|
-
await self.assistant_stream.debouncer.flush()
|
|
198
|
-
self.assistant_stream.debouncer.cancel()
|
|
199
|
-
|
|
200
|
-
async def finish_assistant_stream(self) -> None:
|
|
201
|
-
if self.assistant_stream.mdstream is not None:
|
|
202
|
-
self.assistant_stream.debouncer.cancel()
|
|
203
|
-
self.assistant_stream.mdstream.update(self.assistant_stream.buffer, final=True)
|
|
204
|
-
self.assistant_stream.mdstream = None
|
|
205
|
-
self.assistant_stream.clear()
|
|
206
|
-
|
|
207
|
-
def _print_thinking_prefix(self) -> None:
|
|
208
|
-
self.renderer.print(r_thinking.thinking_prefix())
|
|
209
|
-
|
|
210
|
-
async def _flush_assistant_buffer(self, state: StreamState) -> None:
|
|
211
|
-
if state.mdstream is not None:
|
|
212
|
-
state.mdstream.update(state.buffer)
|
|
213
|
-
|
|
214
|
-
def _maybe_notify_task_finish(self, event: events.TaskFinishEvent) -> None:
|
|
215
|
-
if self.notifier is None:
|
|
216
|
-
return
|
|
217
|
-
if self.renderer.is_sub_agent_session(event.session_id):
|
|
218
|
-
return
|
|
219
|
-
notification = self._build_task_finish_notification(event)
|
|
220
|
-
self.notifier.notify(notification)
|
|
221
|
-
|
|
222
|
-
def _build_task_finish_notification(self, event: events.TaskFinishEvent) -> Notification:
|
|
223
|
-
body = self._compact_result_text(event.task_result)
|
|
224
|
-
return Notification(
|
|
225
|
-
type=NotificationType.AGENT_TASK_COMPLETE,
|
|
226
|
-
title="Task Completed",
|
|
227
|
-
body=body,
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
def _compact_result_text(self, text: str) -> str | None:
|
|
231
|
-
stripped = text.strip()
|
|
232
|
-
if len(stripped) == 0:
|
|
233
|
-
return None
|
|
234
|
-
squashed = " ".join(stripped.split())
|
|
235
|
-
if len(squashed) > 200:
|
|
236
|
-
return squashed[:197] + "..."
|
|
237
|
-
return squashed
|
|
238
|
-
|
|
239
|
-
def _extract_active_form_text(self, todo_event: events.TodoChangeEvent) -> str:
|
|
240
|
-
status_text = ""
|
|
241
|
-
for todo in todo_event.todos:
|
|
242
|
-
if todo.status == "in_progress":
|
|
243
|
-
if len(todo.activeForm) > 0:
|
|
244
|
-
status_text = todo.activeForm
|
|
245
|
-
if len(todo.content) > 0:
|
|
246
|
-
status_text = todo.content
|
|
247
|
-
return status_text.replace("\n", "")
|