klaude-code 1.2.11__py3-none-any.whl → 1.2.13__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 (88) hide show
  1. klaude_code/auth/codex/oauth.py +3 -3
  2. klaude_code/cli/main.py +5 -5
  3. klaude_code/cli/runtime.py +19 -27
  4. klaude_code/cli/session_cmd.py +6 -8
  5. klaude_code/command/__init__.py +31 -28
  6. klaude_code/command/clear_cmd.py +0 -2
  7. klaude_code/command/diff_cmd.py +0 -2
  8. klaude_code/command/export_cmd.py +3 -5
  9. klaude_code/command/help_cmd.py +0 -2
  10. klaude_code/command/model_cmd.py +0 -2
  11. klaude_code/command/refresh_cmd.py +0 -2
  12. klaude_code/command/registry.py +5 -9
  13. klaude_code/command/release_notes_cmd.py +0 -2
  14. klaude_code/command/status_cmd.py +2 -4
  15. klaude_code/command/terminal_setup_cmd.py +2 -4
  16. klaude_code/command/thinking_cmd.py +229 -0
  17. klaude_code/config/__init__.py +1 -1
  18. klaude_code/config/list_model.py +1 -1
  19. klaude_code/config/select_model.py +5 -15
  20. klaude_code/const/__init__.py +1 -1
  21. klaude_code/core/agent.py +14 -69
  22. klaude_code/core/executor.py +11 -10
  23. klaude_code/core/manager/agent_manager.py +4 -4
  24. klaude_code/core/manager/llm_clients.py +10 -49
  25. klaude_code/core/manager/llm_clients_builder.py +8 -21
  26. klaude_code/core/manager/sub_agent_manager.py +3 -3
  27. klaude_code/core/prompt.py +3 -3
  28. klaude_code/core/reminders.py +1 -1
  29. klaude_code/core/task.py +4 -5
  30. klaude_code/core/tool/__init__.py +16 -25
  31. klaude_code/core/tool/file/_utils.py +1 -1
  32. klaude_code/core/tool/file/apply_patch.py +17 -25
  33. klaude_code/core/tool/file/apply_patch_tool.py +4 -7
  34. klaude_code/core/tool/file/edit_tool.py +4 -11
  35. klaude_code/core/tool/file/multi_edit_tool.py +2 -3
  36. klaude_code/core/tool/file/read_tool.py +3 -4
  37. klaude_code/core/tool/file/write_tool.py +2 -3
  38. klaude_code/core/tool/memory/memory_tool.py +2 -8
  39. klaude_code/core/tool/memory/skill_loader.py +3 -2
  40. klaude_code/core/tool/shell/command_safety.py +0 -1
  41. klaude_code/core/tool/tool_context.py +1 -3
  42. klaude_code/core/tool/tool_registry.py +2 -1
  43. klaude_code/core/tool/tool_runner.py +1 -1
  44. klaude_code/core/tool/truncation.py +2 -5
  45. klaude_code/core/turn.py +9 -4
  46. klaude_code/llm/anthropic/client.py +62 -49
  47. klaude_code/llm/client.py +2 -20
  48. klaude_code/llm/codex/client.py +51 -32
  49. klaude_code/llm/input_common.py +2 -2
  50. klaude_code/llm/openai_compatible/client.py +60 -39
  51. klaude_code/llm/openai_compatible/stream_processor.py +2 -1
  52. klaude_code/llm/openrouter/client.py +79 -45
  53. klaude_code/llm/openrouter/reasoning_handler.py +19 -132
  54. klaude_code/llm/registry.py +6 -5
  55. klaude_code/llm/responses/client.py +65 -43
  56. klaude_code/llm/usage.py +1 -49
  57. klaude_code/protocol/commands.py +1 -0
  58. klaude_code/protocol/events.py +7 -0
  59. klaude_code/protocol/llm_param.py +1 -9
  60. klaude_code/protocol/model.py +10 -6
  61. klaude_code/protocol/sub_agent.py +2 -1
  62. klaude_code/session/export.py +1 -8
  63. klaude_code/session/selector.py +12 -7
  64. klaude_code/session/session.py +2 -4
  65. klaude_code/trace/__init__.py +1 -1
  66. klaude_code/trace/log.py +1 -1
  67. klaude_code/ui/__init__.py +4 -9
  68. klaude_code/ui/core/stage_manager.py +7 -4
  69. klaude_code/ui/modes/repl/__init__.py +1 -1
  70. klaude_code/ui/modes/repl/completers.py +6 -7
  71. klaude_code/ui/modes/repl/display.py +3 -4
  72. klaude_code/ui/modes/repl/event_handler.py +63 -5
  73. klaude_code/ui/modes/repl/key_bindings.py +2 -3
  74. klaude_code/ui/modes/repl/renderer.py +2 -1
  75. klaude_code/ui/renderers/diffs.py +1 -4
  76. klaude_code/ui/renderers/metadata.py +1 -12
  77. klaude_code/ui/rich/markdown.py +3 -3
  78. klaude_code/ui/rich/searchable_text.py +6 -6
  79. klaude_code/ui/rich/status.py +3 -4
  80. klaude_code/ui/rich/theme.py +1 -4
  81. klaude_code/ui/terminal/control.py +7 -16
  82. klaude_code/ui/terminal/notifier.py +2 -4
  83. klaude_code/ui/utils/common.py +1 -1
  84. klaude_code/ui/utils/debouncer.py +2 -2
  85. {klaude_code-1.2.11.dist-info → klaude_code-1.2.13.dist-info}/METADATA +1 -1
  86. {klaude_code-1.2.11.dist-info → klaude_code-1.2.13.dist-info}/RECORD +88 -87
  87. {klaude_code-1.2.11.dist-info → klaude_code-1.2.13.dist-info}/WHEEL +0 -0
  88. {klaude_code-1.2.11.dist-info → klaude_code-1.2.13.dist-info}/entry_points.txt +0 -0
