klaude-code 1.8.0__py3-none-any.whl → 2.0.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.
- klaude_code/auth/base.py +97 -0
- klaude_code/auth/claude/__init__.py +6 -0
- klaude_code/auth/claude/exceptions.py +9 -0
- klaude_code/auth/claude/oauth.py +172 -0
- klaude_code/auth/claude/token_manager.py +26 -0
- klaude_code/auth/codex/token_manager.py +10 -50
- klaude_code/cli/auth_cmd.py +127 -46
- klaude_code/cli/config_cmd.py +4 -2
- klaude_code/cli/cost_cmd.py +14 -9
- klaude_code/cli/list_model.py +248 -200
- klaude_code/cli/main.py +1 -1
- klaude_code/cli/runtime.py +7 -5
- klaude_code/cli/self_update.py +1 -1
- klaude_code/cli/session_cmd.py +1 -1
- klaude_code/command/clear_cmd.py +6 -2
- klaude_code/command/command_abc.py +2 -2
- klaude_code/command/debug_cmd.py +4 -4
- klaude_code/command/export_cmd.py +2 -2
- klaude_code/command/export_online_cmd.py +12 -12
- klaude_code/command/fork_session_cmd.py +29 -23
- klaude_code/command/help_cmd.py +4 -4
- klaude_code/command/model_cmd.py +4 -4
- klaude_code/command/model_select.py +1 -1
- klaude_code/command/prompt-commit.md +82 -0
- klaude_code/command/prompt_command.py +3 -3
- klaude_code/command/refresh_cmd.py +2 -2
- klaude_code/command/registry.py +7 -5
- klaude_code/command/release_notes_cmd.py +4 -4
- klaude_code/command/resume_cmd.py +15 -11
- klaude_code/command/status_cmd.py +4 -4
- klaude_code/command/terminal_setup_cmd.py +8 -8
- klaude_code/command/thinking_cmd.py +4 -4
- klaude_code/config/assets/builtin_config.yaml +52 -3
- klaude_code/config/builtin_config.py +16 -5
- klaude_code/config/config.py +31 -7
- klaude_code/config/thinking.py +4 -4
- klaude_code/const.py +146 -91
- klaude_code/core/agent.py +3 -12
- klaude_code/core/executor.py +21 -13
- klaude_code/core/manager/sub_agent_manager.py +71 -7
- klaude_code/core/prompt.py +1 -1
- klaude_code/core/prompts/prompt-sub-agent-image-gen.md +1 -0
- klaude_code/core/prompts/prompt-sub-agent-web.md +27 -1
- klaude_code/core/reminders.py +88 -69
- klaude_code/core/task.py +44 -45
- klaude_code/core/tool/file/apply_patch_tool.py +9 -9
- klaude_code/core/tool/file/diff_builder.py +3 -5
- klaude_code/core/tool/file/edit_tool.py +23 -23
- klaude_code/core/tool/file/move_tool.py +43 -43
- klaude_code/core/tool/file/read_tool.py +44 -39
- klaude_code/core/tool/file/write_tool.py +14 -14
- klaude_code/core/tool/report_back_tool.py +4 -4
- klaude_code/core/tool/shell/bash_tool.py +23 -23
- klaude_code/core/tool/skill/skill_tool.py +7 -7
- klaude_code/core/tool/sub_agent_tool.py +38 -9
- klaude_code/core/tool/todo/todo_write_tool.py +8 -8
- klaude_code/core/tool/todo/update_plan_tool.py +6 -6
- klaude_code/core/tool/tool_abc.py +2 -2
- klaude_code/core/tool/tool_context.py +27 -0
- klaude_code/core/tool/tool_runner.py +88 -42
- klaude_code/core/tool/truncation.py +38 -20
- klaude_code/core/tool/web/mermaid_tool.py +6 -7
- klaude_code/core/tool/web/web_fetch_tool.py +68 -30
- klaude_code/core/tool/web/web_search_tool.py +15 -17
- klaude_code/core/turn.py +120 -73
- klaude_code/llm/anthropic/client.py +104 -44
- klaude_code/llm/anthropic/input.py +116 -108
- klaude_code/llm/bedrock/client.py +8 -5
- klaude_code/llm/claude/__init__.py +3 -0
- klaude_code/llm/claude/client.py +105 -0
- klaude_code/llm/client.py +4 -3
- klaude_code/llm/codex/client.py +16 -10
- klaude_code/llm/google/client.py +122 -60
- klaude_code/llm/google/input.py +94 -108
- klaude_code/llm/image.py +123 -0
- klaude_code/llm/input_common.py +136 -189
- klaude_code/llm/openai_compatible/client.py +17 -7
- klaude_code/llm/openai_compatible/input.py +36 -66
- klaude_code/llm/openai_compatible/stream.py +119 -67
- klaude_code/llm/openai_compatible/tool_call_accumulator.py +23 -11
- klaude_code/llm/openrouter/client.py +34 -9
- klaude_code/llm/openrouter/input.py +63 -64
- klaude_code/llm/openrouter/reasoning.py +22 -24
- klaude_code/llm/registry.py +20 -15
- klaude_code/llm/responses/client.py +107 -45
- klaude_code/llm/responses/input.py +115 -98
- klaude_code/llm/usage.py +52 -25
- klaude_code/protocol/__init__.py +1 -0
- klaude_code/protocol/events.py +16 -12
- klaude_code/protocol/llm_param.py +22 -3
- klaude_code/protocol/message.py +250 -0
- klaude_code/protocol/model.py +94 -281
- klaude_code/protocol/op.py +2 -2
- klaude_code/protocol/sub_agent/__init__.py +2 -2
- klaude_code/protocol/sub_agent/explore.py +10 -0
- klaude_code/protocol/sub_agent/image_gen.py +119 -0
- klaude_code/protocol/sub_agent/task.py +10 -0
- klaude_code/protocol/sub_agent/web.py +10 -0
- klaude_code/session/codec.py +6 -6
- klaude_code/session/export.py +261 -62
- klaude_code/session/selector.py +7 -24
- klaude_code/session/session.py +125 -53
- klaude_code/session/store.py +5 -32
- klaude_code/session/templates/export_session.html +1 -1
- klaude_code/session/templates/mermaid_viewer.html +1 -1
- klaude_code/trace/log.py +11 -6
- klaude_code/ui/core/input.py +1 -1
- klaude_code/ui/core/stage_manager.py +1 -8
- klaude_code/ui/modes/debug/display.py +2 -2
- klaude_code/ui/modes/repl/clipboard.py +2 -2
- klaude_code/ui/modes/repl/completers.py +18 -10
- klaude_code/ui/modes/repl/event_handler.py +136 -127
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
- klaude_code/ui/modes/repl/key_bindings.py +1 -1
- klaude_code/ui/modes/repl/renderer.py +107 -15
- klaude_code/ui/renderers/assistant.py +2 -2
- klaude_code/ui/renderers/common.py +65 -7
- klaude_code/ui/renderers/developer.py +7 -6
- klaude_code/ui/renderers/diffs.py +11 -11
- klaude_code/ui/renderers/mermaid_viewer.py +49 -2
- klaude_code/ui/renderers/metadata.py +39 -31
- klaude_code/ui/renderers/sub_agent.py +57 -16
- klaude_code/ui/renderers/thinking.py +37 -2
- klaude_code/ui/renderers/tools.py +180 -165
- klaude_code/ui/rich/live.py +3 -1
- klaude_code/ui/rich/markdown.py +39 -7
- klaude_code/ui/rich/quote.py +76 -1
- klaude_code/ui/rich/status.py +14 -8
- klaude_code/ui/rich/theme.py +13 -6
- klaude_code/ui/terminal/image.py +34 -0
- klaude_code/ui/terminal/notifier.py +2 -1
- klaude_code/ui/terminal/progress_bar.py +4 -4
- klaude_code/ui/terminal/selector.py +22 -4
- klaude_code/ui/utils/common.py +55 -0
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/METADATA +28 -6
- klaude_code-2.0.0.dist-info/RECORD +229 -0
- klaude_code/command/prompt-jj-describe.md +0 -32
- klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -22
- klaude_code/protocol/sub_agent/oracle.py +0 -91
- klaude_code-1.8.0.dist-info/RECORD +0 -219
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/WHEEL +0 -0
- {klaude_code-1.8.0.dist-info → klaude_code-2.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -10,7 +10,7 @@ from rich.console import Console
|
|
|
10
10
|
from rich.text import Text
|
|
11
11
|
|
|
12
12
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
13
|
-
from klaude_code.protocol import commands, events, model
|
|
13
|
+
from klaude_code.protocol import commands, events, message, model
|
|
14
14
|
from klaude_code.session.export import build_export_html
|
|
15
15
|
|
|
16
16
|
|
|
@@ -33,15 +33,15 @@ class ExportOnlineCommand(CommandABC):
|
|
|
33
33
|
def is_interactive(self) -> bool:
|
|
34
34
|
return False
|
|
35
35
|
|
|
36
|
-
async def run(self, agent: Agent, user_input:
|
|
36
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
37
37
|
del user_input # unused
|
|
38
38
|
# Check if npx or surge is available
|
|
39
39
|
surge_cmd = self._get_surge_command()
|
|
40
40
|
if not surge_cmd:
|
|
41
41
|
event = events.DeveloperMessageEvent(
|
|
42
42
|
session_id=agent.session.id,
|
|
43
|
-
item=
|
|
44
|
-
|
|
43
|
+
item=message.DeveloperMessage(
|
|
44
|
+
parts=message.text_parts_from_str("surge.sh CLI not found. Install with: npm install -g surge"),
|
|
45
45
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
46
46
|
),
|
|
47
47
|
)
|
|
@@ -50,29 +50,29 @@ class ExportOnlineCommand(CommandABC):
|
|
|
50
50
|
try:
|
|
51
51
|
console = Console()
|
|
52
52
|
# Check login status inside status context since npx surge whoami can be slow
|
|
53
|
-
with console.status(Text("Checking surge.sh login status
|
|
53
|
+
with console.status(Text("Checking surge.sh login status…", style="dim"), spinner_style="dim"):
|
|
54
54
|
logged_in = self._is_surge_logged_in(surge_cmd)
|
|
55
55
|
|
|
56
56
|
if not logged_in:
|
|
57
57
|
login_cmd = " ".join([*surge_cmd, "login"])
|
|
58
58
|
event = events.DeveloperMessageEvent(
|
|
59
59
|
session_id=agent.session.id,
|
|
60
|
-
item=
|
|
61
|
-
|
|
60
|
+
item=message.DeveloperMessage(
|
|
61
|
+
parts=message.text_parts_from_str(f"Not logged in to surge.sh. Please run: {login_cmd}"),
|
|
62
62
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
63
63
|
),
|
|
64
64
|
)
|
|
65
65
|
return CommandResult(events=[event])
|
|
66
66
|
|
|
67
|
-
with console.status(Text("Deploying to surge.sh
|
|
67
|
+
with console.status(Text("Deploying to surge.sh…", style="dim"), spinner_style="dim"):
|
|
68
68
|
html_doc = self._build_html(agent)
|
|
69
69
|
domain = self._generate_domain()
|
|
70
70
|
url = self._deploy_to_surge(surge_cmd, html_doc, domain)
|
|
71
71
|
|
|
72
72
|
event = events.DeveloperMessageEvent(
|
|
73
73
|
session_id=agent.session.id,
|
|
74
|
-
item=
|
|
75
|
-
|
|
74
|
+
item=message.DeveloperMessage(
|
|
75
|
+
parts=message.text_parts_from_str(f"Session deployed to: {url}"),
|
|
76
76
|
command_output=model.CommandOutput(command_name=self.name),
|
|
77
77
|
),
|
|
78
78
|
)
|
|
@@ -82,8 +82,8 @@ class ExportOnlineCommand(CommandABC):
|
|
|
82
82
|
|
|
83
83
|
event = events.DeveloperMessageEvent(
|
|
84
84
|
session_id=agent.session.id,
|
|
85
|
-
item=
|
|
86
|
-
|
|
85
|
+
item=message.DeveloperMessage(
|
|
86
|
+
parts=message.text_parts_from_str(f"Failed to deploy session: {exc}\n{traceback.format_exc()}"),
|
|
87
87
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
88
88
|
),
|
|
89
89
|
)
|
|
@@ -6,7 +6,7 @@ from typing import Literal
|
|
|
6
6
|
from prompt_toolkit.styles import Style
|
|
7
7
|
|
|
8
8
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
9
|
-
from klaude_code.protocol import commands, events, model
|
|
9
|
+
from klaude_code.protocol import commands, events, message, model
|
|
10
10
|
from klaude_code.ui.modes.repl.clipboard import copy_to_clipboard
|
|
11
11
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
12
12
|
|
|
@@ -41,29 +41,29 @@ def _truncate(text: str, max_len: int = 60) -> str:
|
|
|
41
41
|
text = text.replace("\n", " ").strip()
|
|
42
42
|
if len(text) <= max_len:
|
|
43
43
|
return text
|
|
44
|
-
return text[: max_len -
|
|
44
|
+
return text[: max_len - 1] + "…"
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def _build_fork_points(conversation_history: list[
|
|
47
|
+
def _build_fork_points(conversation_history: list[message.HistoryEvent]) -> list[ForkPoint]:
|
|
48
48
|
"""Build list of fork points from conversation history.
|
|
49
49
|
|
|
50
50
|
Fork points are:
|
|
51
|
-
- Each
|
|
51
|
+
- Each UserMessage position (for UI display, including first which would be empty session)
|
|
52
52
|
- The end of the conversation (fork entire conversation)
|
|
53
53
|
"""
|
|
54
54
|
fork_points: list[ForkPoint] = []
|
|
55
55
|
user_indices: list[int] = []
|
|
56
56
|
|
|
57
57
|
for i, item in enumerate(conversation_history):
|
|
58
|
-
if isinstance(item,
|
|
58
|
+
if isinstance(item, message.UserMessage):
|
|
59
59
|
user_indices.append(i)
|
|
60
60
|
|
|
61
|
-
# For each
|
|
61
|
+
# For each UserMessage, create a fork point at that position
|
|
62
62
|
for i, user_idx in enumerate(user_indices):
|
|
63
63
|
user_item = conversation_history[user_idx]
|
|
64
|
-
assert isinstance(user_item,
|
|
64
|
+
assert isinstance(user_item, message.UserMessage)
|
|
65
65
|
|
|
66
|
-
# Find the end of this "task" (next
|
|
66
|
+
# Find the end of this "task" (next UserMessage or end of history)
|
|
67
67
|
next_user_idx = user_indices[i + 1] if i + 1 < len(user_indices) else len(conversation_history)
|
|
68
68
|
|
|
69
69
|
# Count tool calls by name and find last assistant message in this segment
|
|
@@ -71,15 +71,19 @@ def _build_fork_points(conversation_history: list[model.ConversationItem]) -> li
|
|
|
71
71
|
last_assistant_content = ""
|
|
72
72
|
for j in range(user_idx, next_user_idx):
|
|
73
73
|
item = conversation_history[j]
|
|
74
|
-
if isinstance(item,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
if isinstance(item, message.AssistantMessage):
|
|
75
|
+
for part in item.parts:
|
|
76
|
+
if isinstance(part, message.ToolCallPart):
|
|
77
|
+
tool_stats[part.tool_name] = tool_stats.get(part.tool_name, 0) + 1
|
|
78
|
+
text = message.join_text_parts(item.parts)
|
|
79
|
+
if text:
|
|
80
|
+
last_assistant_content = text
|
|
81
|
+
|
|
82
|
+
user_text = message.join_text_parts(user_item.parts)
|
|
79
83
|
fork_points.append(
|
|
80
84
|
ForkPoint(
|
|
81
85
|
history_index=user_idx,
|
|
82
|
-
user_message=
|
|
86
|
+
user_message=user_text or "(empty)",
|
|
83
87
|
tool_call_stats=tool_stats,
|
|
84
88
|
last_assistant_summary=_truncate(last_assistant_content) if last_assistant_content else "",
|
|
85
89
|
)
|
|
@@ -195,14 +199,14 @@ class ForkSessionCommand(CommandABC):
|
|
|
195
199
|
def is_interactive(self) -> bool:
|
|
196
200
|
return True
|
|
197
201
|
|
|
198
|
-
async def run(self, agent: Agent, user_input:
|
|
202
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
199
203
|
del user_input # unused
|
|
200
204
|
|
|
201
205
|
if agent.session.messages_count == 0:
|
|
202
206
|
event = events.DeveloperMessageEvent(
|
|
203
207
|
session_id=agent.session.id,
|
|
204
|
-
item=
|
|
205
|
-
|
|
208
|
+
item=message.DeveloperMessage(
|
|
209
|
+
parts=message.text_parts_from_str("(no messages to fork)"),
|
|
206
210
|
command_output=model.CommandOutput(command_name=self.name),
|
|
207
211
|
),
|
|
208
212
|
)
|
|
@@ -221,8 +225,8 @@ class ForkSessionCommand(CommandABC):
|
|
|
221
225
|
|
|
222
226
|
event = events.DeveloperMessageEvent(
|
|
223
227
|
session_id=agent.session.id,
|
|
224
|
-
item=
|
|
225
|
-
|
|
228
|
+
item=message.DeveloperMessage(
|
|
229
|
+
parts=message.text_parts_from_str(f"Session forked successfully. New session id: {new_session.id}"),
|
|
226
230
|
command_output=model.CommandOutput(
|
|
227
231
|
command_name=self.name,
|
|
228
232
|
ui_extra=model.SessionIdUIExtra(session_id=new_session.id),
|
|
@@ -237,8 +241,8 @@ class ForkSessionCommand(CommandABC):
|
|
|
237
241
|
if selected == "cancelled":
|
|
238
242
|
event = events.DeveloperMessageEvent(
|
|
239
243
|
session_id=agent.session.id,
|
|
240
|
-
item=
|
|
241
|
-
|
|
244
|
+
item=message.DeveloperMessage(
|
|
245
|
+
parts=message.text_parts_from_str("(fork cancelled)"),
|
|
242
246
|
command_output=model.CommandOutput(command_name=self.name),
|
|
243
247
|
),
|
|
244
248
|
)
|
|
@@ -256,8 +260,10 @@ class ForkSessionCommand(CommandABC):
|
|
|
256
260
|
|
|
257
261
|
event = events.DeveloperMessageEvent(
|
|
258
262
|
session_id=agent.session.id,
|
|
259
|
-
item=
|
|
260
|
-
|
|
263
|
+
item=message.DeveloperMessage(
|
|
264
|
+
parts=message.text_parts_from_str(
|
|
265
|
+
f"Session forked ({fork_description}). New session id: {new_session.id}"
|
|
266
|
+
),
|
|
261
267
|
command_output=model.CommandOutput(
|
|
262
268
|
command_name=self.name,
|
|
263
269
|
ui_extra=model.SessionIdUIExtra(session_id=new_session.id),
|
klaude_code/command/help_cmd.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
2
|
-
from klaude_code.protocol import commands, events, model
|
|
2
|
+
from klaude_code.protocol import commands, events, message, model
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class HelpCommand(CommandABC):
|
|
@@ -13,7 +13,7 @@ class HelpCommand(CommandABC):
|
|
|
13
13
|
def summary(self) -> str:
|
|
14
14
|
return "Show help and available commands"
|
|
15
15
|
|
|
16
|
-
async def run(self, agent: Agent, user_input:
|
|
16
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
17
17
|
del user_input # unused
|
|
18
18
|
lines: list[str] = [
|
|
19
19
|
"""
|
|
@@ -41,8 +41,8 @@ Available slash commands:"""
|
|
|
41
41
|
|
|
42
42
|
event = events.DeveloperMessageEvent(
|
|
43
43
|
session_id=agent.session.id,
|
|
44
|
-
item=
|
|
45
|
-
|
|
44
|
+
item=message.DeveloperMessage(
|
|
45
|
+
parts=message.text_parts_from_str("\n".join(lines)),
|
|
46
46
|
command_output=model.CommandOutput(command_name=self.name),
|
|
47
47
|
),
|
|
48
48
|
)
|
klaude_code/command/model_cmd.py
CHANGED
|
@@ -4,7 +4,7 @@ from prompt_toolkit.styles import Style
|
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
6
|
from klaude_code.command.model_select import select_model_interactive
|
|
7
|
-
from klaude_code.protocol import commands, events, model, op
|
|
7
|
+
from klaude_code.protocol import commands, events, message, model, op
|
|
8
8
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
9
9
|
|
|
10
10
|
SELECT_STYLE = Style(
|
|
@@ -65,7 +65,7 @@ class ModelCommand(CommandABC):
|
|
|
65
65
|
def placeholder(self) -> str:
|
|
66
66
|
return "model name"
|
|
67
67
|
|
|
68
|
-
async def run(self, agent: Agent, user_input:
|
|
68
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
69
69
|
selected_model = await asyncio.to_thread(select_model_interactive, preferred=user_input.text)
|
|
70
70
|
|
|
71
71
|
current_model = agent.profile.llm_client.model_name if agent.profile else None
|
|
@@ -74,8 +74,8 @@ class ModelCommand(CommandABC):
|
|
|
74
74
|
events=[
|
|
75
75
|
events.DeveloperMessageEvent(
|
|
76
76
|
session_id=agent.session.id,
|
|
77
|
-
item=
|
|
78
|
-
|
|
77
|
+
item=message.DeveloperMessage(
|
|
78
|
+
parts=message.text_parts_from_str("(no change)"),
|
|
79
79
|
command_output=model.CommandOutput(command_name=self.name),
|
|
80
80
|
),
|
|
81
81
|
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Commit current git changes
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
### Step 1: Detect version control system
|
|
8
|
+
|
|
9
|
+
Check if `jj` is available in the current environment. (check in your <env> tag)
|
|
10
|
+
|
|
11
|
+
### Step 2: Run pre-commit checks
|
|
12
|
+
|
|
13
|
+
Before creating a commit, run the following checks:
|
|
14
|
+
|
|
15
|
+
1. Run the project's linter to check and fix code style issues
|
|
16
|
+
2. Run the project's test suite to ensure all tests pass
|
|
17
|
+
3. If either check fails, stop the commit process and report the errors to the user
|
|
18
|
+
4. If both checks pass, proceed to the next step
|
|
19
|
+
|
|
20
|
+
### Step 3A: If jj is available
|
|
21
|
+
|
|
22
|
+
1. Run `jj status` and `jj log -r 'ancestors(@, 10)'` to see working copy changes and the last 10 changes
|
|
23
|
+
2. For each change that has no description (shows as "(no description set)"):
|
|
24
|
+
- Run `jj diff -r <change_id> --git` to view the diff
|
|
25
|
+
- Read related files if needed to understand the context
|
|
26
|
+
- Use `jj describe -r <change_id>` to add a meaningful description
|
|
27
|
+
|
|
28
|
+
### Step 2B: If jj is not available (git)
|
|
29
|
+
|
|
30
|
+
1. Run `git status` to check working directory state
|
|
31
|
+
2. Run `git diff --cached` to check if there are staged changes
|
|
32
|
+
3. If staging area has content:
|
|
33
|
+
- Ask the user: "Staging area has changes. Commit only staged changes, or stage and commit all changes?"
|
|
34
|
+
- If user chooses staged only: proceed with staged changes
|
|
35
|
+
- If user chooses all: run `git add -A` first
|
|
36
|
+
4. If staging area is empty:
|
|
37
|
+
- Run `git add -A` to stage all changes
|
|
38
|
+
5. Review the changes with `git diff --cached`
|
|
39
|
+
6. Create the commit
|
|
40
|
+
|
|
41
|
+
## Commit Message Format
|
|
42
|
+
|
|
43
|
+
In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC:
|
|
44
|
+
|
|
45
|
+
For jj:
|
|
46
|
+
```bash
|
|
47
|
+
jj describe -m "$(cat <<'EOF'
|
|
48
|
+
Commit message here.
|
|
49
|
+
EOF
|
|
50
|
+
)"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For git:
|
|
54
|
+
```bash
|
|
55
|
+
git commit -m "$(cat <<'EOF'
|
|
56
|
+
Commit message here.
|
|
57
|
+
EOF
|
|
58
|
+
)"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Message Style
|
|
62
|
+
|
|
63
|
+
Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
<type>(<scope>): <description>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Types:
|
|
70
|
+
- `feat`: New feature
|
|
71
|
+
- `fix`: Bug fix
|
|
72
|
+
- `docs`: Documentation changes
|
|
73
|
+
- `style`: Code style changes (formatting, no logic change)
|
|
74
|
+
- `refactor`: Code refactoring (no feature or fix)
|
|
75
|
+
- `test`: Adding or updating tests
|
|
76
|
+
- `chore`: Build process, dependencies, or tooling changes
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
- `feat(cli): add --verbose flag for debug output`
|
|
80
|
+
- `fix(llm): handle API timeout errors gracefully`
|
|
81
|
+
- `docs(readme): update installation instructions`
|
|
82
|
+
- `refactor(core): simplify session state management`
|
|
@@ -3,7 +3,7 @@ from importlib.resources import files
|
|
|
3
3
|
import yaml
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
|
-
from klaude_code.protocol import commands,
|
|
6
|
+
from klaude_code.protocol import commands, message, op
|
|
7
7
|
from klaude_code.trace import log_debug
|
|
8
8
|
|
|
9
9
|
|
|
@@ -55,7 +55,7 @@ class PromptCommand(CommandABC):
|
|
|
55
55
|
def support_addition_params(self) -> bool:
|
|
56
56
|
return True
|
|
57
57
|
|
|
58
|
-
async def run(self, agent: Agent, user_input:
|
|
58
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
59
59
|
self._ensure_loaded()
|
|
60
60
|
template_content = self._content or ""
|
|
61
61
|
user_input_text = user_input.text.strip() or "<none>"
|
|
@@ -71,7 +71,7 @@ class PromptCommand(CommandABC):
|
|
|
71
71
|
operations=[
|
|
72
72
|
op.RunAgentOperation(
|
|
73
73
|
session_id=agent.session.id,
|
|
74
|
-
input=
|
|
74
|
+
input=message.UserInputPayload(text=final_prompt, images=user_input.images),
|
|
75
75
|
)
|
|
76
76
|
]
|
|
77
77
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
2
|
-
from klaude_code.protocol import commands, events,
|
|
2
|
+
from klaude_code.protocol import commands, events, message
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class RefreshTerminalCommand(CommandABC):
|
|
@@ -17,7 +17,7 @@ class RefreshTerminalCommand(CommandABC):
|
|
|
17
17
|
def is_interactive(self) -> bool:
|
|
18
18
|
return True
|
|
19
19
|
|
|
20
|
-
async def run(self, agent: Agent, user_input:
|
|
20
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
21
21
|
del user_input # unused
|
|
22
22
|
import os
|
|
23
23
|
|
klaude_code/command/registry.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
|
|
4
4
|
from klaude_code.command.command_abc import Agent, CommandResult
|
|
5
5
|
from klaude_code.command.prompt_command import PromptCommand
|
|
6
|
-
from klaude_code.protocol import commands, events, model, op
|
|
6
|
+
from klaude_code.protocol import commands, events, message, model, op
|
|
7
7
|
from klaude_code.trace import log_debug
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
@@ -133,7 +133,7 @@ def is_slash_command_name(name: str) -> bool:
|
|
|
133
133
|
return _resolve_command_key(name) is not None
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
async def dispatch_command(user_input:
|
|
136
|
+
async def dispatch_command(user_input: message.UserInputPayload, agent: Agent, *, submission_id: str) -> CommandResult:
|
|
137
137
|
_ensure_commands_loaded()
|
|
138
138
|
# Detect command name
|
|
139
139
|
raw = user_input.text
|
|
@@ -168,7 +168,7 @@ async def dispatch_command(user_input: model.UserInputPayload, agent: Agent, *,
|
|
|
168
168
|
command_identifier: commands.CommandName | str = command.name
|
|
169
169
|
|
|
170
170
|
try:
|
|
171
|
-
user_input_for_command =
|
|
171
|
+
user_input_for_command = message.UserInputPayload(text=rest, images=user_input.images)
|
|
172
172
|
result = await command.run(agent, user_input_for_command)
|
|
173
173
|
ops = list(result.operations or [])
|
|
174
174
|
for operation in ops:
|
|
@@ -187,8 +187,10 @@ async def dispatch_command(user_input: model.UserInputPayload, agent: Agent, *,
|
|
|
187
187
|
events=[
|
|
188
188
|
events.DeveloperMessageEvent(
|
|
189
189
|
session_id=agent.session.id,
|
|
190
|
-
item=
|
|
191
|
-
|
|
190
|
+
item=message.DeveloperMessage(
|
|
191
|
+
parts=message.text_parts_from_str(
|
|
192
|
+
f"Command {command_identifier} error: [{e.__class__.__name__}] {e!s}"
|
|
193
|
+
),
|
|
192
194
|
command_output=command_output,
|
|
193
195
|
),
|
|
194
196
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
4
|
-
from klaude_code.protocol import commands, events, model
|
|
4
|
+
from klaude_code.protocol import commands, events, message, model
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def _read_changelog() -> str:
|
|
@@ -68,15 +68,15 @@ class ReleaseNotesCommand(CommandABC):
|
|
|
68
68
|
def summary(self) -> str:
|
|
69
69
|
return "Show the latest release notes"
|
|
70
70
|
|
|
71
|
-
async def run(self, agent: Agent, user_input:
|
|
71
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
72
72
|
del user_input # unused
|
|
73
73
|
changelog = _read_changelog()
|
|
74
74
|
content = _extract_releases(changelog, count=10)
|
|
75
75
|
|
|
76
76
|
event = events.DeveloperMessageEvent(
|
|
77
77
|
session_id=agent.session.id,
|
|
78
|
-
item=
|
|
79
|
-
|
|
78
|
+
item=message.DeveloperMessage(
|
|
79
|
+
parts=message.text_parts_from_str(content),
|
|
80
80
|
command_output=model.CommandOutput(command_name=self.name),
|
|
81
81
|
),
|
|
82
82
|
)
|
|
@@ -3,7 +3,7 @@ import asyncio
|
|
|
3
3
|
from prompt_toolkit.styles import Style
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
|
-
from klaude_code.protocol import commands, events, model, op
|
|
6
|
+
from klaude_code.protocol import commands, events, message, model, op
|
|
7
7
|
from klaude_code.session.selector import build_session_select_options, format_user_messages_display
|
|
8
8
|
from klaude_code.trace import log
|
|
9
9
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
@@ -35,14 +35,16 @@ def select_session_sync() -> str | None:
|
|
|
35
35
|
display_msgs = format_user_messages_display(opt.user_messages)
|
|
36
36
|
title: list[tuple[str, str]] = []
|
|
37
37
|
title.append(("fg:ansibrightblack", f"{idx:2}. "))
|
|
38
|
-
title.append(
|
|
39
|
-
|
|
40
|
-
)
|
|
41
|
-
|
|
38
|
+
title.append(("class:meta", f"{opt.relative_time} · {opt.messages_count} · {opt.model_name}"))
|
|
39
|
+
title.append(("fg:ansibrightblack dim", f" · {opt.session_id}\n"))
|
|
40
|
+
for i, msg in enumerate(display_msgs):
|
|
41
|
+
is_last = i == len(display_msgs) - 1
|
|
42
42
|
if msg == "⋮":
|
|
43
43
|
title.append(("class:msg", f" {msg}\n"))
|
|
44
44
|
else:
|
|
45
|
-
|
|
45
|
+
prefix = "└─" if is_last else "├─"
|
|
46
|
+
title.append(("fg:ansibrightblack dim", f" {prefix} "))
|
|
47
|
+
title.append(("class:msg", f"{msg}\n"))
|
|
46
48
|
title.append(("", "\n"))
|
|
47
49
|
|
|
48
50
|
search_text = " ".join(opt.user_messages) + f" {opt.model_name} {opt.session_id}"
|
|
@@ -80,14 +82,16 @@ class ResumeCommand(CommandABC):
|
|
|
80
82
|
def is_interactive(self) -> bool:
|
|
81
83
|
return True
|
|
82
84
|
|
|
83
|
-
async def run(self, agent: Agent, user_input:
|
|
85
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
84
86
|
del user_input # unused
|
|
85
87
|
|
|
86
88
|
if agent.session.messages_count > 0:
|
|
87
89
|
event = events.DeveloperMessageEvent(
|
|
88
90
|
session_id=agent.session.id,
|
|
89
|
-
item=
|
|
90
|
-
|
|
91
|
+
item=message.DeveloperMessage(
|
|
92
|
+
parts=message.text_parts_from_str(
|
|
93
|
+
"Cannot resume: current session already has messages. Use `klaude -r` to start a new instance with session selection."
|
|
94
|
+
),
|
|
91
95
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
92
96
|
),
|
|
93
97
|
)
|
|
@@ -97,8 +101,8 @@ class ResumeCommand(CommandABC):
|
|
|
97
101
|
if selected_session_id is None:
|
|
98
102
|
event = events.DeveloperMessageEvent(
|
|
99
103
|
session_id=agent.session.id,
|
|
100
|
-
item=
|
|
101
|
-
|
|
104
|
+
item=message.DeveloperMessage(
|
|
105
|
+
parts=message.text_parts_from_str("(no session selected)"),
|
|
102
106
|
command_output=model.CommandOutput(command_name=self.name),
|
|
103
107
|
),
|
|
104
108
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
2
|
-
from klaude_code.protocol import commands, events, model
|
|
2
|
+
from klaude_code.protocol import commands, events, message, model
|
|
3
3
|
from klaude_code.session.session import Session
|
|
4
4
|
|
|
5
5
|
|
|
@@ -132,15 +132,15 @@ class StatusCommand(CommandABC):
|
|
|
132
132
|
def summary(self) -> str:
|
|
133
133
|
return "Show session usage statistics"
|
|
134
134
|
|
|
135
|
-
async def run(self, agent: Agent, user_input:
|
|
135
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
136
136
|
del user_input # unused
|
|
137
137
|
session = agent.session
|
|
138
138
|
aggregated = accumulate_session_usage(session)
|
|
139
139
|
|
|
140
140
|
event = events.DeveloperMessageEvent(
|
|
141
141
|
session_id=session.id,
|
|
142
|
-
item=
|
|
143
|
-
|
|
142
|
+
item=message.DeveloperMessage(
|
|
143
|
+
parts=message.text_parts_from_str(format_status_content(aggregated)),
|
|
144
144
|
command_output=model.CommandOutput(
|
|
145
145
|
command_name=self.name,
|
|
146
146
|
ui_extra=model.SessionStatusUIExtra(
|
|
@@ -3,7 +3,7 @@ import subprocess
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
|
-
from klaude_code.protocol import commands, events, model
|
|
6
|
+
from klaude_code.protocol import commands, events, message, model
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TerminalSetupCommand(CommandABC):
|
|
@@ -21,7 +21,7 @@ class TerminalSetupCommand(CommandABC):
|
|
|
21
21
|
def is_interactive(self) -> bool:
|
|
22
22
|
return False
|
|
23
23
|
|
|
24
|
-
async def run(self, agent: Agent, user_input:
|
|
24
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
25
25
|
del user_input # unused
|
|
26
26
|
term_program = os.environ.get("TERM_PROGRAM", "").lower()
|
|
27
27
|
|
|
@@ -221,28 +221,28 @@ class TerminalSetupCommand(CommandABC):
|
|
|
221
221
|
|
|
222
222
|
return message
|
|
223
223
|
|
|
224
|
-
def _create_success_result(self, agent: "Agent",
|
|
224
|
+
def _create_success_result(self, agent: "Agent", msg: str) -> CommandResult:
|
|
225
225
|
"""Create success result"""
|
|
226
226
|
return CommandResult(
|
|
227
227
|
events=[
|
|
228
228
|
events.DeveloperMessageEvent(
|
|
229
229
|
session_id=agent.session.id,
|
|
230
|
-
item=
|
|
231
|
-
|
|
230
|
+
item=message.DeveloperMessage(
|
|
231
|
+
parts=message.text_parts_from_str(msg),
|
|
232
232
|
command_output=model.CommandOutput(command_name=self.name, is_error=False),
|
|
233
233
|
),
|
|
234
234
|
)
|
|
235
235
|
]
|
|
236
236
|
)
|
|
237
237
|
|
|
238
|
-
def _create_error_result(self, agent: "Agent",
|
|
238
|
+
def _create_error_result(self, agent: "Agent", msg: str) -> CommandResult:
|
|
239
239
|
"""Create error result"""
|
|
240
240
|
return CommandResult(
|
|
241
241
|
events=[
|
|
242
242
|
events.DeveloperMessageEvent(
|
|
243
243
|
session_id=agent.session.id,
|
|
244
|
-
item=
|
|
245
|
-
|
|
244
|
+
item=message.DeveloperMessage(
|
|
245
|
+
parts=message.text_parts_from_str(msg),
|
|
246
246
|
command_output=model.CommandOutput(command_name=self.name, is_error=True),
|
|
247
247
|
),
|
|
248
248
|
)
|
|
@@ -4,7 +4,7 @@ from prompt_toolkit.styles import Style
|
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
6
|
from klaude_code.config.thinking import get_thinking_picker_data, parse_thinking_value
|
|
7
|
-
from klaude_code.protocol import commands, events, llm_param, model, op
|
|
7
|
+
from klaude_code.protocol import commands, events, llm_param, message, model, op
|
|
8
8
|
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
9
9
|
|
|
10
10
|
SELECT_STYLE = Style(
|
|
@@ -67,7 +67,7 @@ class ThinkingCommand(CommandABC):
|
|
|
67
67
|
def is_interactive(self) -> bool:
|
|
68
68
|
return True
|
|
69
69
|
|
|
70
|
-
async def run(self, agent: Agent, user_input:
|
|
70
|
+
async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
|
|
71
71
|
del user_input # unused
|
|
72
72
|
if agent.profile is None:
|
|
73
73
|
return CommandResult(events=[])
|
|
@@ -80,8 +80,8 @@ class ThinkingCommand(CommandABC):
|
|
|
80
80
|
events=[
|
|
81
81
|
events.DeveloperMessageEvent(
|
|
82
82
|
session_id=agent.session.id,
|
|
83
|
-
item=
|
|
84
|
-
|
|
83
|
+
item=message.DeveloperMessage(
|
|
84
|
+
parts=message.text_parts_from_str("(no change)"),
|
|
85
85
|
command_output=model.CommandOutput(command_name=self.name),
|
|
86
86
|
),
|
|
87
87
|
)
|