klaude-code 2.0.1__py3-none-any.whl → 2.1.0__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.
Files changed (160) hide show
  1. klaude_code/app/__init__.py +12 -0
  2. klaude_code/app/runtime.py +215 -0
  3. klaude_code/cli/auth_cmd.py +2 -2
  4. klaude_code/cli/config_cmd.py +2 -2
  5. klaude_code/cli/cost_cmd.py +1 -1
  6. klaude_code/cli/debug.py +12 -36
  7. klaude_code/cli/list_model.py +3 -3
  8. klaude_code/cli/main.py +17 -60
  9. klaude_code/cli/self_update.py +2 -187
  10. klaude_code/cli/session_cmd.py +2 -2
  11. klaude_code/config/config.py +1 -1
  12. klaude_code/config/select_model.py +1 -1
  13. klaude_code/const.py +10 -1
  14. klaude_code/core/agent.py +9 -62
  15. klaude_code/core/agent_profile.py +284 -0
  16. klaude_code/core/executor.py +343 -230
  17. klaude_code/core/manager/llm_clients_builder.py +1 -1
  18. klaude_code/core/manager/sub_agent_manager.py +16 -29
  19. klaude_code/core/reminders.py +107 -155
  20. klaude_code/core/task.py +12 -20
  21. klaude_code/core/tool/__init__.py +5 -19
  22. klaude_code/core/tool/context.py +84 -0
  23. klaude_code/core/tool/file/apply_patch_tool.py +18 -21
  24. klaude_code/core/tool/file/edit_tool.py +42 -44
  25. klaude_code/core/tool/file/read_tool.py +14 -9
  26. klaude_code/core/tool/file/write_tool.py +12 -13
  27. klaude_code/core/tool/report_back_tool.py +4 -1
  28. klaude_code/core/tool/shell/bash_tool.py +6 -11
  29. klaude_code/core/tool/skill/skill_tool.py +3 -1
  30. klaude_code/core/tool/sub_agent_tool.py +8 -7
  31. klaude_code/core/tool/todo/todo_write_tool.py +3 -9
  32. klaude_code/core/tool/todo/update_plan_tool.py +3 -5
  33. klaude_code/core/tool/tool_abc.py +2 -1
  34. klaude_code/core/tool/tool_registry.py +2 -33
  35. klaude_code/core/tool/tool_runner.py +13 -10
  36. klaude_code/core/tool/web/mermaid_tool.py +3 -1
  37. klaude_code/core/tool/web/web_fetch_tool.py +5 -3
  38. klaude_code/core/tool/web/web_search_tool.py +5 -3
  39. klaude_code/core/turn.py +86 -26
  40. klaude_code/llm/anthropic/client.py +1 -1
  41. klaude_code/llm/bedrock/client.py +1 -1
  42. klaude_code/llm/claude/client.py +1 -1
  43. klaude_code/llm/codex/client.py +1 -1
  44. klaude_code/llm/google/client.py +1 -1
  45. klaude_code/llm/openai_compatible/client.py +1 -1
  46. klaude_code/llm/openai_compatible/tool_call_accumulator.py +1 -1
  47. klaude_code/llm/openrouter/client.py +1 -1
  48. klaude_code/llm/openrouter/reasoning.py +1 -1
  49. klaude_code/llm/responses/client.py +1 -1
  50. klaude_code/protocol/events/__init__.py +57 -0
  51. klaude_code/protocol/events/base.py +18 -0
  52. klaude_code/protocol/events/chat.py +20 -0
  53. klaude_code/protocol/events/lifecycle.py +22 -0
  54. klaude_code/protocol/events/metadata.py +15 -0
  55. klaude_code/protocol/events/streaming.py +43 -0
  56. klaude_code/protocol/events/system.py +53 -0
  57. klaude_code/protocol/events/tools.py +23 -0
  58. klaude_code/protocol/message.py +3 -11
  59. klaude_code/protocol/model.py +78 -9
  60. klaude_code/protocol/op.py +5 -0
  61. klaude_code/protocol/sub_agent/explore.py +0 -15
  62. klaude_code/protocol/sub_agent/task.py +1 -1
  63. klaude_code/protocol/sub_agent/web.py +1 -17
  64. klaude_code/protocol/tools.py +0 -1
  65. klaude_code/session/session.py +6 -5
  66. klaude_code/skill/assets/create-plan/SKILL.md +76 -0
  67. klaude_code/skill/loader.py +1 -1
  68. klaude_code/skill/system_skills.py +1 -1
  69. klaude_code/tui/__init__.py +8 -0
  70. klaude_code/{command → tui/command}/clear_cmd.py +2 -1
  71. klaude_code/{command → tui/command}/debug_cmd.py +4 -3
  72. klaude_code/{command → tui/command}/export_cmd.py +2 -1
  73. klaude_code/{command → tui/command}/export_online_cmd.py +6 -5
  74. klaude_code/{command → tui/command}/fork_session_cmd.py +10 -9
  75. klaude_code/{command → tui/command}/help_cmd.py +3 -2
  76. klaude_code/{command → tui/command}/model_cmd.py +5 -4
  77. klaude_code/{command → tui/command}/model_select.py +2 -2
  78. klaude_code/{command → tui/command}/prompt_command.py +4 -3
  79. klaude_code/{command → tui/command}/refresh_cmd.py +3 -1
  80. klaude_code/{command → tui/command}/registry.py +16 -6
  81. klaude_code/{command → tui/command}/release_notes_cmd.py +3 -2
  82. klaude_code/{command → tui/command}/resume_cmd.py +6 -5
  83. klaude_code/{command → tui/command}/status_cmd.py +4 -3
  84. klaude_code/{command → tui/command}/terminal_setup_cmd.py +4 -3
  85. klaude_code/{command → tui/command}/thinking_cmd.py +4 -3
  86. klaude_code/tui/commands.py +164 -0
  87. klaude_code/{ui/renderers → tui/components}/assistant.py +3 -3
  88. klaude_code/{ui/renderers → tui/components}/bash_syntax.py +2 -2
  89. klaude_code/{ui/renderers → tui/components}/common.py +1 -1
  90. klaude_code/tui/components/developer.py +231 -0
  91. klaude_code/{ui/renderers → tui/components}/diffs.py +2 -2
  92. klaude_code/{ui/renderers → tui/components}/errors.py +2 -2
  93. klaude_code/{ui/renderers → tui/components}/metadata.py +34 -21
  94. klaude_code/{ui → tui/components}/rich/markdown.py +78 -34
  95. klaude_code/{ui → tui/components}/rich/status.py +2 -2
  96. klaude_code/{ui → tui/components}/rich/theme.py +12 -5
  97. klaude_code/{ui/renderers → tui/components}/sub_agent.py +23 -43
  98. klaude_code/{ui/renderers → tui/components}/thinking.py +3 -3
  99. klaude_code/{ui/renderers → tui/components}/tools.py +11 -48
  100. klaude_code/{ui/renderers → tui/components}/user_input.py +3 -20
  101. klaude_code/tui/display.py +85 -0
  102. klaude_code/{ui/modes/repl → tui/input}/__init__.py +1 -1
  103. klaude_code/{ui/modes/repl → tui/input}/completers.py +1 -1
  104. klaude_code/{ui/modes/repl/input_prompt_toolkit.py → tui/input/prompt_toolkit.py} +11 -7
  105. klaude_code/tui/machine.py +606 -0
  106. klaude_code/tui/renderer.py +707 -0
  107. klaude_code/tui/runner.py +321 -0
  108. klaude_code/tui/terminal/__init__.py +56 -0
  109. klaude_code/{ui → tui}/terminal/color.py +1 -1
  110. klaude_code/{ui → tui}/terminal/control.py +1 -1
  111. klaude_code/{ui → tui}/terminal/notifier.py +1 -1
  112. klaude_code/{ui → tui}/terminal/selector.py +36 -17
  113. klaude_code/ui/__init__.py +6 -50
  114. klaude_code/ui/core/display.py +3 -3
  115. klaude_code/ui/core/input.py +2 -1
  116. klaude_code/ui/{modes/debug/display.py → debug_mode.py} +1 -1
  117. klaude_code/ui/{modes/exec/display.py → exec_mode.py} +1 -4
  118. klaude_code/ui/terminal/__init__.py +6 -54
  119. klaude_code/ui/terminal/title.py +31 -0
  120. klaude_code/update.py +163 -0
  121. {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/METADATA +1 -1
  122. klaude_code-2.1.0.dist-info/RECORD +235 -0
  123. klaude_code/cli/runtime.py +0 -525
  124. klaude_code/core/prompt.py +0 -108
  125. klaude_code/core/tool/file/move_tool.md +0 -41
  126. klaude_code/core/tool/file/move_tool.py +0 -435
  127. klaude_code/core/tool/tool_context.py +0 -148
  128. klaude_code/protocol/events.py +0 -194
  129. klaude_code/skill/assets/dev-docs/SKILL.md +0 -108
  130. klaude_code/trace/__init__.py +0 -21
  131. klaude_code/ui/core/stage_manager.py +0 -48
  132. klaude_code/ui/modes/__init__.py +0 -1
  133. klaude_code/ui/modes/debug/__init__.py +0 -1
  134. klaude_code/ui/modes/exec/__init__.py +0 -1
  135. klaude_code/ui/modes/repl/display.py +0 -61
  136. klaude_code/ui/modes/repl/event_handler.py +0 -634
  137. klaude_code/ui/modes/repl/renderer.py +0 -463
  138. klaude_code/ui/renderers/developer.py +0 -215
  139. klaude_code/ui/utils/__init__.py +0 -1
  140. klaude_code-2.0.1.dist-info/RECORD +0 -229
  141. /klaude_code/{trace/log.py → log.py} +0 -0
  142. /klaude_code/{command → tui/command}/__init__.py +0 -0
  143. /klaude_code/{command → tui/command}/command_abc.py +0 -0
  144. /klaude_code/{command → tui/command}/prompt-commit.md +0 -0
  145. /klaude_code/{command → tui/command}/prompt-init.md +0 -0
  146. /klaude_code/{ui/renderers → tui/components}/__init__.py +0 -0
  147. /klaude_code/{ui/renderers → tui/components}/mermaid_viewer.py +0 -0
  148. /klaude_code/{ui → tui/components}/rich/__init__.py +0 -0
  149. /klaude_code/{ui → tui/components}/rich/cjk_wrap.py +0 -0
  150. /klaude_code/{ui → tui/components}/rich/code_panel.py +0 -0
  151. /klaude_code/{ui → tui/components}/rich/live.py +0 -0
  152. /klaude_code/{ui → tui/components}/rich/quote.py +0 -0
  153. /klaude_code/{ui → tui/components}/rich/searchable_text.py +0 -0
  154. /klaude_code/{ui/modes/repl → tui/input}/clipboard.py +0 -0
  155. /klaude_code/{ui/modes/repl → tui/input}/key_bindings.py +0 -0
  156. /klaude_code/{ui → tui}/terminal/image.py +0 -0
  157. /klaude_code/{ui → tui}/terminal/progress_bar.py +0 -0
  158. /klaude_code/ui/{utils/common.py → common.py} +0 -0
  159. {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/WHEEL +0 -0
  160. {klaude_code-2.0.1.dist-info → klaude_code-2.1.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from klaude_code.protocol import model
4
+
5
+ from .base import Event
6
+
7
+
8
+ class TaskStartEvent(Event):
9
+ sub_agent_state: model.SubAgentState | None = None
10
+
11
+
12
+ class TaskFinishEvent(Event):
13
+ task_result: str
14
+ has_structured_output: bool = False
15
+
16
+
17
+ class TurnStartEvent(Event):
18
+ pass
19
+
20
+
21
+ class TurnEndEvent(Event):
22
+ pass
@@ -0,0 +1,15 @@
1
+ """Metadata-related protocol events."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from klaude_code.protocol import model
6
+
7
+ from .base import Event, ResponseEvent
8
+
9
+
10
+ class UsageEvent(ResponseEvent):
11
+ usage: model.Usage
12
+
13
+
14
+ class TaskMetadataEvent(Event):
15
+ metadata: model.TaskMetadataItem
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from .base import ResponseEvent
4
+
5
+
6
+ class ThinkingStartEvent(ResponseEvent):
7
+ pass
8
+
9
+
10
+ class ThinkingDeltaEvent(ResponseEvent):
11
+ content: str
12
+
13
+
14
+ class ThinkingEndEvent(ResponseEvent):
15
+ pass
16
+
17
+
18
+ class AssistantTextStartEvent(ResponseEvent):
19
+ pass
20
+
21
+
22
+ class AssistantTextDeltaEvent(ResponseEvent):
23
+ content: str
24
+
25
+
26
+ class AssistantTextEndEvent(ResponseEvent):
27
+ pass
28
+
29
+
30
+ class AssistantImageDeltaEvent(ResponseEvent):
31
+ file_path: str
32
+
33
+
34
+ class ToolCallStartEvent(ResponseEvent):
35
+ tool_call_id: str
36
+ tool_name: str
37
+
38
+
39
+ class ResponseCompleteEvent(ResponseEvent):
40
+ """Final snapshot of the model response."""
41
+
42
+ content: str
43
+ thinking_text: str | None = None
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from klaude_code.protocol import llm_param
4
+ from klaude_code.protocol.events.chat import DeveloperMessageEvent, UserMessageEvent
5
+ from klaude_code.protocol.events.lifecycle import TaskFinishEvent, TaskStartEvent, TurnStartEvent
6
+ from klaude_code.protocol.events.metadata import TaskMetadataEvent
7
+ from klaude_code.protocol.events.streaming import AssistantImageDeltaEvent, ResponseCompleteEvent
8
+ from klaude_code.protocol.events.tools import ToolCallEvent, ToolResultEvent
9
+
10
+ from .base import Event
11
+
12
+
13
+ class WelcomeEvent(Event):
14
+ work_dir: str
15
+ llm_config: llm_param.LLMConfigParameter
16
+ show_klaude_code_info: bool = True
17
+
18
+
19
+ class ErrorEvent(Event):
20
+ error_message: str
21
+ can_retry: bool = False
22
+
23
+
24
+ class InterruptEvent(Event):
25
+ pass
26
+
27
+
28
+ class EndEvent(Event):
29
+ """Global display shutdown."""
30
+
31
+ session_id: str = "__app__"
32
+
33
+
34
+ type ReplayEventUnion = (
35
+ TaskStartEvent
36
+ | TaskFinishEvent
37
+ | TurnStartEvent
38
+ | AssistantImageDeltaEvent
39
+ | ResponseCompleteEvent
40
+ | ToolCallEvent
41
+ | ToolResultEvent
42
+ | UserMessageEvent
43
+ | TaskMetadataEvent
44
+ | InterruptEvent
45
+ | DeveloperMessageEvent
46
+ | ErrorEvent
47
+ )
48
+
49
+
50
+ class ReplayHistoryEvent(Event):
51
+ events: list[ReplayEventUnion]
52
+ updated_at: float
53
+ is_load: bool = True
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ from klaude_code.protocol import model
6
+
7
+ from .base import ResponseEvent
8
+
9
+
10
+ class ToolCallEvent(ResponseEvent):
11
+ tool_call_id: str
12
+ tool_name: str
13
+ arguments: str
14
+
15
+
16
+ class ToolResultEvent(ResponseEvent):
17
+ tool_call_id: str
18
+ tool_name: str
19
+ result: str
20
+ ui_extra: model.ToolResultUIExtra | None = None
21
+ status: Literal["success", "error"]
22
+ task_metadata: model.TaskMetadata | None = None
23
+ is_last_in_turn: bool = True
@@ -12,8 +12,7 @@ from typing import Annotated, Literal
12
12
  from pydantic import BaseModel, Field, field_validator
13
13
 
14
14
  from klaude_code.protocol.model import (
15
- AtPatternParseResult,
16
- CommandOutput,
15
+ DeveloperUIExtra,
17
16
  StopReason,
18
17
  TaskMetadata,
19
18
  TaskMetadataItem,
@@ -137,15 +136,8 @@ class DeveloperMessage(MessageBase):
137
136
  role: Literal["developer"] = "developer"
138
137
  parts: list[Part]
139
138
 
140
- # Special fields for reminders UI
141
- memory_paths: list[str] | None = None
142
- memory_mentioned: dict[str, list[str]] | None = None # memory_path -> list of @ patterns mentioned in it
143
- external_file_changes: list[str] | None = None
144
- todo_use: bool | None = None
145
- at_files: list[AtPatternParseResult] | None = None
146
- command_output: CommandOutput | None = None
147
- user_image_count: int | None = None
148
- skill_name: str | None = None # Skill name activated via $skill syntax
139
+ # Structured UI-only metadata (never sent to the LLM).
140
+ ui_extra: DeveloperUIExtra | None = None
149
141
 
150
142
 
151
143
  class UserMessage(MessageBase):
@@ -272,21 +272,90 @@ ToolResultUIExtra = Annotated[
272
272
  ]
273
273
 
274
274
 
275
- class AtPatternParseResult(BaseModel):
276
- path: str
277
- tool_name: str
278
- result: str
279
- tool_args: str
280
- operation: Literal["Read", "List"]
281
- mentioned_in: str | None = None # Parent file that referenced this file
282
-
283
-
284
275
  class CommandOutput(BaseModel):
285
276
  command_name: CommandName
286
277
  ui_extra: ToolResultUIExtra | None = None
287
278
  is_error: bool = False
288
279
 
289
280
 
281
+ class MemoryFileLoaded(BaseModel):
282
+ path: str
283
+ mentioned_patterns: list[str] = Field(default_factory=list)
284
+
285
+
286
+ class MemoryLoadedUIItem(BaseModel):
287
+ type: Literal["memory_loaded"] = "memory_loaded"
288
+ files: list[MemoryFileLoaded]
289
+
290
+
291
+ class ExternalFileChangesUIItem(BaseModel):
292
+ type: Literal["external_file_changes"] = "external_file_changes"
293
+ paths: list[str]
294
+
295
+
296
+ class TodoReminderUIItem(BaseModel):
297
+ type: Literal["todo_reminder"] = "todo_reminder"
298
+ reason: Literal["empty", "not_used_recently"]
299
+
300
+
301
+ class AtFileOp(BaseModel):
302
+ operation: Literal["Read", "List"]
303
+ path: str
304
+ mentioned_in: str | None = None
305
+
306
+
307
+ class AtFileOpsUIItem(BaseModel):
308
+ type: Literal["at_file_ops"] = "at_file_ops"
309
+ ops: list[AtFileOp]
310
+
311
+
312
+ class UserImagesUIItem(BaseModel):
313
+ type: Literal["user_images"] = "user_images"
314
+ count: int
315
+
316
+
317
+ class SkillActivatedUIItem(BaseModel):
318
+ type: Literal["skill_activated"] = "skill_activated"
319
+ name: str
320
+
321
+
322
+ class CommandOutputUIItem(BaseModel):
323
+ type: Literal["command_output"] = "command_output"
324
+ output: CommandOutput
325
+
326
+
327
+ type DeveloperUIItem = (
328
+ MemoryLoadedUIItem
329
+ | ExternalFileChangesUIItem
330
+ | TodoReminderUIItem
331
+ | AtFileOpsUIItem
332
+ | UserImagesUIItem
333
+ | SkillActivatedUIItem
334
+ | CommandOutputUIItem
335
+ )
336
+
337
+
338
+ def _empty_developer_ui_items() -> list[DeveloperUIItem]:
339
+ return []
340
+
341
+
342
+ class DeveloperUIExtra(BaseModel):
343
+ items: list[DeveloperUIItem] = Field(default_factory=_empty_developer_ui_items)
344
+
345
+
346
+ def build_command_output_extra(
347
+ command_name: CommandName,
348
+ *,
349
+ ui_extra: ToolResultUIExtra | None = None,
350
+ is_error: bool = False,
351
+ ) -> DeveloperUIExtra:
352
+ return DeveloperUIExtra(
353
+ items=[
354
+ CommandOutputUIItem(output=CommandOutput(command_name=command_name, ui_extra=ui_extra, is_error=is_error))
355
+ ]
356
+ )
357
+
358
+
290
359
  class SubAgentState(BaseModel):
291
360
  sub_agent_type: SubAgentType
292
361
  sub_agent_desc: str
@@ -51,6 +51,11 @@ class RunAgentOperation(Operation):
51
51
  type: OperationType = OperationType.RUN_AGENT
52
52
  session_id: str
53
53
  input: UserInputPayload
54
+ # Frontends may choose to render the user message themselves (e.g. TUI) to support
55
+ # event-only commands; in that case the core should skip emitting the UserMessageEvent.
56
+ emit_user_message_event: bool = True
57
+ # Frontends may choose to run without persisting input (e.g. some interactive commands).
58
+ persist_user_input: bool = True
54
59
 
55
60
  async def execute(self, handler: OperationHandler) -> None:
56
61
  await handler.handle_run_agent(self)
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any
4
-
5
3
  from klaude_code.protocol import tools
6
4
  from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
5
 
@@ -37,11 +35,6 @@ EXPLORE_PARAMETERS = {
37
35
  "type": "string",
38
36
  "description": "The task for the agent to perform",
39
37
  },
40
- "thoroughness": {
41
- "type": "string",
42
- "enum": ["quick", "medium", "very thorough"],
43
- "description": "Controls how deep the sub-agent should search the repo",
44
- },
45
38
  "output_format": {
46
39
  "type": "object",
47
40
  "description": "Optional JSON Schema for sub-agent structured output",
@@ -52,13 +45,6 @@ EXPLORE_PARAMETERS = {
52
45
  }
53
46
 
54
47
 
55
- def _explore_prompt_builder(args: dict[str, Any]) -> str:
56
- """Build the Explore prompt from tool arguments."""
57
- prompt = args.get("prompt", "").strip()
58
- thoroughness = args.get("thoroughness", "medium")
59
- return f"{prompt}\nthoroughness: {thoroughness}"
60
-
61
-
62
48
  register_sub_agent(
63
49
  SubAgentProfile(
64
50
  name="Explore",
@@ -66,7 +52,6 @@ register_sub_agent(
66
52
  parameters=EXPLORE_PARAMETERS,
67
53
  prompt_file="prompts/prompt-sub-agent-explore.md",
68
54
  tool_set=(tools.BASH, tools.READ),
69
- prompt_builder=_explore_prompt_builder,
70
55
  active_form="Exploring",
71
56
  output_schema_arg="output_format",
72
57
  )
@@ -64,7 +64,7 @@ register_sub_agent(
64
64
  description=TASK_DESCRIPTION,
65
65
  parameters=TASK_PARAMETERS,
66
66
  prompt_file="prompts/prompt-sub-agent.md",
67
- tool_set=(tools.BASH, tools.READ, tools.EDIT, tools.WRITE, tools.MOVE),
67
+ tool_set=(tools.BASH, tools.READ, tools.EDIT, tools.WRITE),
68
68
  active_form="Tasking",
69
69
  output_schema_arg="output_format",
70
70
  )
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any
4
-
5
3
  from klaude_code.protocol import tools
6
4
  from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
5
 
@@ -21,7 +19,7 @@ Capabilities:
21
19
  How to use:
22
20
  - Write a clear prompt describing what information you need - the agent will search and fetch as needed
23
21
  - Account for "Today's date" in <env>. For example, if <env> says "Today's date: 2025-07-01", and the user wants the latest docs, do not use 2024 in the search query. Use 2025.
24
- - Optionally provide a `url` if you already know the target page
22
+ - Provide the url if you already know the target page
25
23
  - Use `output_format` (JSON Schema) to get structured data back from the agent
26
24
 
27
25
  What you receive:
@@ -48,10 +46,6 @@ WEB_AGENT_PARAMETERS = {
48
46
  "type": "string",
49
47
  "description": "A short (3-5 word) description of the task",
50
48
  },
51
- "url": {
52
- "type": "string",
53
- "description": "The URL to fetch and analyze. If not provided, the agent will search the web first",
54
- },
55
49
  "prompt": {
56
50
  "type": "string",
57
51
  "description": "Instructions for searching, analyzing, or extracting content from the web page",
@@ -66,15 +60,6 @@ WEB_AGENT_PARAMETERS = {
66
60
  }
67
61
 
68
62
 
69
- def _web_agent_prompt_builder(args: dict[str, Any]) -> str:
70
- """Build the WebAgent prompt from tool arguments."""
71
- url = args.get("url", "")
72
- prompt = args.get("prompt", "")
73
- if url:
74
- return f"URL to fetch: {url}\nTask: {prompt}"
75
- return prompt
76
-
77
-
78
63
  register_sub_agent(
79
64
  SubAgentProfile(
80
65
  name="WebAgent",
@@ -82,7 +67,6 @@ register_sub_agent(
82
67
  parameters=WEB_AGENT_PARAMETERS,
83
68
  prompt_file="prompts/prompt-sub-agent-web.md",
84
69
  tool_set=(tools.BASH, tools.READ, tools.WEB_FETCH, tools.WEB_SEARCH, tools.WRITE),
85
- prompt_builder=_web_agent_prompt_builder,
86
70
  active_form="Surfing",
87
71
  output_schema_arg="output_format",
88
72
  )
@@ -1,6 +1,5 @@
1
1
  BASH = "Bash"
2
2
  APPLY_PATCH = "apply_patch"
3
- MOVE = "Move"
4
3
  EDIT = "Edit"
5
4
 
6
5
  READ = "Read"
@@ -289,7 +289,7 @@ class Session(BaseModel):
289
289
  return True
290
290
  return isinstance(prev_item, (message.UserMessage, message.ToolResultMessage, message.DeveloperMessage))
291
291
 
292
- def get_history_item(self) -> Iterable[events.HistoryItemEvent]:
292
+ def get_history_item(self) -> Iterable[events.ReplayEventUnion]:
293
293
  seen_sub_agent_sessions: set[str] = set()
294
294
  prev_item: message.HistoryEvent | None = None
295
295
  last_assistant_content: str = ""
@@ -314,8 +314,8 @@ class Session(BaseModel):
314
314
  response_id=am.response_id,
315
315
  session_id=self.id,
316
316
  )
317
- yield events.AssistantMessageEvent(
318
- thinking_text=thinking_text,
317
+ yield events.ResponseCompleteEvent(
318
+ thinking_text=thinking_text or None,
319
319
  content=content,
320
320
  response_id=am.response_id,
321
321
  session_id=self.id,
@@ -360,7 +360,8 @@ class Session(BaseModel):
360
360
  images=images or None,
361
361
  )
362
362
  case model.TaskMetadataItem() as mt:
363
- yield events.TaskMetadataEvent(session_id=self.id, metadata=mt)
363
+ if self.sub_agent_state is None:
364
+ yield events.TaskMetadataEvent(session_id=self.id, metadata=mt)
364
365
  case message.DeveloperMessage() as dm:
365
366
  yield events.DeveloperMessageEvent(session_id=self.id, item=dm)
366
367
  case message.StreamErrorItem() as se:
@@ -377,7 +378,7 @@ class Session(BaseModel):
377
378
 
378
379
  def _iter_sub_agent_history(
379
380
  self, tool_result: message.ToolResultMessage, seen_sub_agent_sessions: set[str]
380
- ) -> Iterable[events.HistoryItemEvent]:
381
+ ) -> Iterable[events.ReplayEventUnion]:
381
382
  ui_extra = tool_result.ui_extra
382
383
  if not isinstance(ui_extra, model.SessionIdUIExtra):
383
384
  return
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: create-plan
3
+ description: Create a concise plan. Use when a user explicitly asks for a plan related to a coding task.
4
+ metadata:
5
+ short-description: Create a plan
6
+ ---
7
+
8
+ # Create Plan
9
+
10
+ ## Goal
11
+
12
+ Turn a user prompt into a **single, actionable plan** delivered in the final assistant message.
13
+
14
+ ## Minimal workflow
15
+
16
+ 1. **Scan context quickly**
17
+ - Read `README.md` and any obvious docs (`docs/`, `CONTRIBUTING.md`, `ARCHITECTURE.md`).
18
+ - Skim relevant files (the ones most likely touched).
19
+ - Identify constraints (language, frameworks, CI/test commands, deployment shape).
20
+
21
+ 2. **Ask follow-ups only if blocking**
22
+ - Ask **at most 1–2 questions**.
23
+ - Only ask if you cannot responsibly plan without the answer; prefer multiple-choice.
24
+ - If unsure but not blocked, make a reasonable assumption and proceed.
25
+
26
+ 3. **Create a plan using the template below**
27
+ - Start with **1 short paragraph** describing the intent and approach.
28
+ - Clearly call out what is **in scope** and what is **not in scope** in short.
29
+ - Then provide a **small checklist** of action items (default 6–10 items).
30
+ - Each checklist item should be a concrete action and, when helpful, mention files/commands.
31
+ - **Make items atomic and ordered**: discovery → changes → tests → rollout.
32
+ - **Verb-first**: “Add…”, “Refactor…”, “Verify…”, “Ship…”.
33
+ - Include at least one item for **tests/validation** and one for **edge cases/risk** when applicable.
34
+ - If there are unknowns, include a tiny **Open questions** section (max 3).
35
+
36
+ 4. **Write the plan to `plan.md` in the current working directory**
37
+ - Use the Write tool to save the plan to `./plan.md`
38
+ - If `plan.md` already exists, overwrite it with the new plan
39
+
40
+ 5. **Do not preface the plan with meta explanations; output only the plan as per template**
41
+
42
+ ## Plan template (follow exactly)
43
+
44
+ ```markdown
45
+ # Plan
46
+
47
+ <1–3 sentences: what we’re doing, why, and the high-level approach.>
48
+
49
+ ## Scope
50
+ - In:
51
+ - Out:
52
+
53
+ ## Action items
54
+ [ ] <Step 1>
55
+ [ ] <Step 2>
56
+ [ ] <Step 3>
57
+ [ ] <Step 4>
58
+ [ ] <Step 5>
59
+ [ ] <Step 6>
60
+
61
+ ## Open questions
62
+ - <Question 1>
63
+ - <Question 2>
64
+ - <Question 3>
65
+ ```
66
+
67
+ ## Checklist item guidance
68
+ Good checklist items:
69
+ - Point to likely files/modules: src/..., app/..., services/...
70
+ - Name concrete validation: “Run npm test”, “Add unit tests for X”
71
+ - Include safe rollout when relevant: feature flag, migration plan, rollback note
72
+
73
+ Avoid:
74
+ - Vague steps (“handle backend”, “do auth”)
75
+ - Too many micro-steps
76
+ - Writing code snippets (keep the plan implementation-agnostic)
@@ -5,7 +5,7 @@ from typing import ClassVar
5
5
 
6
6
  import yaml
7
7
 
8
- from klaude_code.trace import log_debug
8
+ from klaude_code.log import log_debug
9
9
 
10
10
 
11
11
  @dataclass
@@ -11,7 +11,7 @@ from contextlib import contextmanager
11
11
  from importlib import resources
12
12
  from pathlib import Path
13
13
 
14
- from klaude_code.trace import log_debug
14
+ from klaude_code.log import log_debug
15
15
 
16
16
  # Marker file name for tracking installed skills version
17
17
  SYSTEM_SKILLS_MARKER_FILENAME = ".klaude-system-skills.marker"
@@ -0,0 +1,8 @@
1
+ """Terminal (TUI) frontend for klaude-code.
2
+
3
+ This package contains all terminal-specific UI code (Rich rendering,
4
+ prompt-toolkit input, and terminal integrations).
5
+
6
+ The tui layer may depend on `klaude_code.ui`, but `klaude_code.ui` must not
7
+ depend on `klaude_code.tui`.
8
+ """
@@ -1,6 +1,7 @@
1
- from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
2
1
  from klaude_code.protocol import commands, message, op
3
2
 
3
+ from .command_abc import Agent, CommandABC, CommandResult
4
+
4
5
 
5
6
  class ClearCommand(CommandABC):
6
7
  """Clear current session and start a new conversation"""
@@ -1,6 +1,7 @@
1
- from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
1
+ from klaude_code.log import DebugType, get_current_log_file, is_debug_enabled, set_debug_logging
2
2
  from klaude_code.protocol import commands, events, message, model
3
- from klaude_code.trace import DebugType, get_current_log_file, is_debug_enabled, set_debug_logging
3
+
4
+ from .command_abc import Agent, CommandABC, CommandResult
4
5
 
5
6
 
6
7
  def _format_status() -> str:
@@ -72,7 +73,7 @@ class DebugCommand(CommandABC):
72
73
  session_id=agent.session.id,
73
74
  item=message.DeveloperMessage(
74
75
  parts=message.text_parts_from_str(content),
75
- command_output=model.CommandOutput(command_name=self.name),
76
+ ui_extra=model.build_command_output_extra(self.name),
76
77
  ),
77
78
  )
78
79
  ]
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
4
 
5
- from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
6
5
  from klaude_code.protocol import commands, message, op
7
6
 
7
+ from .command_abc import Agent, CommandABC, CommandResult
8
+
8
9
 
9
10
  class ExportCommand(CommandABC):
10
11
  """Export the current session into a standalone HTML transcript."""
@@ -9,10 +9,11 @@ from pathlib import Path
9
9
  from rich.console import Console
10
10
  from rich.text import Text
11
11
 
12
- from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
13
12
  from klaude_code.protocol import commands, events, message, model
14
13
  from klaude_code.session.export import build_export_html
15
14
 
15
+ from .command_abc import Agent, CommandABC, CommandResult
16
+
16
17
 
17
18
  class ExportOnlineCommand(CommandABC):
18
19
  """Export and deploy the current session to surge.sh as a static webpage."""
@@ -42,7 +43,7 @@ class ExportOnlineCommand(CommandABC):
42
43
  session_id=agent.session.id,
43
44
  item=message.DeveloperMessage(
44
45
  parts=message.text_parts_from_str("surge.sh CLI not found. Install with: npm install -g surge"),
45
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
46
+ ui_extra=model.build_command_output_extra(self.name, is_error=True),
46
47
  ),
47
48
  )
48
49
  return CommandResult(events=[event])
@@ -59,7 +60,7 @@ class ExportOnlineCommand(CommandABC):
59
60
  session_id=agent.session.id,
60
61
  item=message.DeveloperMessage(
61
62
  parts=message.text_parts_from_str(f"Not logged in to surge.sh. Please run: {login_cmd}"),
62
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
63
+ ui_extra=model.build_command_output_extra(self.name, is_error=True),
63
64
  ),
64
65
  )
65
66
  return CommandResult(events=[event])
@@ -73,7 +74,7 @@ class ExportOnlineCommand(CommandABC):
73
74
  session_id=agent.session.id,
74
75
  item=message.DeveloperMessage(
75
76
  parts=message.text_parts_from_str(f"Session deployed to: {url}"),
76
- command_output=model.CommandOutput(command_name=self.name),
77
+ ui_extra=model.build_command_output_extra(self.name),
77
78
  ),
78
79
  )
79
80
  return CommandResult(events=[event])
@@ -84,7 +85,7 @@ class ExportOnlineCommand(CommandABC):
84
85
  session_id=agent.session.id,
85
86
  item=message.DeveloperMessage(
86
87
  parts=message.text_parts_from_str(f"Failed to deploy session: {exc}\n{traceback.format_exc()}"),
87
- command_output=model.CommandOutput(command_name=self.name, is_error=True),
88
+ ui_extra=model.build_command_output_extra(self.name, is_error=True),
88
89
  ),
89
90
  )
90
91
  return CommandResult(events=[event])