@@ -78,13 +78,13 @@ class OAuthCallbackHandler(BaseHTTPRequestHandler):
78
78
  self.end_headers()
79
79
 
80
80
  if OAuthCallbackHandler.error:
81
- html = """
81
+ html = f"""
82
82
  <html><body style="font-family: sans-serif; text-align: center; padding: 50px;">
83
83
  <h1>Authentication Failed</h1>
84
- <p>Error: {}</p>
84
+ <p>Error: {OAuthCallbackHandler.error}</p>
85
85
  <p>Please close this window and try again.</p>
86
86
  </body></html>
87
- """.format(OAuthCallbackHandler.error)
87
+ """
88
88
  else:
89
89
  html = """
90
90
  <html><body style="font-family: sans-serif; text-align: center; padding: 50px;">
klaude_code/cli/main.py CHANGED
@@ -67,7 +67,7 @@ def login_command(
67
67
  if state and not state.is_expired():
68
68
  log(("You are already logged in to Codex.", "green"))
69
69
  log(f" Account ID: {state.account_id[:8]}...")
70
- expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.timezone.utc)
70
+ expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
71
71
  log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
72
72
  if not typer.confirm("Do you want to re-login?"):
73
73
  return
@@ -80,11 +80,11 @@ def login_command(
80
80
  state = oauth.login()
81
81
  log(("Login successful!", "green"))
82
82
  log(f" Account ID: {state.account_id[:8]}...")
83
- expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.timezone.utc)
83
+ expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
84
84
  log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
85
85
  except Exception as e:
86
86
  log((f"Login failed: {e}", "red"))
87
- raise typer.Exit(1)
87
+ raise typer.Exit(1) from None
88
88
 
89
89
 
90
90
  @app.command("logout")
@@ -173,11 +173,11 @@ def edit_config() -> None:
173
173
  subprocess.run([editor, str(config_path)], check=True)
174
174
  except subprocess.CalledProcessError as e:
175
175
  log((f"Error: Failed to open editor: {e}", "red"))
176
- raise typer.Exit(1)
176
+ raise typer.Exit(1) from None
177
177
  except FileNotFoundError:
178
178
  log((f"Error: Editor '{editor}' not found", "red"))
179
179
  log("Please install a text editor or set your $EDITOR environment variable")
180
- raise typer.Exit(1)
180
+ raise typer.Exit(1) from None
181
181
 
182
182
 
183
183
  @app.command("exec")
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import contextlib
2
3
  import sys
3
4
  from dataclasses import dataclass
4
5
  from typing import Any, Protocol
@@ -169,32 +170,26 @@ async def cleanup_app_components(components: AppComponents) -> None:
169
170
  await components.display_task
170
171
  finally:
171
172
  # Always attempt to clear Ghostty progress bar and restore cursor visibility
172
- try:
173
+ # Best-effort only; never fail cleanup due to OSC errors
174
+ with contextlib.suppress(Exception):
173
175
  emit_osc94(OSC94States.HIDDEN)
174
- except Exception:
175
- # Best-effort only; never fail cleanup due to OSC errors
176
- pass
177
176
 
178
- try:
179
- # Ensure the terminal cursor is visible even if Rich's Status spinner
180
- # did not get a chance to stop cleanly (e.g. on KeyboardInterrupt).
177
+ # Ensure the terminal cursor is visible even if Rich's Status spinner
178
+ # did not get a chance to stop cleanly (e.g. on KeyboardInterrupt).
179
+ # If this fails the shell can still recover via `reset`/`stty sane`.
180
+ with contextlib.suppress(Exception):
181
181
  stream = getattr(sys, "__stdout__", None) or sys.stdout
182
182
  stream.write("\033[?25h")
183
183
  stream.flush()
184
- except Exception:
185
- # If this fails the shell can still recover via `reset`/`stty sane`.
186
- pass
187
184
 
188
185
 
189
186
  async def _handle_keyboard_interrupt(executor: Executor) -> None:
190
187
  """Handle Ctrl+C by logging and sending a global interrupt."""
191
188
 
192
189
  log("Bye!")
193
- try:
190
+ # Executor might already be stopping
191
+ with contextlib.suppress(Exception):
194
192
  await executor.submit(op.InterruptOperation(target_session_id=None))
195
- except Exception:
196
- # Executor might already be stopping
197
- pass
198
193
 
199
194
 
200
195
  async def run_exec(init_config: AppInitConfig, input_content: str) -> None:
@@ -259,9 +254,12 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
259
254
  if isinstance(components.display, ui.REPLDisplay):
260
255
  printer = components.display.renderer
261
256
  # Check if it's a DebugEventDisplay wrapping a REPLDisplay
262
- elif isinstance(components.display, ui.DebugEventDisplay) and components.display.wrapped_display:
263
- if isinstance(components.display.wrapped_display, ui.REPLDisplay):
264
- printer = components.display.wrapped_display.renderer
257
+ elif (
258
+ isinstance(components.display, ui.DebugEventDisplay)
259
+ and components.display.wrapped_display
260
+ and isinstance(components.display.wrapped_display, ui.REPLDisplay)
261
+ ):
262
+ printer = components.display.wrapped_display.renderer
265
263
 
266
264
  if printer is not None:
267
265
  printer.print(Text(f" {MSG} ", style="bold yellow reverse"))
@@ -272,10 +270,8 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
272
270
  print(MSG, file=sys.stderr)
273
271
 
274
272
  def _hide_progress() -> None:
275
- try:
273
+ with contextlib.suppress(Exception):
276
274
  emit_osc94(OSC94States.HIDDEN)
277
- except Exception:
278
- pass
279
275
 
280
276
  restore_sigint = install_sigint_double_press_exit(_show_toast_once, _hide_progress)
281
277
 
@@ -315,17 +311,13 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
315
311
  finally:
316
312
  # Stop ESC monitor and wait for it to finish cleaning up TTY
317
313
  stop_event.set()
318
- try:
314
+ with contextlib.suppress(Exception):
319
315
  await esc_task
320
- except Exception:
321
- pass
322
316
 
323
317
  except KeyboardInterrupt:
324
318
  await _handle_keyboard_interrupt(components.executor)
325
319
  finally:
326
- try:
327
- # Restore original SIGINT handler
320
+ # Restore original SIGINT handler
321
+ with contextlib.suppress(Exception):
328
322
  restore_sigint()
329
- except Exception:
330
- pass
331
323
  await cleanup_app_components(components)
@@ -46,10 +46,9 @@ def session_clean(
46
46
  log(f"No sessions with fewer than {min_messages} messages found.")
47
47
  return
48
48
 
49
- if not yes:
50
- if not _session_confirm(to_delete, "Delete these sessions?"):
51
- log("Aborted.")
52
- return
49
+ if not yes and not _session_confirm(to_delete, "Delete these sessions?"):
50
+ log("Aborted.")
51
+ return
53
52
 
54
53
  deleted = Session.clean_small_sessions(min_messages)
55
54
  log(f"Deleted {deleted} session(s).")
@@ -65,10 +64,9 @@ def session_clean_all(
65
64
  log("No sessions found.")
66
65
  return
67
66
 
68
- if not yes:
69
- if not _session_confirm(sessions, "Delete ALL sessions? This cannot be undone."):
70
- log("Aborted.")
71
- return
67
+ if not yes and not _session_confirm(sessions, "Delete ALL sessions? This cannot be undone."):
68
+ log("Aborted.")
69
+ return
72
70
 
73
71
  deleted = Session.clean_all_sessions()
74
72
  log(f"Deleted {deleted} session(s).")
@@ -5,7 +5,7 @@ from .registry import (
5
5
  has_interactive_command,
6
6
  is_slash_command_name,
7
7
  load_prompt_commands,
8
- register_command,
8
+ register,
9
9
  )
10
10
 
11
11
  # Lazy load commands to avoid heavy imports at module load time
@@ -17,38 +17,41 @@ def ensure_commands_loaded() -> None:
17
17
 
18
18
  This function is called internally by registry functions like get_commands(),
19
19
  dispatch_command(), etc. It can also be called explicitly if early loading is desired.
20
+
21
+ Commands are registered in display order - the order here determines
22
+ the order shown in slash command completion.
20
23
  """
