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.
Files changed (54) hide show
  1. klaude_code/cli/config_cmd.py +1 -1
  2. klaude_code/cli/debug.py +1 -1
  3. klaude_code/cli/main.py +3 -9
  4. klaude_code/cli/runtime.py +10 -13
  5. klaude_code/command/__init__.py +4 -1
  6. klaude_code/command/clear_cmd.py +2 -7
  7. klaude_code/command/command_abc.py +33 -5
  8. klaude_code/command/debug_cmd.py +79 -0
  9. klaude_code/command/diff_cmd.py +2 -6
  10. klaude_code/command/export_cmd.py +7 -7
  11. klaude_code/command/export_online_cmd.py +1 -5
  12. klaude_code/command/help_cmd.py +4 -9
  13. klaude_code/command/model_cmd.py +10 -6
  14. klaude_code/command/prompt_command.py +2 -6
  15. klaude_code/command/refresh_cmd.py +2 -7
  16. klaude_code/command/registry.py +2 -4
  17. klaude_code/command/release_notes_cmd.py +2 -6
  18. klaude_code/command/status_cmd.py +2 -7
  19. klaude_code/command/terminal_setup_cmd.py +2 -6
  20. klaude_code/command/thinking_cmd.py +13 -8
  21. klaude_code/config/select_model.py +81 -5
  22. klaude_code/const/__init__.py +1 -1
  23. klaude_code/core/executor.py +236 -109
  24. klaude_code/core/manager/__init__.py +2 -4
  25. klaude_code/core/prompts/prompt-claude-code.md +1 -1
  26. klaude_code/core/prompts/prompt-sub-agent-web.md +8 -5
  27. klaude_code/core/reminders.py +9 -35
  28. klaude_code/core/tool/file/read_tool.py +38 -10
  29. klaude_code/core/tool/shell/bash_tool.py +22 -2
  30. klaude_code/core/tool/tool_runner.py +26 -23
  31. klaude_code/core/tool/truncation.py +23 -9
  32. klaude_code/core/tool/web/web_fetch_tool.md +1 -1
  33. klaude_code/core/tool/web/web_fetch_tool.py +36 -1
  34. klaude_code/core/turn.py +28 -0
  35. klaude_code/protocol/commands.py +1 -0
  36. klaude_code/protocol/sub_agent/web.py +3 -2
  37. klaude_code/session/session.py +2 -2
  38. klaude_code/session/templates/export_session.html +24 -13
  39. klaude_code/trace/__init__.py +20 -2
  40. klaude_code/ui/modes/repl/completers.py +19 -2
  41. klaude_code/ui/modes/repl/event_handler.py +8 -6
  42. klaude_code/ui/renderers/metadata.py +2 -4
  43. klaude_code/ui/renderers/thinking.py +24 -8
  44. klaude_code/ui/renderers/tools.py +79 -10
  45. klaude_code/ui/rich/code_panel.py +112 -0
  46. klaude_code/ui/rich/markdown.py +3 -4
  47. klaude_code/ui/rich/status.py +0 -2
  48. klaude_code/ui/rich/theme.py +10 -1
  49. {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/METADATA +16 -6
  50. {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/RECORD +53 -52
  51. klaude_code/core/manager/agent_manager.py +0 -132
  52. /klaude_code/{config → cli}/list_model.py +0 -0
  53. {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/WHEEL +0 -0
  54. {klaude_code-1.2.17.dist-info → klaude_code-1.2.18.dist-info}/entry_points.txt +0 -0
@@ -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.config.list_model import display_models_and_providers
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", "nvim", "vim", "nano"]:
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
- # Prefer the explicitly provided model as default; otherwise main model
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
@@ -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 Agent, DefaultModelProfileProvider, VanillaModelProfileProvider
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
- active_session_ids = executor.context.agent_manager.active_session_ids()
149
- return active_session_ids[0] if active_session_ids else session_id
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(agent=agent, update_message=update_message)
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
- active_ids = components.executor.context.agent_manager.active_session_ids()
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()
@@ -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",
@@ -1,11 +1,6 @@
1
- from typing import TYPE_CHECKING
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: "Agent") -> CommandResult:
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 TYPE_CHECKING
3
+ from typing import Protocol
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
- from klaude_code.protocol import commands
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
- if TYPE_CHECKING:
11
- from klaude_code.core.agent import Agent
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: "Agent") -> CommandResult:
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
+ )
@@ -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: "Agent") -> CommandResult:
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 False
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("", agent)
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."""
@@ -1,11 +1,6 @@
1
- from typing import TYPE_CHECKING
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: "Agent") -> CommandResult:
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
- additional_instructions = " \\[additional instructions]" if cmd_obj.support_addition_params else ""
43
- lines.append(f" [b]/{cmd_name}[/b]{additional_instructions} — {cmd_obj.summary}")
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,
@@ -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
- async def run(self, raw: str, agent: "Agent") -> CommandResult:
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: "Agent") -> CommandResult:
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 typing import TYPE_CHECKING
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: "Agent") -> CommandResult:
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")
@@ -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: "Agent") -> CommandResult:
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: "Agent") -> CommandResult:
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 typing import TYPE_CHECKING
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: "Agent") -> CommandResult:
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: "Agent") -> CommandResult:
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 ["gpt5.1", "openai/gpt-5.1", "gpt-5.1-codex-2025-11-13"]
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: "Agent") -> CommandResult:
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