klaude-code 2.0.2__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- klaude_code/app/__init__.py +12 -0
- klaude_code/app/runtime.py +215 -0
- klaude_code/cli/auth_cmd.py +2 -2
- klaude_code/cli/config_cmd.py +2 -2
- klaude_code/cli/cost_cmd.py +1 -1
- klaude_code/cli/debug.py +12 -36
- klaude_code/cli/list_model.py +3 -3
- klaude_code/cli/main.py +17 -60
- klaude_code/cli/self_update.py +2 -187
- klaude_code/cli/session_cmd.py +2 -2
- klaude_code/config/config.py +1 -1
- klaude_code/config/select_model.py +1 -1
- klaude_code/const.py +9 -1
- klaude_code/core/agent.py +9 -62
- klaude_code/core/agent_profile.py +291 -0
- klaude_code/core/executor.py +335 -230
- klaude_code/core/manager/llm_clients_builder.py +1 -1
- klaude_code/core/manager/sub_agent_manager.py +16 -29
- klaude_code/core/reminders.py +84 -103
- klaude_code/core/task.py +12 -20
- klaude_code/core/tool/__init__.py +5 -19
- klaude_code/core/tool/context.py +84 -0
- klaude_code/core/tool/file/apply_patch_tool.py +18 -21
- klaude_code/core/tool/file/edit_tool.py +39 -42
- klaude_code/core/tool/file/read_tool.py +14 -9
- klaude_code/core/tool/file/write_tool.py +12 -13
- klaude_code/core/tool/report_back_tool.py +4 -1
- klaude_code/core/tool/shell/bash_tool.py +6 -11
- klaude_code/core/tool/sub_agent_tool.py +8 -7
- klaude_code/core/tool/todo/todo_write_tool.py +3 -9
- klaude_code/core/tool/todo/update_plan_tool.py +3 -5
- klaude_code/core/tool/tool_abc.py +2 -1
- klaude_code/core/tool/tool_registry.py +2 -33
- klaude_code/core/tool/tool_runner.py +13 -10
- klaude_code/core/tool/web/mermaid_tool.py +3 -1
- klaude_code/core/tool/web/web_fetch_tool.py +5 -3
- klaude_code/core/tool/web/web_search_tool.py +5 -3
- klaude_code/core/turn.py +87 -30
- klaude_code/llm/anthropic/client.py +1 -1
- klaude_code/llm/bedrock/client.py +1 -1
- klaude_code/llm/claude/client.py +1 -1
- klaude_code/llm/codex/client.py +1 -1
- klaude_code/llm/google/client.py +1 -1
- klaude_code/llm/openai_compatible/client.py +1 -1
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +1 -1
- klaude_code/llm/openrouter/client.py +1 -1
- klaude_code/llm/openrouter/reasoning.py +1 -1
- klaude_code/llm/responses/client.py +1 -1
- klaude_code/protocol/commands.py +1 -0
- klaude_code/protocol/events/__init__.py +57 -0
- klaude_code/protocol/events/base.py +18 -0
- klaude_code/protocol/events/chat.py +20 -0
- klaude_code/protocol/events/lifecycle.py +22 -0
- klaude_code/protocol/events/metadata.py +15 -0
- klaude_code/protocol/events/streaming.py +43 -0
- klaude_code/protocol/events/system.py +53 -0
- klaude_code/protocol/events/tools.py +27 -0
- klaude_code/protocol/op.py +5 -0
- klaude_code/protocol/tools.py +0 -1
- klaude_code/session/session.py +6 -7
- klaude_code/skill/assets/create-plan/SKILL.md +76 -0
- klaude_code/skill/loader.py +32 -88
- klaude_code/skill/manager.py +38 -0
- klaude_code/skill/system_skills.py +1 -1
- klaude_code/tui/__init__.py +8 -0
- klaude_code/{command → tui/command}/__init__.py +3 -0
- klaude_code/{command → tui/command}/clear_cmd.py +2 -1
- klaude_code/tui/command/copy_cmd.py +53 -0
- klaude_code/{command → tui/command}/debug_cmd.py +3 -2
- klaude_code/{command → tui/command}/export_cmd.py +2 -1
- klaude_code/{command → tui/command}/export_online_cmd.py +2 -1
- klaude_code/{command → tui/command}/fork_session_cmd.py +4 -3
- klaude_code/{command → tui/command}/help_cmd.py +2 -1
- klaude_code/{command → tui/command}/model_cmd.py +4 -3
- klaude_code/{command → tui/command}/model_select.py +2 -2
- klaude_code/{command → tui/command}/prompt_command.py +4 -3
- klaude_code/{command → tui/command}/refresh_cmd.py +3 -1
- klaude_code/{command → tui/command}/registry.py +6 -5
- klaude_code/{command → tui/command}/release_notes_cmd.py +2 -1
- klaude_code/{command → tui/command}/resume_cmd.py +4 -3
- klaude_code/{command → tui/command}/status_cmd.py +2 -1
- klaude_code/{command → tui/command}/terminal_setup_cmd.py +2 -1
- klaude_code/{command → tui/command}/thinking_cmd.py +3 -2
- klaude_code/tui/commands.py +164 -0
- klaude_code/{ui/renderers → tui/components}/assistant.py +3 -3
- klaude_code/{ui/renderers → tui/components}/bash_syntax.py +2 -2
- klaude_code/{ui/renderers → tui/components}/common.py +1 -1
- klaude_code/{ui/renderers → tui/components}/developer.py +4 -4
- klaude_code/{ui/renderers → tui/components}/diffs.py +2 -2
- klaude_code/{ui/renderers → tui/components}/errors.py +2 -2
- klaude_code/{ui/renderers → tui/components}/metadata.py +7 -7
- klaude_code/{ui → tui/components}/rich/markdown.py +9 -23
- klaude_code/{ui → tui/components}/rich/status.py +2 -2
- klaude_code/{ui → tui/components}/rich/theme.py +3 -1
- klaude_code/{ui/renderers → tui/components}/sub_agent.py +23 -43
- klaude_code/{ui/renderers → tui/components}/thinking.py +3 -3
- klaude_code/{ui/renderers → tui/components}/tools.py +13 -17
- klaude_code/{ui/renderers → tui/components}/user_input.py +3 -20
- klaude_code/tui/display.py +85 -0
- klaude_code/{ui/modes/repl → tui/input}/__init__.py +1 -1
- klaude_code/{ui/modes/repl → tui/input}/completers.py +1 -1
- klaude_code/{ui/modes/repl/input_prompt_toolkit.py → tui/input/prompt_toolkit.py} +6 -6
- klaude_code/tui/machine.py +608 -0
- klaude_code/tui/renderer.py +707 -0
- klaude_code/tui/runner.py +321 -0
- klaude_code/tui/terminal/__init__.py +56 -0
- klaude_code/{ui → tui}/terminal/color.py +1 -1
- klaude_code/{ui → tui}/terminal/control.py +1 -1
- klaude_code/{ui → tui}/terminal/notifier.py +1 -1
- klaude_code/ui/__init__.py +6 -50
- klaude_code/ui/core/display.py +3 -3
- klaude_code/ui/core/input.py +2 -1
- klaude_code/ui/{modes/debug/display.py → debug_mode.py} +1 -1
- klaude_code/ui/{modes/exec/display.py → exec_mode.py} +0 -2
- klaude_code/ui/terminal/__init__.py +6 -54
- klaude_code/ui/terminal/title.py +31 -0
- klaude_code/update.py +163 -0
- {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/METADATA +1 -1
- klaude_code-2.1.1.dist-info/RECORD +233 -0
- klaude_code/cli/runtime.py +0 -518
- klaude_code/core/prompt.py +0 -108
- klaude_code/core/tool/skill/skill_tool.md +0 -24
- klaude_code/core/tool/skill/skill_tool.py +0 -87
- klaude_code/core/tool/tool_context.py +0 -148
- klaude_code/protocol/events.py +0 -195
- klaude_code/skill/assets/dev-docs/SKILL.md +0 -108
- klaude_code/trace/__init__.py +0 -21
- klaude_code/ui/core/stage_manager.py +0 -48
- klaude_code/ui/modes/__init__.py +0 -1
- klaude_code/ui/modes/debug/__init__.py +0 -1
- klaude_code/ui/modes/exec/__init__.py +0 -1
- klaude_code/ui/modes/repl/display.py +0 -61
- klaude_code/ui/modes/repl/event_handler.py +0 -629
- klaude_code/ui/modes/repl/renderer.py +0 -464
- klaude_code/ui/renderers/__init__.py +0 -0
- klaude_code/ui/utils/__init__.py +0 -1
- klaude_code-2.0.2.dist-info/RECORD +0 -227
- /klaude_code/{trace/log.py → log.py} +0 -0
- /klaude_code/{command → tui/command}/command_abc.py +0 -0
- /klaude_code/{command → tui/command}/prompt-commit.md +0 -0
- /klaude_code/{command → tui/command}/prompt-init.md +0 -0
- /klaude_code/{core/tool/skill → tui/components}/__init__.py +0 -0
- /klaude_code/{ui/renderers → tui/components}/mermaid_viewer.py +0 -0
- /klaude_code/{ui → tui/components}/rich/__init__.py +0 -0
- /klaude_code/{ui → tui/components}/rich/cjk_wrap.py +0 -0
- /klaude_code/{ui → tui/components}/rich/code_panel.py +0 -0
- /klaude_code/{ui → tui/components}/rich/live.py +0 -0
- /klaude_code/{ui → tui/components}/rich/quote.py +0 -0
- /klaude_code/{ui → tui/components}/rich/searchable_text.py +0 -0
- /klaude_code/{ui/modes/repl → tui/input}/clipboard.py +0 -0
- /klaude_code/{ui/modes/repl → tui/input}/key_bindings.py +0 -0
- /klaude_code/{ui → tui}/terminal/image.py +0 -0
- /klaude_code/{ui → tui}/terminal/progress_bar.py +0 -0
- /klaude_code/{ui → tui}/terminal/selector.py +0 -0
- /klaude_code/ui/{utils/common.py → common.py} +0 -0
- {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/WHEEL +0 -0
- {klaude_code-2.0.2.dist-info → klaude_code-2.1.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
"""SkillTool - Tool for agent to activate and load skills."""
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
from pydantic import BaseModel
|
|
6
|
-
|
|
7
|
-
from klaude_code.core.tool.tool_abc import ToolABC, load_desc
|
|
8
|
-
from klaude_code.core.tool.tool_registry import register
|
|
9
|
-
from klaude_code.protocol import llm_param, message, tools
|
|
10
|
-
from klaude_code.skill import get_available_skills, get_skill, list_skill_names
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@register(tools.SKILL)
|
|
14
|
-
class SkillTool(ToolABC):
|
|
15
|
-
"""Tool to execute/load a skill within the main conversation."""
|
|
16
|
-
|
|
17
|
-
@classmethod
|
|
18
|
-
def schema(cls) -> llm_param.ToolSchema:
|
|
19
|
-
"""Generate schema with embedded available skills metadata."""
|
|
20
|
-
skills_xml = cls._generate_skills_xml()
|
|
21
|
-
|
|
22
|
-
return llm_param.ToolSchema(
|
|
23
|
-
name=tools.SKILL,
|
|
24
|
-
type="function",
|
|
25
|
-
description=load_desc(Path(__file__).parent / "skill_tool.md", {"skills_xml": skills_xml}),
|
|
26
|
-
parameters={
|
|
27
|
-
"type": "object",
|
|
28
|
-
"properties": {
|
|
29
|
-
"command": {
|
|
30
|
-
"type": "string",
|
|
31
|
-
"description": "Name of the skill to execute",
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"required": ["command"],
|
|
35
|
-
},
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
@classmethod
|
|
39
|
-
def _generate_skills_xml(cls) -> str:
|
|
40
|
-
"""Generate XML format skills metadata."""
|
|
41
|
-
skills = get_available_skills()
|
|
42
|
-
if not skills:
|
|
43
|
-
return ""
|
|
44
|
-
|
|
45
|
-
xml_parts: list[str] = []
|
|
46
|
-
for name, description, location in skills:
|
|
47
|
-
xml_parts.append(f"""<skill>
|
|
48
|
-
<name>{name}</name>
|
|
49
|
-
<description>{description}</description>
|
|
50
|
-
<location>{location}</location>
|
|
51
|
-
</skill>""")
|
|
52
|
-
return "\n".join(xml_parts)
|
|
53
|
-
|
|
54
|
-
class SkillArguments(BaseModel):
|
|
55
|
-
command: str
|
|
56
|
-
|
|
57
|
-
@classmethod
|
|
58
|
-
async def call(cls, arguments: str) -> message.ToolResultMessage:
|
|
59
|
-
"""Load and return full skill content."""
|
|
60
|
-
try:
|
|
61
|
-
args = cls.SkillArguments.model_validate_json(arguments)
|
|
62
|
-
except ValueError as e:
|
|
63
|
-
return message.ToolResultMessage(
|
|
64
|
-
status="error",
|
|
65
|
-
output_text=f"Invalid arguments: {e}",
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
skill = get_skill(args.command)
|
|
69
|
-
|
|
70
|
-
if not skill:
|
|
71
|
-
available = ", ".join(list_skill_names())
|
|
72
|
-
return message.ToolResultMessage(
|
|
73
|
-
status="error",
|
|
74
|
-
output_text=f"Skill '{args.command}' does not exist. Available skills: {available}",
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
# Get base directory from skill_path
|
|
78
|
-
base_dir = str(skill.skill_path.parent) if skill.skill_path else "unknown"
|
|
79
|
-
|
|
80
|
-
# Return with loading message format
|
|
81
|
-
result = f"""<command-message>The "{skill.name}" skill is activated</command-message>
|
|
82
|
-
<command-name>{skill.name}</command-name>
|
|
83
|
-
|
|
84
|
-
Base directory for this skill: {base_dir}
|
|
85
|
-
|
|
86
|
-
{skill.to_prompt()}"""
|
|
87
|
-
return message.ToolResultMessage(status="success", output_text=result)
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from collections.abc import Awaitable, Callable, Generator, MutableMapping
|
|
4
|
-
from contextlib import contextmanager
|
|
5
|
-
from contextvars import ContextVar, Token
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
|
|
8
|
-
from klaude_code.protocol import model
|
|
9
|
-
from klaude_code.protocol.sub_agent import SubAgentResult
|
|
10
|
-
from klaude_code.session.session import Session
|
|
11
|
-
|
|
12
|
-
type FileTracker = MutableMapping[str, model.FileStatus]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class TodoContext:
|
|
17
|
-
"""Todo access interface exposed to tools.
|
|
18
|
-
|
|
19
|
-
Tools can only read the current todo list and replace it with
|
|
20
|
-
a new list; they cannot access the full Session object.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
get_todos: Callable[[], list[model.TodoItem]]
|
|
24
|
-
set_todos: Callable[[list[model.TodoItem]], None]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@dataclass
|
|
28
|
-
class SessionTodoStore:
|
|
29
|
-
"""Adapter exposing session todos through an explicit interface."""
|
|
30
|
-
|
|
31
|
-
session: Session
|
|
32
|
-
|
|
33
|
-
def get(self) -> list[model.TodoItem]:
|
|
34
|
-
return self.session.todos
|
|
35
|
-
|
|
36
|
-
def set(self, todos: list[model.TodoItem]) -> None:
|
|
37
|
-
self.session.todos = todos
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass
|
|
41
|
-
class ToolContextToken:
|
|
42
|
-
"""Tokens used to restore tool execution context.
|
|
43
|
-
|
|
44
|
-
This captures the contextvar tokens for the current file tracker
|
|
45
|
-
and todo context so callers can safely reset them after a tool
|
|
46
|
-
finishes running.
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
file_tracker_token: Token[FileTracker | None] | None
|
|
50
|
-
todo_token: Token[TodoContext | None] | None
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# Holds the current file tracker mapping for tool execution context.
|
|
54
|
-
# Set by Agent/Reminder right before invoking a tool.
|
|
55
|
-
current_file_tracker_var: ContextVar[FileTracker | None] = ContextVar("current_file_tracker", default=None)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# Holds the todo access context for tools.
|
|
59
|
-
current_todo_context_var: ContextVar[TodoContext | None] = ContextVar("current_todo_context", default=None)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def set_tool_context_from_session(session: Session) -> ToolContextToken:
|
|
63
|
-
"""Bind the given session's file tracker and todos into tool context.
|
|
64
|
-
|
|
65
|
-
This should be called by the Agent or reminder helpers immediately
|
|
66
|
-
before invoking tools so that file and todo tools can operate on
|
|
67
|
-
the correct per-session state without seeing the full Session.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
file_tracker_token = current_file_tracker_var.set(session.file_tracker)
|
|
71
|
-
todo_ctx = build_todo_context(session)
|
|
72
|
-
todo_token = current_todo_context_var.set(todo_ctx)
|
|
73
|
-
return ToolContextToken(file_tracker_token=file_tracker_token, todo_token=todo_token)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def reset_tool_context(token: ToolContextToken) -> None:
|
|
77
|
-
"""Restore tool execution context from a previously captured token."""
|
|
78
|
-
|
|
79
|
-
if token.file_tracker_token is not None:
|
|
80
|
-
current_file_tracker_var.reset(token.file_tracker_token)
|
|
81
|
-
if token.todo_token is not None:
|
|
82
|
-
current_todo_context_var.reset(token.todo_token)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@contextmanager
|
|
86
|
-
def tool_context(file_tracker: FileTracker, todo_ctx: TodoContext) -> Generator[ToolContextToken]:
|
|
87
|
-
"""Context manager for setting and resetting tool execution context."""
|
|
88
|
-
|
|
89
|
-
file_tracker_token = current_file_tracker_var.set(file_tracker)
|
|
90
|
-
todo_token = current_todo_context_var.set(todo_ctx)
|
|
91
|
-
token = ToolContextToken(file_tracker_token=file_tracker_token, todo_token=todo_token)
|
|
92
|
-
try:
|
|
93
|
-
yield token
|
|
94
|
-
finally:
|
|
95
|
-
reset_tool_context(token)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def build_todo_context(session: Session) -> TodoContext:
|
|
99
|
-
"""Create a TodoContext backed by the given session."""
|
|
100
|
-
|
|
101
|
-
store = SessionTodoStore(session)
|
|
102
|
-
return TodoContext(get_todos=store.get, set_todos=store.set)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def get_current_file_tracker() -> FileTracker | None:
|
|
106
|
-
"""Return the current file tracker mapping for this tool context."""
|
|
107
|
-
|
|
108
|
-
return current_file_tracker_var.get()
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def get_current_todo_context() -> TodoContext | None:
|
|
112
|
-
"""Return the current todo access context for this tool context."""
|
|
113
|
-
|
|
114
|
-
return current_todo_context_var.get()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
# Holds a handle to run a nested subtask (sub-agent) from within a tool call.
|
|
118
|
-
# The callable takes a model.SubAgentState and returns a SubAgentResult.
|
|
119
|
-
current_run_subtask_callback: ContextVar[Callable[[model.SubAgentState], Awaitable[SubAgentResult]] | None] = (
|
|
120
|
-
ContextVar("current_run_subtask_callback", default=None)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
# Allows sub-agent execution to record the created/used session id for the currently
|
|
125
|
-
# executing tool call (used by ToolExecutor.cancel() to include session_id in UIExtra).
|
|
126
|
-
current_sub_agent_session_id_recorder: ContextVar[Callable[[str], None] | None] = ContextVar(
|
|
127
|
-
"current_sub_agent_session_id_recorder",
|
|
128
|
-
default=None,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def record_sub_agent_session_id(session_id: str) -> None:
|
|
133
|
-
"""Record the sub-agent session id for the current tool call, if supported."""
|
|
134
|
-
|
|
135
|
-
recorder = current_sub_agent_session_id_recorder.get()
|
|
136
|
-
if recorder is None:
|
|
137
|
-
return
|
|
138
|
-
recorder(session_id)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
# Tracks sub-agent resume claims for the current turn.
|
|
142
|
-
#
|
|
143
|
-
# This is used to reject multiple sub-agent tool calls in the same LLM response
|
|
144
|
-
# that attempt to resume the same agent ID.
|
|
145
|
-
current_sub_agent_resume_claims: ContextVar[set[str] | None] = ContextVar(
|
|
146
|
-
"current_sub_agent_resume_claims",
|
|
147
|
-
default=None,
|
|
148
|
-
)
|
klaude_code/protocol/events.py
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
from typing import Literal
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from klaude_code.protocol import llm_param, message, model
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
Event is how Agent Executor and UI Display communicate.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class EndEvent(BaseModel):
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ErrorEvent(BaseModel):
|
|
17
|
-
error_message: str
|
|
18
|
-
can_retry: bool = False
|
|
19
|
-
session_id: str | None = None
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class TaskStartEvent(BaseModel):
|
|
23
|
-
session_id: str
|
|
24
|
-
sub_agent_state: model.SubAgentState | None = None
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class TaskFinishEvent(BaseModel):
|
|
28
|
-
session_id: str
|
|
29
|
-
task_result: str
|
|
30
|
-
has_structured_output: bool = False
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class TurnStartEvent(BaseModel):
|
|
34
|
-
"""For now, this event is used for UI to flush developer message buffer and print an empty line"""
|
|
35
|
-
|
|
36
|
-
session_id: str
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class TurnEndEvent(BaseModel):
|
|
40
|
-
session_id: str
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class TurnToolCallStartEvent(BaseModel):
|
|
44
|
-
"""For UI changing status text"""
|
|
45
|
-
|
|
46
|
-
session_id: str
|
|
47
|
-
response_id: str | None = None
|
|
48
|
-
tool_call_id: str
|
|
49
|
-
tool_name: str
|
|
50
|
-
arguments: str
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class ThinkingDeltaEvent(BaseModel):
|
|
54
|
-
session_id: str
|
|
55
|
-
response_id: str | None = None
|
|
56
|
-
content: str
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class AssistantTextDeltaEvent(BaseModel):
|
|
60
|
-
session_id: str
|
|
61
|
-
response_id: str | None = None
|
|
62
|
-
content: str
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class AssistantImageDeltaEvent(BaseModel):
|
|
66
|
-
session_id: str
|
|
67
|
-
response_id: str | None = None
|
|
68
|
-
file_path: str
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
class AssistantMessageEvent(BaseModel):
|
|
72
|
-
response_id: str | None = None
|
|
73
|
-
session_id: str
|
|
74
|
-
content: str
|
|
75
|
-
thinking_text: str | None = None
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
class DeveloperMessageEvent(BaseModel):
|
|
79
|
-
"""DeveloperMessages are reminders in user messages or tool results, see: core/reminders.py"""
|
|
80
|
-
|
|
81
|
-
session_id: str
|
|
82
|
-
item: message.DeveloperMessage
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class ToolCallEvent(BaseModel):
|
|
86
|
-
session_id: str
|
|
87
|
-
response_id: str | None = None
|
|
88
|
-
tool_call_id: str
|
|
89
|
-
tool_name: str
|
|
90
|
-
arguments: str
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class ToolResultEvent(BaseModel):
|
|
94
|
-
session_id: str
|
|
95
|
-
response_id: str | None = None
|
|
96
|
-
tool_call_id: str
|
|
97
|
-
tool_name: str
|
|
98
|
-
result: str
|
|
99
|
-
ui_extra: model.ToolResultUIExtra | None = None
|
|
100
|
-
status: Literal["success", "error"]
|
|
101
|
-
task_metadata: model.TaskMetadata | None = None # Sub-agent task metadata
|
|
102
|
-
# Whether this tool result is the last one emitted in the current turn.
|
|
103
|
-
# Used by UI renderers to close tree-style prefixes.
|
|
104
|
-
is_last_in_turn: bool = True
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class ResponseMetadataEvent(BaseModel):
|
|
108
|
-
"""Internal event for turn-level metadata. Not exposed to UI directly."""
|
|
109
|
-
|
|
110
|
-
session_id: str
|
|
111
|
-
metadata: model.Usage
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class TaskMetadataEvent(BaseModel):
|
|
115
|
-
"""Task-level aggregated metadata for UI display."""
|
|
116
|
-
|
|
117
|
-
session_id: str
|
|
118
|
-
metadata: model.TaskMetadataItem
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
class UserMessageEvent(BaseModel):
|
|
122
|
-
session_id: str
|
|
123
|
-
content: str
|
|
124
|
-
images: list[message.ImageURLPart] | None = None
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class WelcomeEvent(BaseModel):
|
|
128
|
-
work_dir: str
|
|
129
|
-
llm_config: llm_param.LLMConfigParameter
|
|
130
|
-
show_klaude_code_info: bool = True
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
class InterruptEvent(BaseModel):
|
|
134
|
-
session_id: str
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
class TodoChangeEvent(BaseModel):
|
|
138
|
-
session_id: str
|
|
139
|
-
todos: list[model.TodoItem]
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
class ContextUsageEvent(BaseModel):
|
|
143
|
-
"""Real-time context usage update during task execution."""
|
|
144
|
-
|
|
145
|
-
session_id: str
|
|
146
|
-
context_percent: float # Context usage percentage (0-100)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
HistoryItemEvent = (
|
|
150
|
-
TaskStartEvent
|
|
151
|
-
| TaskFinishEvent
|
|
152
|
-
| TurnStartEvent # This event is used for UI to print new empty line
|
|
153
|
-
| AssistantImageDeltaEvent
|
|
154
|
-
| AssistantMessageEvent
|
|
155
|
-
| ToolCallEvent
|
|
156
|
-
| ToolResultEvent
|
|
157
|
-
| UserMessageEvent
|
|
158
|
-
| TaskMetadataEvent
|
|
159
|
-
| InterruptEvent
|
|
160
|
-
| DeveloperMessageEvent
|
|
161
|
-
| ErrorEvent
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
class ReplayHistoryEvent(BaseModel):
|
|
166
|
-
session_id: str
|
|
167
|
-
events: list[HistoryItemEvent]
|
|
168
|
-
updated_at: float
|
|
169
|
-
is_load: bool = True
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
Event = (
|
|
173
|
-
TaskStartEvent
|
|
174
|
-
| TaskFinishEvent
|
|
175
|
-
| ThinkingDeltaEvent
|
|
176
|
-
| AssistantTextDeltaEvent
|
|
177
|
-
| AssistantImageDeltaEvent
|
|
178
|
-
| AssistantMessageEvent
|
|
179
|
-
| ToolCallEvent
|
|
180
|
-
| ToolResultEvent
|
|
181
|
-
| ResponseMetadataEvent
|
|
182
|
-
| TaskMetadataEvent
|
|
183
|
-
| ReplayHistoryEvent
|
|
184
|
-
| ErrorEvent
|
|
185
|
-
| EndEvent
|
|
186
|
-
| WelcomeEvent
|
|
187
|
-
| UserMessageEvent
|
|
188
|
-
| InterruptEvent
|
|
189
|
-
| DeveloperMessageEvent
|
|
190
|
-
| TodoChangeEvent
|
|
191
|
-
| TurnStartEvent
|
|
192
|
-
| TurnEndEvent
|
|
193
|
-
| TurnToolCallStartEvent
|
|
194
|
-
| ContextUsageEvent
|
|
195
|
-
)
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: dev-docs
|
|
3
|
-
description: Manage development documentation for complex tasks. Use this skill when users want to create a strategic plan with structured task breakdown, or update development documentation before context compaction/reset. Triggers include "create a plan", "dev docs", "update docs before context reset", "context limit approaching".
|
|
4
|
-
metadata:
|
|
5
|
-
short-description: Create and update development documentation
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Dev Docs
|
|
9
|
-
|
|
10
|
-
Manage development documentation for complex, multi-phase tasks. This skill supports two workflows:
|
|
11
|
-
1. **Create**: Generate a comprehensive strategic plan with structured task breakdown
|
|
12
|
-
2. **Update**: Update documentation before context compaction or reset
|
|
13
|
-
|
|
14
|
-
## Create Development Plan
|
|
15
|
-
|
|
16
|
-
When creating a new plan:
|
|
17
|
-
|
|
18
|
-
1. **Analyze the request** and determine the scope of planning needed
|
|
19
|
-
2. **Examine relevant files** in the codebase to understand current state
|
|
20
|
-
3. **Create a structured plan** with:
|
|
21
|
-
- Executive Summary
|
|
22
|
-
- Current State Analysis
|
|
23
|
-
- Proposed Future State
|
|
24
|
-
- Implementation Phases (broken into sections)
|
|
25
|
-
- Detailed Tasks (actionable items with clear acceptance criteria)
|
|
26
|
-
- Risk Assessment and Mitigation Strategies
|
|
27
|
-
- Success Metrics
|
|
28
|
-
- Required Resources and Dependencies
|
|
29
|
-
|
|
30
|
-
4. **Task Breakdown Structure**:
|
|
31
|
-
- Each major section represents a phase or component
|
|
32
|
-
- Number and prioritize tasks within sections
|
|
33
|
-
- Include clear acceptance criteria for each task
|
|
34
|
-
- Specify dependencies between tasks
|
|
35
|
-
- Estimate effort levels (S/M/L/XL)
|
|
36
|
-
|
|
37
|
-
5. **Create task management structure**:
|
|
38
|
-
- Create directory: `dev/active/[task-name]/` (relative to project root)
|
|
39
|
-
- Generate three files:
|
|
40
|
-
- `[task-name]-plan.md` - The comprehensive plan
|
|
41
|
-
- `[task-name]-context.md` - Key files, decisions, dependencies
|
|
42
|
-
- `[task-name]-tasks.md` - Checklist format for tracking progress
|
|
43
|
-
- Include "Last Updated: YYYY-MM-DD" in each file
|
|
44
|
-
|
|
45
|
-
6. **Stop and Consult**: Pause and negotiate the plan with the user.
|
|
46
|
-
|
|
47
|
-
### Quality Standards
|
|
48
|
-
|
|
49
|
-
- Plans must be self-contained with all necessary context
|
|
50
|
-
- Use clear, actionable language
|
|
51
|
-
- Include specific technical details where relevant
|
|
52
|
-
- Consider both technical and business perspectives
|
|
53
|
-
- Account for potential risks and edge cases
|
|
54
|
-
|
|
55
|
-
## Update Development Documentation
|
|
56
|
-
|
|
57
|
-
When approaching context limits or before context reset:
|
|
58
|
-
|
|
59
|
-
### 1. Update Active Task Documentation
|
|
60
|
-
|
|
61
|
-
For each task in `/dev/active/`:
|
|
62
|
-
|
|
63
|
-
Update `[task-name]-context.md` with:
|
|
64
|
-
- Current implementation state
|
|
65
|
-
- Key decisions made this session
|
|
66
|
-
- Files modified and why
|
|
67
|
-
- Any blockers or issues discovered
|
|
68
|
-
- Next immediate steps
|
|
69
|
-
- Last Updated timestamp
|
|
70
|
-
|
|
71
|
-
Update `[task-name]-tasks.md` with:
|
|
72
|
-
- Mark completed tasks with checkmark
|
|
73
|
-
- Add any new tasks discovered
|
|
74
|
-
- Update in-progress tasks with current status
|
|
75
|
-
- Reorder priorities if needed
|
|
76
|
-
|
|
77
|
-
### 2. Capture Session Context
|
|
78
|
-
|
|
79
|
-
Include any relevant information about:
|
|
80
|
-
- Complex problems solved
|
|
81
|
-
- Architectural decisions made
|
|
82
|
-
- Tricky bugs found and fixed
|
|
83
|
-
- Integration points discovered
|
|
84
|
-
- Testing approaches used
|
|
85
|
-
- Performance optimizations made
|
|
86
|
-
|
|
87
|
-
### 3. Update Memory (if applicable)
|
|
88
|
-
|
|
89
|
-
- Store any new patterns or solutions in project memory/documentation
|
|
90
|
-
- Update entity relationships discovered
|
|
91
|
-
- Add observations about system behavior
|
|
92
|
-
|
|
93
|
-
### 4. Document Unfinished Work
|
|
94
|
-
|
|
95
|
-
- What was being worked on when context limit approached
|
|
96
|
-
- Exact state of any partially completed features
|
|
97
|
-
- Commands that need to be run on restart
|
|
98
|
-
- Any temporary workarounds that need permanent fixes
|
|
99
|
-
|
|
100
|
-
### 5. Create Handoff Notes
|
|
101
|
-
|
|
102
|
-
If switching to a new conversation:
|
|
103
|
-
- Exact file and line being edited
|
|
104
|
-
- The goal of current changes
|
|
105
|
-
- Any uncommitted changes that need attention
|
|
106
|
-
- Test commands to verify work
|
|
107
|
-
|
|
108
|
-
**Priority**: Focus on capturing information that would be hard to rediscover or reconstruct from code alone.
|
klaude_code/trace/__init__.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from .log import (
|
|
2
|
-
DebugType,
|
|
3
|
-
get_current_log_file,
|
|
4
|
-
is_debug_enabled,
|
|
5
|
-
log,
|
|
6
|
-
log_debug,
|
|
7
|
-
logger,
|
|
8
|
-
prepare_debug_log_file,
|
|
9
|
-
set_debug_logging,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
__all__ = [
|
|
13
|
-
"DebugType",
|
|
14
|
-
"get_current_log_file",
|
|
15
|
-
"is_debug_enabled",
|
|
16
|
-
"log",
|
|
17
|
-
"log_debug",
|
|
18
|
-
"logger",
|
|
19
|
-
"prepare_debug_log_file",
|
|
20
|
-
"set_debug_logging",
|
|
21
|
-
]
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from collections.abc import Awaitable, Callable
|
|
4
|
-
from enum import Enum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Stage(Enum):
|
|
8
|
-
WAITING = "waiting"
|
|
9
|
-
THINKING = "thinking"
|
|
10
|
-
ASSISTANT = "assistant"
|
|
11
|
-
TOOL_CALL = "tool_call"
|
|
12
|
-
TOOL_RESULT = "tool_result"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class StageManager:
|
|
16
|
-
"""Manage display stage transitions and invoke lifecycle callbacks."""
|
|
17
|
-
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
*,
|
|
21
|
-
finish_assistant: Callable[[], Awaitable[None]],
|
|
22
|
-
finish_thinking: Callable[[], Awaitable[None]],
|
|
23
|
-
):
|
|
24
|
-
self._stage = Stage.WAITING
|
|
25
|
-
self._finish_assistant = finish_assistant
|
|
26
|
-
self._finish_thinking = finish_thinking
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def current_stage(self) -> Stage:
|
|
30
|
-
return self._stage
|
|
31
|
-
|
|
32
|
-
async def transition_to(self, new_stage: Stage) -> None:
|
|
33
|
-
if self._stage == new_stage:
|
|
34
|
-
return
|
|
35
|
-
await self._leave_current_stage()
|
|
36
|
-
self._stage = new_stage
|
|
37
|
-
|
|
38
|
-
async def enter_thinking_stage(self) -> None:
|
|
39
|
-
if self._stage == Stage.THINKING:
|
|
40
|
-
return
|
|
41
|
-
await self.transition_to(Stage.THINKING)
|
|
42
|
-
|
|
43
|
-
async def _leave_current_stage(self) -> None:
|
|
44
|
-
if self._stage == Stage.THINKING:
|
|
45
|
-
await self._finish_thinking()
|
|
46
|
-
elif self._stage == Stage.ASSISTANT:
|
|
47
|
-
await self._finish_assistant()
|
|
48
|
-
self._stage = Stage.WAITING
|
klaude_code/ui/modes/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# UI mode implementations
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Debug mode
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Exec mode
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import contextlib
|
|
4
|
-
from typing import override
|
|
5
|
-
|
|
6
|
-
from klaude_code.protocol import events
|
|
7
|
-
from klaude_code.ui.core.display import DisplayABC
|
|
8
|
-
from klaude_code.ui.modes.repl.event_handler import DisplayEventHandler
|
|
9
|
-
from klaude_code.ui.modes.repl.renderer import REPLRenderer
|
|
10
|
-
from klaude_code.ui.terminal.notifier import TerminalNotifier
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class REPLDisplay(DisplayABC):
|
|
14
|
-
"""
|
|
15
|
-
Interactive terminal display using Rich for rendering.
|
|
16
|
-
|
|
17
|
-
REPLDisplay provides a full-featured terminal UI with:
|
|
18
|
-
- Rich markdown rendering for assistant messages
|
|
19
|
-
- Syntax-highlighted code blocks and diffs
|
|
20
|
-
- Animated spinners for in-progress operations
|
|
21
|
-
- Tool call and result visualization
|
|
22
|
-
- OSC94 error indicator (for supported terminals)
|
|
23
|
-
- Desktop notifications on task completion
|
|
24
|
-
|
|
25
|
-
This is the primary display mode for interactive klaude-code sessions.
|
|
26
|
-
For non-interactive use, see ExecDisplay. For debugging, wrap with
|
|
27
|
-
DebugEventDisplay.
|
|
28
|
-
|
|
29
|
-
Lifecycle:
|
|
30
|
-
1. start(): No-op (initialization happens in __init__)
|
|
31
|
-
2. consume_event(): Delegates to DisplayEventHandler for event processing
|
|
32
|
-
3. stop(): Stops the event handler and ensures spinner is cleaned up
|
|
33
|
-
|
|
34
|
-
Attributes:
|
|
35
|
-
renderer: The REPLRenderer instance for terminal output
|
|
36
|
-
notifier: TerminalNotifier for desktop notifications
|
|
37
|
-
event_handler: DisplayEventHandler that processes events
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
def __init__(self, theme: str | None = None, notifier: TerminalNotifier | None = None):
|
|
41
|
-
self.renderer = REPLRenderer(theme)
|
|
42
|
-
self.notifier = notifier or TerminalNotifier()
|
|
43
|
-
self.event_handler = DisplayEventHandler(self.renderer, notifier=self.notifier)
|
|
44
|
-
|
|
45
|
-
@override
|
|
46
|
-
async def consume_event(self, event: events.Event) -> None:
|
|
47
|
-
await self.event_handler.consume_event(event)
|
|
48
|
-
|
|
49
|
-
@override
|
|
50
|
-
async def start(self) -> None:
|
|
51
|
-
pass
|
|
52
|
-
|
|
53
|
-
@override
|
|
54
|
-
async def stop(self) -> None:
|
|
55
|
-
await self.event_handler.stop()
|
|
56
|
-
# Ensure any active spinner is stopped so Rich restores the cursor.
|
|
57
|
-
# Spinner may already be stopped or not started; ignore.
|
|
58
|
-
with contextlib.suppress(Exception):
|
|
59
|
-
self.renderer.spinner_stop()
|
|
60
|
-
with contextlib.suppress(Exception):
|
|
61
|
-
self.renderer.stop_bottom_live()
|