21
24
  global _commands_loaded
22
25
  if _commands_loaded:
23
26
  return
24
27
  _commands_loaded = True
25
28
 
26
- # Import command modules to trigger @register_command decorators
27
- from . import clear_cmd as _clear_cmd # noqa: F401
28
- from . import diff_cmd as _diff_cmd # noqa: F401
29
- from . import export_cmd as _export_cmd # noqa: F401
30
- from . import help_cmd as _help_cmd # noqa: F401
31
- from . import model_cmd as _model_cmd # noqa: F401
32
- from . import refresh_cmd as _refresh_cmd # noqa: F401
33
- from . import release_notes_cmd as _release_notes_cmd # noqa: F401
34
- from . import status_cmd as _status_cmd # noqa: F401
35
- from . import terminal_setup_cmd as _terminal_setup_cmd # noqa: F401
36
-
37
- # Suppress unused variable warnings
38
- _ = (
39
- _clear_cmd,
40
- _diff_cmd,
41
- _export_cmd,
42
- _help_cmd,
43
- _model_cmd,
44
- _refresh_cmd,
45
- _release_notes_cmd,
46
- _status_cmd,
47
- _terminal_setup_cmd,
48
- )
29
+ # Import and register commands in display order
30
+ from .clear_cmd import ClearCommand
31
+ from .diff_cmd import DiffCommand
32
+ from .export_cmd import ExportCommand
33
+ from .help_cmd import HelpCommand
34
+ from .model_cmd import ModelCommand
35
+ from .refresh_cmd import RefreshTerminalCommand
36
+ from .release_notes_cmd import ReleaseNotesCommand
37
+ from .status_cmd import StatusCommand
38
+ from .terminal_setup_cmd import TerminalSetupCommand
39
+ from .thinking_cmd import ThinkingCommand
49
40
 
