klaude-code 1.2.17__py3-none-any.whl → 1.2.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- klaude_code/cli/config_cmd.py +1 -1
- klaude_code/cli/debug.py +1 -1
- klaude_code/cli/main.py +3 -9
- klaude_code/cli/runtime.py +10 -13
- klaude_code/command/__init__.py +4 -1
- klaude_code/command/clear_cmd.py +2 -7
- klaude_code/command/command_abc.py +33 -5
- klaude_code/command/debug_cmd.py +79 -0
- klaude_code/command/diff_cmd.py +2 -6
- klaude_code/command/export_cmd.py +7 -7
- klaude_code/command/export_online_cmd.py +1 -5
- klaude_code/command/help_cmd.py +4 -9
- klaude_code/command/model_cmd.py +10 -6
- klaude_code/command/prompt_command.py +2 -6
- klaude_code/command/refresh_cmd.py +2 -7
- klaude_code/command/registry.py +2 -4
- klaude_code/command/release_notes_cmd.py +2 -6
- klaude_code/command/status_cmd.py +2 -7
- klaude_code/command/terminal_setup_cmd.py +2 -6
- klaude_code/command/thinking_cmd.py +13 -8
- klaude_code/config/select_model.py +81 -5
- klaude_code/const/__init__.py +1 -1
- klaude_code/core/executor.py +236 -109
- klaude_code/core/manager/__init__.py +2 -4
- klaude_code/core/prompts/prompt-claude-code.md +1 -1
- klaude_code/core/prompts/prompt-sub-agent-web.md +8 -5
- klaude_code/core/reminders.py +9 -35
- klaude_code/core/tool/file/read_tool.py +38 -10
- klaude_code/core/tool/shell/bash_tool.py +22 -2
- klaude_code/core/tool/tool_runner.py +26 -23
- klaude_code/core/tool/truncation.py +23 -9
- klaude_code/core/tool/web/web_fetch_tool.md +1 -1
- klaude_code/core/tool/web/web_fetch_tool.py +36 -1
- klaude_code/core/turn.py +28 -0
- klaude_code/protocol/commands.py +1 -0
- klaude_code/protocol/sub_agent/web.py +3 -2
- klaude_code/session/session.py +2 -2
- klaude_code/session/templates/export_session.html +24 -13
- klaude_code/trace/__init__.py +20 -2
- klaude_code/ui/modes/repl/completers.py +19 -2
- klaude_code/ui/modes/repl/event_handler.py +8 -6
- klaude_code/ui/renderers/metadata.py +2 -4
- klaude_code/ui/renderers/thinking.py +24 -8
- klaude_code/ui/renderers/tools.py +79 -10
- klaude_code/ui/rich/code_panel.py +112 -0
- klaude_code/ui/rich/markdown.py +3 -4
- klaude_code/ui/rich/status.py +0 -2
- klaude_code/ui/rich/theme.py +10 -1
- {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/METADATA +16 -6
- {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/RECORD +53 -52
- klaude_code/core/manager/agent_manager.py +0 -132
- /klaude_code/{config → cli}/list_model.py +0 -0
- {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/WHEEL +0 -0
- {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/entry_points.txt +0 -0
klaude_code/cli/config_cmd.py
CHANGED
|
@@ -12,7 +12,7 @@ from klaude_code.trace import log
|
|
|
12
12
|
|
|
13
13
|
def list_models() -> None:
|
|
14
14
|
"""List all models and providers configuration"""
|
|
15
|
-
from klaude_code.
|
|
15
|
+
from klaude_code.cli.list_model import display_models_and_providers
|
|
16
16
|
from klaude_code.ui.terminal.color import is_light_terminal_background
|
|
17
17
|
|
|
18
18
|
config = load_config()
|
klaude_code/cli/debug.py
CHANGED
|
@@ -48,7 +48,7 @@ def open_log_file_in_editor(path: Path) -> None:
|
|
|
48
48
|
editor = os.environ.get("EDITOR")
|
|
49
49
|
|
|
50
50
|
if not editor:
|
|
51
|
-
for cmd in ["open", "xdg-open", "code", "
|
|
51
|
+
for cmd in ["open", "xdg-open", "code", "TextEdit", "notepad"]:
|
|
52
52
|
try:
|
|
53
53
|
subprocess.run(["which", cmd], check=True, capture_output=True)
|
|
54
54
|
editor = cmd
|
klaude_code/cli/main.py
CHANGED
|
@@ -11,7 +11,6 @@ from klaude_code.cli.auth_cmd import register_auth_commands
|
|
|
11
11
|
from klaude_code.cli.config_cmd import register_config_commands
|
|
12
12
|
from klaude_code.cli.debug import DEBUG_FILTER_HELP, open_log_file_in_editor, resolve_debug_settings
|
|
13
13
|
from klaude_code.cli.session_cmd import register_session_commands
|
|
14
|
-
from klaude_code.config import load_config
|
|
15
14
|
from klaude_code.session import Session, resume_select_session
|
|
16
15
|
from klaude_code.trace import DebugType, prepare_debug_log_file
|
|
17
16
|
|
|
@@ -157,13 +156,8 @@ def exec_command(
|
|
|
157
156
|
from klaude_code.config.select_model import select_model_from_config
|
|
158
157
|
|
|
159
158
|
chosen_model = model
|
|
160
|
-
if select_model:
|
|
161
|
-
|
|
162
|
-
config = load_config()
|
|
163
|
-
if config is None:
|
|
164
|
-
raise typer.Exit(1)
|
|
165
|
-
default_name = model or config.main_model
|
|
166
|
-
chosen_model = select_model_from_config(preferred=default_name)
|
|
159
|
+
if model or select_model:
|
|
160
|
+
chosen_model = select_model_from_config(preferred=model)
|
|
167
161
|
if chosen_model is None:
|
|
168
162
|
return
|
|
169
163
|
|
|
@@ -243,7 +237,7 @@ def main_callback(
|
|
|
243
237
|
setup_terminal_title()
|
|
244
238
|
|
|
245
239
|
chosen_model = model
|
|
246
|
-
if select_model:
|
|
240
|
+
if model or select_model:
|
|
247
241
|
chosen_model = select_model_from_config(preferred=model)
|
|
248
242
|
if chosen_model is None:
|
|
249
243
|
return
|
klaude_code/cli/runtime.py
CHANGED
|
@@ -10,7 +10,7 @@ from rich.text import Text
|
|
|
10
10
|
from klaude_code import ui
|
|
11
11
|
from klaude_code.command import has_interactive_command
|
|
12
12
|
from klaude_code.config import Config, load_config
|
|
13
|
-
from klaude_code.core.agent import
|
|
13
|
+
from klaude_code.core.agent import DefaultModelProfileProvider, VanillaModelProfileProvider
|
|
14
14
|
from klaude_code.core.executor import Executor
|
|
15
15
|
from klaude_code.core.manager import build_llm_clients
|
|
16
16
|
from klaude_code.protocol import events, op
|
|
@@ -98,8 +98,10 @@ async def initialize_app_components(init_config: AppInitConfig) -> AppComponents
|
|
|
98
98
|
executor_task = asyncio.create_task(executor.start())
|
|
99
99
|
|
|
100
100
|
theme: str | None = config.theme
|
|
101
|
-
if theme is None:
|
|
101
|
+
if theme is None and not init_config.is_exec_mode:
|
|
102
102
|
# Auto-detect theme from terminal background when config does not specify a theme.
|
|
103
|
+
# Skip detection in exec mode to avoid TTY race conditions with parent process's
|
|
104
|
+
# ESC monitor when running as a subprocess.
|
|
103
105
|
detected = is_light_terminal_background()
|
|
104
106
|
if detected is True:
|
|
105
107
|
theme = "light"
|
|
@@ -145,8 +147,8 @@ async def initialize_session(
|
|
|
145
147
|
await executor.submit_and_wait(op.InitAgentOperation(session_id=session_id))
|
|
146
148
|
await event_queue.join()
|
|
147
149
|
|
|
148
|
-
|
|
149
|
-
return
|
|
150
|
+
active_session_id = executor.context.current_session_id()
|
|
151
|
+
return active_session_id or session_id
|
|
150
152
|
|
|
151
153
|
|
|
152
154
|
async def cleanup_app_components(components: AppComponents) -> None:
|
|
@@ -214,16 +216,12 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
214
216
|
|
|
215
217
|
# Create status provider for bottom toolbar
|
|
216
218
|
def _status_provider() -> REPLStatusSnapshot:
|
|
217
|
-
agent: Agent | None = None
|
|
218
|
-
# Get the first active agent (there should only be one in interactive mode)
|
|
219
|
-
active_agents = components.executor.context.active_agents
|
|
220
|
-
if active_agents:
|
|
221
|
-
agent = next(iter(active_agents.values()), None)
|
|
222
|
-
|
|
223
219
|
# Check for updates (returns None if uv not available)
|
|
224
220
|
update_message = get_update_message()
|
|
225
221
|
|
|
226
|
-
return build_repl_status_snapshot(
|
|
222
|
+
return build_repl_status_snapshot(
|
|
223
|
+
agent=components.executor.context.current_agent, update_message=update_message
|
|
224
|
+
)
|
|
227
225
|
|
|
228
226
|
# Set up input provider for interactive mode
|
|
229
227
|
input_provider: ui.InputProviderABC = ui.PromptToolkitInput(status_provider=_status_provider)
|
|
@@ -268,8 +266,7 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
268
266
|
|
|
269
267
|
This is necessary because /clear command creates a new session with a different ID.
|
|
270
268
|
"""
|
|
271
|
-
|
|
272
|
-
return active_ids[0] if active_ids else None
|
|
269
|
+
return components.executor.context.current_session_id()
|
|
273
270
|
|
|
274
271
|
# Input
|
|
275
272
|
await input_provider.start()
|
klaude_code/command/__init__.py
CHANGED
|
@@ -28,6 +28,7 @@ def ensure_commands_loaded() -> None:
|
|
|
28
28
|
|
|
29
29
|
# Import and register commands in display order
|
|
30
30
|
from .clear_cmd import ClearCommand
|
|
31
|
+
from .debug_cmd import DebugCommand
|
|
31
32
|
from .diff_cmd import DiffCommand
|
|
32
33
|
from .export_cmd import ExportCommand
|
|
33
34
|
from .export_online_cmd import ExportOnlineCommand
|
|
@@ -46,12 +47,13 @@ def ensure_commands_loaded() -> None:
|
|
|
46
47
|
register(ThinkingCommand())
|
|
47
48
|
register(ModelCommand())
|
|
48
49
|
load_prompt_commands()
|
|
49
|
-
register(ClearCommand())
|
|
50
50
|
register(StatusCommand())
|
|
51
51
|
register(DiffCommand())
|
|
52
52
|
register(HelpCommand())
|
|
53
53
|
register(ReleaseNotesCommand())
|
|
54
54
|
register(TerminalSetupCommand())
|
|
55
|
+
register(DebugCommand())
|
|
56
|
+
register(ClearCommand())
|
|
55
57
|
|
|
56
58
|
# Load prompt-based commands (appended after built-in commands)
|
|
57
59
|
|
|
@@ -60,6 +62,7 @@ def ensure_commands_loaded() -> None:
|
|
|
60
62
|
def __getattr__(name: str) -> object:
|
|
61
63
|
_commands_map = {
|
|
62
64
|
"ClearCommand": "clear_cmd",
|
|
65
|
+
"DebugCommand": "debug_cmd",
|
|
63
66
|
"DiffCommand": "diff_cmd",
|
|
64
67
|
"ExportCommand": "export_cmd",
|
|
65
68
|
"ExportOnlineCommand": "export_online_cmd",
|
klaude_code/command/clear_cmd.py
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult, InputAction
|
|
1
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult, InputAction
|
|
4
2
|
from klaude_code.protocol import commands
|
|
5
3
|
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from klaude_code.core.agent import Agent
|
|
8
|
-
|
|
9
4
|
|
|
10
5
|
class ClearCommand(CommandABC):
|
|
11
6
|
"""Clear current session and start a new conversation"""
|
|
@@ -18,5 +13,5 @@ class ClearCommand(CommandABC):
|
|
|
18
13
|
def summary(self) -> str:
|
|
19
14
|
return "Clear conversation history and free up context"
|
|
20
15
|
|
|
21
|
-
async def run(self, raw: str, agent:
|
|
16
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
22
17
|
return CommandResult(actions=[InputAction.clear()])
|
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Protocol
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from klaude_code.
|
|
7
|
+
from klaude_code.llm import LLMClientABC
|
|
8
|
+
from klaude_code.protocol import commands, llm_param
|
|
8
9
|
from klaude_code.protocol import events as protocol_events
|
|
10
|
+
from klaude_code.session.session import Session
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
class AgentProfile(Protocol):
|
|
14
|
+
"""Protocol for the agent's active model profile."""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def llm_client(self) -> LLMClientABC: ...
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def system_prompt(self) -> str | None: ...
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def tools(self) -> list[llm_param.ToolSchema]: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Agent(Protocol):
|
|
27
|
+
"""Protocol for Agent objects passed to commands."""
|
|
28
|
+
|
|
29
|
+
session: Session
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def profile(self) -> AgentProfile | None: ...
|
|
33
|
+
|
|
34
|
+
def get_llm_client(self) -> LLMClientABC: ...
|
|
12
35
|
|
|
13
36
|
|
|
14
37
|
class InputActionType(str, Enum):
|
|
@@ -80,8 +103,13 @@ class CommandABC(ABC):
|
|
|
80
103
|
"""Whether this command support additional parameters."""
|
|
81
104
|
return False
|
|
82
105
|
|
|
106
|
+
@property
|
|
107
|
+
def placeholder(self) -> str:
|
|
108
|
+
"""Placeholder text for additional parameters in help display."""
|
|
109
|
+
return "additional instructions"
|
|
110
|
+
|
|
83
111
|
@abstractmethod
|
|
84
|
-
async def run(self, raw: str, agent:
|
|
112
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
85
113
|
"""
|
|
86
114
|
Execute the command.
|
|
87
115
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
2
|
+
from klaude_code.protocol import commands, events, model
|
|
3
|
+
from klaude_code.trace import DebugType, get_current_log_file, is_debug_enabled, set_debug_logging
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _format_status() -> str:
|
|
7
|
+
"""Format the current debug status for display."""
|
|
8
|
+
if not is_debug_enabled():
|
|
9
|
+
return "Debug: OFF"
|
|
10
|
+
|
|
11
|
+
log_file = get_current_log_file()
|
|
12
|
+
log_path_str = str(log_file) if log_file else "(console)"
|
|
13
|
+
return f"Debug: ON\nLog file: {log_path_str}"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _parse_debug_filters(raw: str) -> set[DebugType] | None:
|
|
17
|
+
filters: set[DebugType] = set()
|
|
18
|
+
for chunk in raw.split(","):
|
|
19
|
+
normalized = chunk.strip().lower().replace("-", "_")
|
|
20
|
+
if not normalized:
|
|
21
|
+
continue
|
|
22
|
+
try:
|
|
23
|
+
filters.add(DebugType(normalized))
|
|
24
|
+
except ValueError as exc:
|
|
25
|
+
raise ValueError(normalized) from exc
|
|
26
|
+
return filters or None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DebugCommand(CommandABC):
|
|
30
|
+
"""Toggle debug mode and configure debug filters."""
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> commands.CommandName:
|
|
34
|
+
return commands.CommandName.DEBUG
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def summary(self) -> str:
|
|
38
|
+
return "Toggle debug mode (optional: filter types)"
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def support_addition_params(self) -> bool:
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def placeholder(self) -> str:
|
|
46
|
+
return "filter types"
|
|
47
|
+
|
|
48
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
49
|
+
raw = raw.strip()
|
|
50
|
+
|
|
51
|
+
# /debug (no args) - enable debug
|
|
52
|
+
if not raw:
|
|
53
|
+
set_debug_logging(True, write_to_file=True)
|
|
54
|
+
return self._message_result(agent, _format_status())
|
|
55
|
+
|
|
56
|
+
# /debug <filters> - enable with filters
|
|
57
|
+
try:
|
|
58
|
+
filters = _parse_debug_filters(raw)
|
|
59
|
+
if filters:
|
|
60
|
+
set_debug_logging(True, write_to_file=True, filters=filters)
|
|
61
|
+
filter_names = ", ".join(sorted(dt.value for dt in filters))
|
|
62
|
+
return self._message_result(agent, f"Filters: {filter_names}\n{_format_status()}")
|
|
63
|
+
except ValueError:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
return self._message_result(agent, f"Invalid filter: {raw}\nValid: {', '.join(dt.value for dt in DebugType)}")
|
|
67
|
+
|
|
68
|
+
def _message_result(self, agent: "Agent", content: str) -> CommandResult:
|
|
69
|
+
return CommandResult(
|
|
70
|
+
events=[
|
|
71
|
+
events.DeveloperMessageEvent(
|
|
72
|
+
session_id=agent.session.id,
|
|
73
|
+
item=model.DeveloperMessageItem(
|
|
74
|
+
content=content,
|
|
75
|
+
command_output=model.CommandOutput(command_name=self.name),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
)
|
klaude_code/command/diff_cmd.py
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
3
|
|
|
5
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
4
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
5
|
from klaude_code.protocol import commands, events, model
|
|
7
6
|
|
|
8
|
-
if TYPE_CHECKING:
|
|
9
|
-
from klaude_code.core.agent import Agent
|
|
10
|
-
|
|
11
7
|
|
|
12
8
|
class DiffCommand(CommandABC):
|
|
13
9
|
"""Show git diff for the current repository."""
|
|
@@ -20,7 +16,7 @@ class DiffCommand(CommandABC):
|
|
|
20
16
|
def summary(self) -> str:
|
|
21
17
|
return "Show git diff"
|
|
22
18
|
|
|
23
|
-
async def run(self, raw: str, agent:
|
|
19
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
24
20
|
try:
|
|
25
21
|
# Check if current directory is in a git repository
|
|
26
22
|
git_check = subprocess.run(
|
|
@@ -2,15 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import subprocess
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
5
|
|
|
7
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
6
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
8
7
|
from klaude_code.protocol import commands, events, model
|
|
9
8
|
from klaude_code.session.export import build_export_html, get_default_export_path
|
|
10
9
|
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from klaude_code.core.agent import Agent
|
|
13
|
-
|
|
14
10
|
|
|
15
11
|
class ExportCommand(CommandABC):
|
|
16
12
|
"""Export the current session into a standalone HTML transcript."""
|
|
@@ -25,7 +21,11 @@ class ExportCommand(CommandABC):
|
|
|
25
21
|
|
|
26
22
|
@property
|
|
27
23
|
def support_addition_params(self) -> bool:
|
|
28
|
-
return
|
|
24
|
+
return True
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def placeholder(self) -> str:
|
|
28
|
+
return "output path"
|
|
29
29
|
|
|
30
30
|
@property
|
|
31
31
|
def is_interactive(self) -> bool:
|
|
@@ -33,7 +33,7 @@ class ExportCommand(CommandABC):
|
|
|
33
33
|
|
|
34
34
|
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
35
35
|
try:
|
|
36
|
-
output_path = self._resolve_output_path(
|
|
36
|
+
output_path = self._resolve_output_path(raw, agent)
|
|
37
37
|
html_doc = self._build_html(agent)
|
|
38
38
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
39
39
|
output_path.write_text(html_doc, encoding="utf-8")
|
|
@@ -5,15 +5,11 @@ import shutil
|
|
|
5
5
|
import subprocess
|
|
6
6
|
import tempfile
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
9
8
|
|
|
10
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
9
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
11
10
|
from klaude_code.protocol import commands, events, model
|
|
12
11
|
from klaude_code.session.export import build_export_html
|
|
13
12
|
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from klaude_code.core.agent import Agent
|
|
16
|
-
|
|
17
13
|
|
|
18
14
|
class ExportOnlineCommand(CommandABC):
|
|
19
15
|
"""Export and deploy the current session to surge.sh as a static webpage."""
|
klaude_code/command/help_cmd.py
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
1
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
4
2
|
from klaude_code.protocol import commands, events, model
|
|
5
3
|
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from klaude_code.core.agent import Agent
|
|
8
|
-
|
|
9
4
|
|
|
10
5
|
class HelpCommand(CommandABC):
|
|
11
6
|
"""Display help information for all available slash commands."""
|
|
@@ -18,7 +13,7 @@ class HelpCommand(CommandABC):
|
|
|
18
13
|
def summary(self) -> str:
|
|
19
14
|
return "Show help and available commands"
|
|
20
15
|
|
|
21
|
-
async def run(self, raw: str, agent:
|
|
16
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
22
17
|
lines: list[str] = [
|
|
23
18
|
"""
|
|
24
19
|
Usage:
|
|
@@ -39,8 +34,8 @@ Available slash commands:"""
|
|
|
39
34
|
|
|
40
35
|
if commands:
|
|
41
36
|
for cmd_name, cmd_obj in sorted(commands.items()):
|
|
42
|
-
|
|
43
|
-
lines.append(f" [b]/{cmd_name}[/b]{
|
|
37
|
+
placeholder = f" \\[{cmd_obj.placeholder}]" if cmd_obj.support_addition_params else ""
|
|
38
|
+
lines.append(f" [b]/{cmd_name}[/b]{placeholder} — {cmd_obj.summary}")
|
|
44
39
|
|
|
45
40
|
event = events.DeveloperMessageEvent(
|
|
46
41
|
session_id=agent.session.id,
|
klaude_code/command/model_cmd.py
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
4
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult, InputAction
|
|
3
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult, InputAction
|
|
5
4
|
from klaude_code.config.select_model import select_model_from_config
|
|
6
5
|
from klaude_code.protocol import commands, events, model
|
|
7
6
|
|
|
8
|
-
if TYPE_CHECKING:
|
|
9
|
-
from klaude_code.core.agent import Agent
|
|
10
|
-
|
|
11
7
|
|
|
12
8
|
class ModelCommand(CommandABC):
|
|
13
9
|
"""Display or change the model configuration."""
|
|
@@ -24,7 +20,15 @@ class ModelCommand(CommandABC):
|
|
|
24
20
|
def is_interactive(self) -> bool:
|
|
25
21
|
return True
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
@property
|
|
24
|
+
def support_addition_params(self) -> bool:
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def placeholder(self) -> str:
|
|
29
|
+
return "model name"
|
|
30
|
+
|
|
31
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
28
32
|
selected_model = await asyncio.to_thread(select_model_from_config, preferred=raw)
|
|
29
33
|
|
|
30
34
|
current_model = agent.profile.llm_client.model_name if agent.profile else None
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
from importlib.resources import files
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
4
3
|
import yaml
|
|
5
4
|
|
|
6
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult, InputAction
|
|
5
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult, InputAction
|
|
7
6
|
from klaude_code.protocol import commands
|
|
8
7
|
from klaude_code.trace import log_debug
|
|
9
8
|
|
|
10
|
-
if TYPE_CHECKING:
|
|
11
|
-
from klaude_code.core.agent import Agent
|
|
12
|
-
|
|
13
9
|
|
|
14
10
|
class PromptCommand(CommandABC):
|
|
15
11
|
"""Command that loads a prompt from a markdown file."""
|
|
@@ -59,7 +55,7 @@ class PromptCommand(CommandABC):
|
|
|
59
55
|
def support_addition_params(self) -> bool:
|
|
60
56
|
return True
|
|
61
57
|
|
|
62
|
-
async def run(self, raw: str, agent:
|
|
58
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
63
59
|
self._ensure_loaded()
|
|
64
60
|
template_content = self._content or ""
|
|
65
61
|
user_input = raw.strip() or "<none>"
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
1
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
4
2
|
from klaude_code.protocol import commands, events
|
|
5
3
|
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from klaude_code.core.agent import Agent
|
|
8
|
-
|
|
9
4
|
|
|
10
5
|
class RefreshTerminalCommand(CommandABC):
|
|
11
6
|
"""Refresh terminal display"""
|
|
@@ -22,7 +17,7 @@ class RefreshTerminalCommand(CommandABC):
|
|
|
22
17
|
def is_interactive(self) -> bool:
|
|
23
18
|
return True
|
|
24
19
|
|
|
25
|
-
async def run(self, raw: str, agent:
|
|
20
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
26
21
|
import os
|
|
27
22
|
|
|
28
23
|
os.system("cls" if os.name == "nt" else "clear")
|
klaude_code/command/registry.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
from importlib.resources import files
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
|
-
from klaude_code.command.command_abc import CommandResult, InputAction
|
|
4
|
+
from klaude_code.command.command_abc import Agent, CommandResult, InputAction
|
|
5
5
|
from klaude_code.command.prompt_command import PromptCommand
|
|
6
6
|
from klaude_code.protocol import commands, events, model
|
|
7
7
|
from klaude_code.trace import log_debug
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
|
-
from klaude_code.core.agent import Agent
|
|
11
|
-
|
|
12
10
|
from .command_abc import CommandABC
|
|
13
11
|
|
|
14
12
|
_COMMANDS: dict[commands.CommandName | str, "CommandABC"] = {}
|
|
@@ -50,7 +48,7 @@ def is_slash_command_name(name: str) -> bool:
|
|
|
50
48
|
return name in _COMMANDS
|
|
51
49
|
|
|
52
50
|
|
|
53
|
-
async def dispatch_command(raw: str, agent:
|
|
51
|
+
async def dispatch_command(raw: str, agent: Agent) -> CommandResult:
|
|
54
52
|
_ensure_commands_loaded()
|
|
55
53
|
# Detect command name
|
|
56
54
|
if not raw.startswith("/"):
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
4
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
3
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
5
4
|
from klaude_code.protocol import commands, events, model
|
|
6
5
|
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from klaude_code.core.agent import Agent
|
|
9
|
-
|
|
10
6
|
|
|
11
7
|
def _read_changelog() -> str:
|
|
12
8
|
"""Read CHANGELOG.md from project root."""
|
|
@@ -72,7 +68,7 @@ class ReleaseNotesCommand(CommandABC):
|
|
|
72
68
|
def summary(self) -> str:
|
|
73
69
|
return "Show the latest release notes"
|
|
74
70
|
|
|
75
|
-
async def run(self, raw: str, agent:
|
|
71
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
76
72
|
changelog = _read_changelog()
|
|
77
73
|
content = _extract_releases(changelog, count=10)
|
|
78
74
|
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
1
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
4
2
|
from klaude_code.protocol import commands, events, model
|
|
5
3
|
from klaude_code.session.session import Session
|
|
6
4
|
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from klaude_code.core.agent import Agent
|
|
9
|
-
|
|
10
5
|
|
|
11
6
|
class AggregatedUsage(model.BaseModel):
|
|
12
7
|
"""Aggregated usage statistics including per-model breakdown."""
|
|
@@ -137,7 +132,7 @@ class StatusCommand(CommandABC):
|
|
|
137
132
|
def summary(self) -> str:
|
|
138
133
|
return "Show session usage statistics"
|
|
139
134
|
|
|
140
|
-
async def run(self, raw: str, agent:
|
|
135
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
141
136
|
session = agent.session
|
|
142
137
|
aggregated = accumulate_session_usage(session)
|
|
143
138
|
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import subprocess
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
5
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
7
6
|
from klaude_code.protocol import commands, events, model
|
|
8
7
|
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from klaude_code.core.agent import Agent
|
|
11
|
-
|
|
12
8
|
|
|
13
9
|
class TerminalSetupCommand(CommandABC):
|
|
14
10
|
"""Setup shift+enter newline functionality in terminal"""
|
|
@@ -25,7 +21,7 @@ class TerminalSetupCommand(CommandABC):
|
|
|
25
21
|
def is_interactive(self) -> bool:
|
|
26
22
|
return False
|
|
27
23
|
|
|
28
|
-
async def run(self, raw: str, agent:
|
|
24
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
29
25
|
term_program = os.environ.get("TERM_PROGRAM", "").lower()
|
|
30
26
|
|
|
31
27
|
try:
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
4
3
|
import questionary
|
|
5
4
|
|
|
6
|
-
from klaude_code.command.command_abc import CommandABC, CommandResult
|
|
5
|
+
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
7
6
|
from klaude_code.protocol import commands, events, llm_param, model
|
|
8
7
|
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from klaude_code.core.agent import Agent
|
|
11
|
-
|
|
12
|
-
|
|
13
8
|
# Thinking level options for different protocols
|
|
14
9
|
RESPONSES_LEVELS = ["minimal", "low", "medium", "high"]
|
|
15
10
|
RESPONSES_GPT51_LEVELS = ["none", "minimal", "low", "medium", "high"]
|
|
11
|
+
RESPONSES_GPT52_LEVELS = ["none", "minimal", "low", "medium", "high", "xhigh"]
|
|
16
12
|
RESPONSES_CODEX_MAX_LEVELS = ["medium", "high", "xhigh"]
|
|
17
13
|
|
|
18
14
|
ANTHROPIC_LEVELS: list[tuple[str, int | None]] = [
|
|
@@ -35,7 +31,14 @@ def _is_gpt51_model(model_name: str | None) -> bool:
|
|
|
35
31
|
"""Check if the model is GPT-5.1."""
|
|
36
32
|
if not model_name:
|
|
37
33
|
return False
|
|
38
|
-
return model_name.lower() in ["
|
|
34
|
+
return model_name.lower() in ["gpt-5.1", "openai/gpt-5.1", "gpt-5.1-codex-2025-11-13"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _is_gpt52_model(model_name: str | None) -> bool:
|
|
38
|
+
"""Check if the model is GPT-5.2."""
|
|
39
|
+
if not model_name:
|
|
40
|
+
return False
|
|
41
|
+
return model_name.lower() in ["gpt-5.2", "openai/gpt-5.2"]
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def _is_codex_max_model(model_name: str | None) -> bool:
|
|
@@ -49,6 +52,8 @@ def _get_levels_for_responses(model_name: str | None) -> list[str]:
|
|
|
49
52
|
"""Get thinking levels for responses protocol."""
|
|
50
53
|
if _is_codex_max_model(model_name):
|
|
51
54
|
return RESPONSES_CODEX_MAX_LEVELS
|
|
55
|
+
if _is_gpt52_model(model_name):
|
|
56
|
+
return RESPONSES_GPT52_LEVELS
|
|
52
57
|
if _is_gpt51_model(model_name):
|
|
53
58
|
return RESPONSES_GPT51_LEVELS
|
|
54
59
|
return RESPONSES_LEVELS
|
|
@@ -164,7 +169,7 @@ class ThinkingCommand(CommandABC):
|
|
|
164
169
|
def is_interactive(self) -> bool:
|
|
165
170
|
return True
|
|
166
171
|
|
|
167
|
-
async def run(self, raw: str, agent:
|
|
172
|
+
async def run(self, raw: str, agent: Agent) -> CommandResult:
|
|
168
173
|
if not agent.profile:
|
|
169
174
|
return self._no_change_result(agent, "No profile configured")
|
|
170
175
|
|