50
- # Load prompt-based commands
41
+ # Register in desired display order
42
+ register(ExportCommand())
43
+ register(RefreshTerminalCommand())
44
+ register(ThinkingCommand())
45
+ register(ModelCommand())
51
46
  load_prompt_commands()
47
+ register(ClearCommand())
48
+ register(StatusCommand())
49
+ register(DiffCommand())
50
+ register(HelpCommand())
51
+ register(ReleaseNotesCommand())
52
+ register(TerminalSetupCommand())
53
+
54
+ # Load prompt-based commands (appended after built-in commands)
52
55
 
53
56
 
54
57
  # Lazy accessors for command classes
@@ -63,6 +66,7 @@ def __getattr__(name: str) -> object:
63
66
  "ReleaseNotesCommand": "release_notes_cmd",
64
67
  "StatusCommand": "status_cmd",
65
68
  "TerminalSetupCommand": "terminal_setup_cmd",
69
+ "ThinkingCommand": "thinking_cmd",
66
70
  }
67
71
  if name in _commands_map:
68
72
  import importlib
@@ -77,14 +81,13 @@ __all__ = [
77
81
  # "ClearCommand", "DiffCommand", "HelpCommand", "ModelCommand",
78
82
  # "ExportCommand", "RefreshTerminalCommand", "ReleaseNotesCommand",
79
83
  # "StatusCommand", "TerminalSetupCommand",
80
- "register_command",
81
84
  "CommandABC",
82
85
  "CommandResult",
83
86
  "InputAction",
84
87
  "InputActionType",
85
88
  "dispatch_command",
89
+ "ensure_commands_loaded",
86
90
  "get_commands",
87
- "is_slash_command_name",
88
91
  "has_interactive_command",
89
- "ensure_commands_loaded",
92
+ "is_slash_command_name",
90
93
  ]
@@ -1,14 +1,12 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
3
  from klaude_code.command.command_abc import CommandABC, CommandResult, InputAction
4
- from klaude_code.command.registry import register_command
5
4
  from klaude_code.protocol import commands
6
5
 
7
6
  if TYPE_CHECKING:
8
7
  from klaude_code.core.agent import Agent
9
8
 
10
9
 
11
- @register_command
12
10
  class ClearCommand(CommandABC):
13
11
  """Clear current session and start a new conversation"""
14
12
 
@@ -3,14 +3,12 @@ from pathlib import Path
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from klaude_code.command.command_abc import CommandABC, CommandResult
6
- from klaude_code.command.registry import register_command
7
6
  from klaude_code.protocol import commands, events, model
8
7
 
9
8
  if TYPE_CHECKING:
10
9
  from klaude_code.core.agent import Agent
11
10
 
12
11
 
13
- @register_command
14
12
  class DiffCommand(CommandABC):
15
13
  """Show git diff for the current repository."""
16
14
 
@@ -5,7 +5,6 @@ from pathlib import Path
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from klaude_code.command.command_abc import CommandABC, CommandResult
8
- from klaude_code.command.registry import register_command
9
8
  from klaude_code.protocol import commands, events, model
10
9
  from klaude_code.session.export import build_export_html, get_default_export_path
11
10
 
@@ -13,7 +12,6 @@ if TYPE_CHECKING:
13
12
  from klaude_code.core.agent import Agent
14
13
 
15
14
 
16
- @register_command
17
15
  class ExportCommand(CommandABC):
18
16
  """Export the current session into a standalone HTML transcript."""
19
17
 
@@ -33,7 +31,7 @@ class ExportCommand(CommandABC):
33
31
  def is_interactive(self) -> bool:
34
32
  return False
35
33
 
36
- async def run(self, raw: str, agent: "Agent") -> CommandResult:
34
+ async def run(self, raw: str, agent: Agent) -> CommandResult:
37
35
  try:
38
36
  output_path = self._resolve_output_path(raw, agent)
39
37
  html_doc = self._build_html(agent)
@@ -60,7 +58,7 @@ class ExportCommand(CommandABC):
60
58
  )
61
59
  return CommandResult(events=[event])
62
60
 
63
- def _resolve_output_path(self, raw: str, agent: "Agent") -> Path:
61
+ def _resolve_output_path(self, raw: str, agent: Agent) -> Path:
64
62
  trimmed = raw.strip()
65
63
  if trimmed:
66
64
  candidate = Path(trimmed).expanduser()
@@ -81,7 +79,7 @@ class ExportCommand(CommandABC):
81
79
  msg = f"Failed to open HTML with `open`: {exc}"
82
80
  raise RuntimeError(msg) from exc
83
81
 
84
- def _build_html(self, agent: "Agent") -> str:
82
+ def _build_html(self, agent: Agent) -> str:
85
83
  profile = agent.profile
86
84
  system_prompt = (profile.system_prompt if profile else "") or ""
87
85
  tools = profile.tools if profile else []
@@ -1,14 +1,12 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
3
  from klaude_code.command.command_abc import CommandABC, CommandResult
4
- from klaude_code.command.registry import register_command
5
4
  from klaude_code.protocol import commands, events, model
6
5
 
7
6
  if TYPE_CHECKING:
8
7
  from klaude_code.core.agent import Agent
9
8
 
10
9
 
11
- @register_command
12
10
  class HelpCommand(CommandABC):
13
11
  """Display help information for all available slash commands."""
14
12
 
@@ -2,7 +2,6 @@ import asyncio
2
2
  from typing import TYPE_CHECKING
3
3
 
4
4
  from klaude_code.command.command_abc import CommandABC, CommandResult, InputAction
5
- from klaude_code.command.registry import register_command
6
5
  from klaude_code.config import select_model_from_config
7
6
  from klaude_code.protocol import commands, events, model
8
7
 
@@ -10,7 +9,6 @@ if TYPE_CHECKING:
10
9
  from klaude_code.core.agent import Agent
11
10
 
12
11
 
13
- @register_command
14
12
  class ModelCommand(CommandABC):
15
13
  """Display or change the model configuration."""
16
14
 
@@ -1,14 +1,12 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
3
  from klaude_code.command.command_abc import CommandABC, CommandResult
4
- from klaude_code.command.registry import register_command
5
4
  from klaude_code.protocol import commands, events
6
5
 
7
6
  if TYPE_CHECKING:
8
7
  from klaude_code.core.agent import Agent
9
8
 
10
9
 
11
- @register_command
12
10
  class RefreshTerminalCommand(CommandABC):
13
11
  """Refresh terminal display"""
14
12
 
@@ -1,5 +1,5 @@
1
1
  from importlib.resources import files
2
- from typing import TYPE_CHECKING, TypeVar
2
+ from typing import TYPE_CHECKING
3
3
 
4
4
  from klaude_code.command.command_abc import CommandResult, InputAction
5
5
  from klaude_code.command.prompt_command import PromptCommand
@@ -13,14 +13,10 @@ if TYPE_CHECKING:
13
13
 
14
14
  _COMMANDS: dict[commands.CommandName | str, "CommandABC"] = {}
15
15
 
16
- T = TypeVar("T", bound="CommandABC")
17
16
 
18
-
19
- def register_command(cls: type[T]) -> type[T]:
20
- """Decorator to register a command class in the global registry."""
21
- instance = cls()
22
- _COMMANDS[instance.name] = instance
23
- return cls
17
+ def register(cmd: "CommandABC") -> None:
18
+ """Register a command instance. Order of registration determines display order."""
19
+ _COMMANDS[cmd.name] = cmd
24
20
 
25
21
 
26
22
  def load_prompt_commands():
@@ -98,7 +94,7 @@ async def dispatch_command(raw: str, agent: "Agent") -> CommandResult:
98
94
  events.DeveloperMessageEvent(
99
95
  session_id=agent.session.id,
100
96
  item=model.DeveloperMessageItem(
101
- content=f"Command {command_identifier} error: [{e.__class__.__name__}] {str(e)}",
97
+ content=f"Command {command_identifier} error: [{e.__class__.__name__}] {e!s}",
102
98
  command_output=command_output,
103
99
  ),
104
100
  )
@@ -2,7 +2,6 @@ from pathlib import Path
2
2
  from typing import TYPE_CHECKING
3
3
 
4
4
  from klaude_code.command.command_abc import CommandABC, CommandResult
5
- from klaude_code.command.registry import register_command
6
5
  from klaude_code.protocol import commands, events, model
7
6
 
8
7
  if TYPE_CHECKING:
@@ -62,7 +61,6 @@ def _extract_releases(changelog: str, count: int = 1) -> str:
62
61
  return "\n".join("\n".join(release) for release in releases).strip()
63
62
 
64
63
 
65
- @register_command
66
64
  class ReleaseNotesCommand(CommandABC):
67
65
  """Display the latest release notes from CHANGELOG.md."""
68
66
 
@@ -1,7 +1,6 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
3
  from klaude_code.command.command_abc import CommandABC, CommandResult
4
- from klaude_code.command.registry import register_command
5
4
  from klaude_code.protocol import commands, events, model
6
5
  from klaude_code.session.session import Session
7
6
 
@@ -60,8 +59,8 @@ def accumulate_session_usage(session: Session) -> AggregatedUsage:
60
59
  total.cache_read_cost = (total.cache_read_cost or 0.0) + usage.cache_read_cost
61
60
 
62
61
  # Track peak context window size (max across all tasks)
63
- if usage.context_token is not None:
64
- total.context_token = usage.context_token
62
+ if usage.context_size is not None:
63
+ total.context_size = usage.context_size
65
64
 
66
65
  # Keep the latest context_limit for computed context_usage_percent
67
66
  if usage.context_limit is not None:
@@ -127,7 +126,6 @@ def format_status_content(aggregated: AggregatedUsage) -> str:
127
126
  return "\n".join(lines)
128
127
 
129
128
 
130
- @register_command
131
129
  class StatusCommand(CommandABC):
132
130
  """Display session usage statistics."""
133
131
 
@@ -4,14 +4,12 @@ from pathlib import Path
4
4
  from typing import TYPE_CHECKING
5
5
 
6
6
  from klaude_code.command.command_abc import CommandABC, CommandResult
7
- from klaude_code.command.registry import register_command
8
7
  from klaude_code.protocol import commands, events, model
9
8
 
10
9
  if TYPE_CHECKING:
11
10
  from klaude_code.core.agent import Agent
12
11
 
13
12
 
14
- @register_command
15
13
  class TerminalSetupCommand(CommandABC):
16
14
  """Setup shift+enter newline functionality in terminal"""
17
15
 
@@ -45,7 +43,7 @@ class TerminalSetupCommand(CommandABC):
45
43
  return self._create_success_result(agent, message)
46
44
 
47
45
  except Exception as e:
48
- return self._create_error_result(agent, f"Error configuring terminal: {str(e)}")
46
+ return self._create_error_result(agent, f"Error configuring terminal: {e!s}")
49
47
 
50
48
  def _setup_ghostty(self) -> str:
51
49
  """Configure shift+enter newline for Ghostty terminal"""
@@ -115,7 +113,7 @@ class TerminalSetupCommand(CommandABC):
115
113
  )
116
114
 
117
115
  except Exception as e:
118
- raise Exception(f"Error configuring iTerm: {str(e)}")
116
+ raise Exception(f"Error configuring iTerm: {e!s}") from e
119
117
 
120
118
  def _setup_vscode_family(self) -> str:
121
119
  """Configure shift+enter newline for VS Code family terminals (VS Code, Windsurf, Cursor).