klaude-code 2.1.1__py3-none-any.whl → 2.3.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.
Files changed (72) hide show
  1. klaude_code/app/__init__.py +1 -2
  2. klaude_code/app/runtime.py +13 -41
  3. klaude_code/cli/list_model.py +27 -10
  4. klaude_code/cli/main.py +42 -159
  5. klaude_code/config/assets/builtin_config.yaml +36 -14
  6. klaude_code/config/config.py +144 -7
  7. klaude_code/config/select_model.py +38 -13
  8. klaude_code/config/sub_agent_model_helper.py +217 -0
  9. klaude_code/const.py +2 -2
  10. klaude_code/core/agent_profile.py +71 -5
  11. klaude_code/core/executor.py +75 -0
  12. klaude_code/core/manager/llm_clients_builder.py +18 -12
  13. klaude_code/core/prompts/prompt-nano-banana.md +1 -0
  14. klaude_code/core/tool/shell/command_safety.py +4 -189
  15. klaude_code/core/tool/sub_agent_tool.py +2 -1
  16. klaude_code/core/turn.py +1 -1
  17. klaude_code/llm/anthropic/client.py +8 -5
  18. klaude_code/llm/anthropic/input.py +54 -29
  19. klaude_code/llm/google/client.py +2 -2
  20. klaude_code/llm/google/input.py +23 -2
  21. klaude_code/llm/openai_compatible/input.py +22 -13
  22. klaude_code/llm/openai_compatible/stream.py +1 -1
  23. klaude_code/llm/openrouter/input.py +37 -25
  24. klaude_code/llm/responses/client.py +1 -1
  25. klaude_code/llm/responses/input.py +96 -57
  26. klaude_code/protocol/commands.py +1 -2
  27. klaude_code/protocol/events/system.py +4 -0
  28. klaude_code/protocol/message.py +2 -2
  29. klaude_code/protocol/op.py +17 -0
  30. klaude_code/protocol/op_handler.py +5 -0
  31. klaude_code/protocol/sub_agent/AGENTS.md +28 -0
  32. klaude_code/protocol/sub_agent/__init__.py +10 -14
  33. klaude_code/protocol/sub_agent/image_gen.py +2 -1
  34. klaude_code/session/codec.py +2 -6
  35. klaude_code/session/session.py +9 -1
  36. klaude_code/skill/assets/create-plan/SKILL.md +3 -5
  37. klaude_code/tui/command/__init__.py +7 -10
  38. klaude_code/tui/command/clear_cmd.py +1 -1
  39. klaude_code/tui/command/command_abc.py +1 -2
  40. klaude_code/tui/command/copy_cmd.py +1 -2
  41. klaude_code/tui/command/fork_session_cmd.py +4 -4
  42. klaude_code/tui/command/model_cmd.py +6 -43
  43. klaude_code/tui/command/model_select.py +75 -15
  44. klaude_code/tui/command/refresh_cmd.py +1 -2
  45. klaude_code/tui/command/resume_cmd.py +3 -4
  46. klaude_code/tui/command/status_cmd.py +1 -1
  47. klaude_code/tui/command/sub_agent_model_cmd.py +190 -0
  48. klaude_code/tui/components/bash_syntax.py +1 -1
  49. klaude_code/tui/components/common.py +1 -1
  50. klaude_code/tui/components/developer.py +10 -15
  51. klaude_code/tui/components/metadata.py +2 -64
  52. klaude_code/tui/components/rich/cjk_wrap.py +3 -2
  53. klaude_code/tui/components/rich/status.py +49 -3
  54. klaude_code/tui/components/rich/theme.py +4 -2
  55. klaude_code/tui/components/sub_agent.py +25 -46
  56. klaude_code/tui/components/user_input.py +9 -21
  57. klaude_code/tui/components/welcome.py +99 -0
  58. klaude_code/tui/input/prompt_toolkit.py +14 -1
  59. klaude_code/tui/renderer.py +2 -3
  60. klaude_code/tui/runner.py +2 -2
  61. klaude_code/tui/terminal/selector.py +8 -18
  62. klaude_code/ui/__init__.py +0 -24
  63. klaude_code/ui/common.py +3 -2
  64. klaude_code/ui/core/display.py +2 -2
  65. {klaude_code-2.1.1.dist-info → klaude_code-2.3.0.dist-info}/METADATA +16 -81
  66. {klaude_code-2.1.1.dist-info → klaude_code-2.3.0.dist-info}/RECORD +68 -67
  67. klaude_code/tui/command/help_cmd.py +0 -51
  68. klaude_code/tui/command/prompt-commit.md +0 -82
  69. klaude_code/tui/command/release_notes_cmd.py +0 -85
  70. klaude_code/ui/exec_mode.py +0 -60
  71. {klaude_code-2.1.1.dist-info → klaude_code-2.3.0.dist-info}/WHEEL +0 -0
  72. {klaude_code-2.1.1.dist-info → klaude_code-2.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,99 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ from rich.console import Group, RenderableType
4
+ from rich.text import Text
5
+
6
+ from klaude_code.log import is_debug_enabled
7
+ from klaude_code.protocol import events
8
+ from klaude_code.tui.components.rich.quote import Quote
9
+ from klaude_code.tui.components.rich.theme import ThemeKey
10
+ from klaude_code.ui.common import format_model_params
11
+
12
+
13
+ def _get_version() -> str:
14
+ """Get the current version of klaude-code."""
15
+ try:
16
+ return version("klaude-code")
17
+ except PackageNotFoundError:
18
+ return "unknown"
19
+
20
+
21
+ def render_welcome(e: events.WelcomeEvent) -> RenderableType:
22
+ """Render the welcome panel with model info and settings.
23
+
24
+ Args:
25
+ e: The welcome event.
26
+ """
27
+ debug_mode = is_debug_enabled()
28
+
29
+ panel_content = Text()
30
+
31
+ if e.show_klaude_code_info:
32
+ # First line: Klaude Code version
33
+ klaude_code_style = ThemeKey.WELCOME_DEBUG_TITLE if debug_mode else ThemeKey.WELCOME_HIGHLIGHT_BOLD
34
+ panel_content.append_text(Text("Klaude Code", style=klaude_code_style))
35
+ panel_content.append_text(Text(f" v{_get_version()}", style=ThemeKey.WELCOME_INFO))
36
+ panel_content.append_text(Text("\n"))
37
+
38
+ # Model line: model @ provider · params...
39
+ panel_content.append_text(
40
+ Text.assemble(
41
+ (str(e.llm_config.model), ThemeKey.WELCOME_HIGHLIGHT),
42
+ (" @ ", ThemeKey.WELCOME_INFO),
43
+ (e.llm_config.provider_name, ThemeKey.WELCOME_INFO),
44
+ )
45
+ )
46
+
47
+ # Use format_model_params for consistent formatting
48
+ param_strings = format_model_params(e.llm_config)
49
+
50
+ # Check if we have sub-agent models to show
51
+ has_sub_agents = e.show_sub_agent_models and e.sub_agent_models
52
+
53
+ # Render config items with tree-style prefixes
54
+ for i, param_str in enumerate(param_strings):
55
+ is_last = i == len(param_strings) - 1 and not has_sub_agents
56
+ prefix = "└─ " if is_last else "├─ "
57
+ panel_content.append_text(
58
+ Text.assemble(
59
+ ("\n", ThemeKey.WELCOME_INFO),
60
+ (prefix, ThemeKey.LINES),
61
+ (param_str, ThemeKey.WELCOME_INFO),
62
+ )
63
+ )
64
+
65
+ # Render sub-agent models
66
+ if has_sub_agents:
67
+ # Add sub-agents header with tree prefix
68
+ panel_content.append_text(
69
+ Text.assemble(
70
+ ("\n", ThemeKey.WELCOME_INFO),
71
+ ("└─ ", ThemeKey.LINES),
72
+ ("sub-agents:", ThemeKey.WELCOME_INFO),
73
+ )
74
+ )
75
+ sub_agent_items = list(e.sub_agent_models.items())
76
+ max_type_len = max(len(t) for t in e.sub_agent_models)
77
+ for i, (sub_agent_type, sub_llm_config) in enumerate(sub_agent_items):
78
+ is_last = i == len(sub_agent_items) - 1
79
+ prefix = "└─ " if is_last else "├─ "
80
+ panel_content.append_text(
81
+ Text.assemble(
82
+ ("\n", ThemeKey.WELCOME_INFO),
83
+ (" ", ThemeKey.WELCOME_INFO), # Indentation for sub-items
84
+ (prefix, ThemeKey.LINES),
85
+ (sub_agent_type.lower().ljust(max_type_len), ThemeKey.WELCOME_INFO),
86
+ (": ", ThemeKey.LINES),
87
+ (str(sub_llm_config.model), ThemeKey.WELCOME_HIGHLIGHT),
88
+ (" @ ", ThemeKey.WELCOME_INFO),
89
+ (sub_llm_config.provider_name, ThemeKey.WELCOME_INFO),
90
+ )
91
+ )
92
+
93
+ border_style = ThemeKey.WELCOME_DEBUG_BORDER if debug_mode else ThemeKey.LINES
94
+
95
+ if e.show_klaude_code_info:
96
+ groups = ["", Quote(panel_content, style=border_style, prefix="▌ "), ""]
97
+ else:
98
+ groups = [Quote(panel_content, style=border_style, prefix="▌ "), ""]
99
+ return Group(*groups)
@@ -455,7 +455,7 @@ class PromptToolkitInput(InputProviderABC):
455
455
  config = load_config()
456
456
  models: list[ModelEntry] = sorted(
457
457
  config.iter_model_entries(only_available=True),
458
- key=lambda m: m.model_name.lower(),
458
+ key=lambda m: (m.model_name.lower(), m.provider.lower()),
459
459
  )
460
460
  if not models:
461
461
  return [], None
@@ -468,6 +468,15 @@ class PromptToolkitInput(InputProviderABC):
468
468
  initial = self._get_current_model_config_name()
469
469
  if initial is None:
470
470
  initial = config.main_model
471
+ if isinstance(initial, str) and initial and "@" not in initial:
472
+ try:
473
+ resolved = config.resolve_model_location_prefer_available(initial) or config.resolve_model_location(
474
+ initial
475
+ )
476
+ except ValueError:
477
+ resolved = None
478
+ if resolved is not None:
479
+ initial = f"{resolved[0]}@{resolved[1]}"
471
480
  return items, initial
472
481
 
473
482
  def _open_model_picker(self) -> None:
@@ -608,6 +617,10 @@ class PromptToolkitInput(InputProviderABC):
608
617
  (symbol_style, " ctrl-t "),
609
618
  (text_style, " "),
610
619
  (text_style, "think"),
620
+ (text_style, " "),
621
+ (symbol_style, " ctrl-v "),
622
+ (text_style, " "),
623
+ (text_style, "paste image"),
611
624
  ]
612
625
  )
613
626
 
@@ -61,6 +61,7 @@ from klaude_code.tui.components import sub_agent as c_sub_agent
61
61
  from klaude_code.tui.components import thinking as c_thinking
62
62
  from klaude_code.tui.components import tools as c_tools
63
63
  from klaude_code.tui.components import user_input as c_user_input
64
+ from klaude_code.tui.components import welcome as c_welcome
64
65
  from klaude_code.tui.components.common import truncate_head, truncate_middle
65
66
  from klaude_code.tui.components.rich import status as r_status
66
67
  from klaude_code.tui.components.rich.live import CropAboveLive, SingleLine
@@ -511,7 +512,7 @@ class TUICommandRenderer:
511
512
  self.print()
512
513
 
513
514
  def display_welcome(self, event: events.WelcomeEvent) -> None:
514
- self.print(c_metadata.render_welcome(event))
515
+ self.print(c_welcome.render_welcome(event))
515
516
 
516
517
  def display_user_message(self, event: events.UserMessageEvent) -> None:
517
518
  self.print(c_user_input.render_user_input(event.content))
@@ -567,10 +568,8 @@ class TUICommandRenderer:
567
568
  self.print(
568
569
  c_sub_agent.render_sub_agent_result(
569
570
  event.task_result,
570
- code_theme=self.themes.code_theme,
571
571
  has_structured_output=event.has_structured_output,
572
572
  description=description,
573
- style=ThemeKey.TOOL_RESULT,
574
573
  )
575
574
  )
576
575
 
klaude_code/tui/runner.py CHANGED
@@ -77,12 +77,12 @@ async def submit_user_input_payload(
77
77
  raise ValueError("Multiple RunAgentOperation results are not supported")
78
78
 
79
79
  for run_op in run_ops:
80
- run_op.persist_user_input = cmd_result.persist_user_input
80
+ run_op.persist_user_input = cmd_result.persist
81
81
  run_op.emit_user_message_event = False
82
82
 
83
83
  if cmd_result.events:
84
84
  for evt in cmd_result.events:
85
- if cmd_result.persist_events and isinstance(evt, events.DeveloperMessageEvent):
85
+ if cmd_result.persist and isinstance(evt, events.DeveloperMessageEvent):
86
86
  agent.session.append_history([evt.item])
87
87
  await executor.context.emit_event(evt)
88
88
 
@@ -19,6 +19,8 @@ from prompt_toolkit.layout.containers import Container, ScrollOffsets
19
19
  from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
20
20
  from prompt_toolkit.styles import Style, merge_styles
21
21
 
22
+ from klaude_code.ui.common import format_model_params
23
+
22
24
 
23
25
  @dataclass(frozen=True, slots=True)
24
26
  class SelectItem[T]:
@@ -49,26 +51,14 @@ def build_model_select_items(models: list[Any]) -> list[SelectItem[str]]:
49
51
  max_model_name_length = max(len(m.model_name) for m in models)
50
52
  num_width = len(str(len(models)))
51
53
 
52
- def _thinking_info(m: Any) -> str:
53
- thinking = m.model_params.thinking
54
- if not thinking:
55
- return ""
56
- if thinking.reasoning_effort:
57
- return f"reasoning {thinking.reasoning_effort}"
58
- if thinking.budget_tokens:
59
- return f"thinking budget {thinking.budget_tokens}"
60
- return "thinking (configured)"
61
-
62
54
  items: list[SelectItem[str]] = []
63
55
  for idx, m in enumerate(models, 1):
64
56
  model_id = m.model_params.model or "N/A"
65
- first_line_prefix = f"{m.model_name:<{max_model_name_length}} "
66
- thinking_info = _thinking_info(m)
57
+ # Display the base model name only; provider stays in the meta section.
58
+ display_name = m.model_name
59
+ first_line_prefix = f"{display_name:<{max_model_name_length}} → "
67
60
  meta_parts: list[str] = [m.provider]
68
- if thinking_info:
69
- meta_parts.append(thinking_info)
70
- if m.model_params.verbosity:
71
- meta_parts.append(f"verbosity {m.model_params.verbosity}")
61
+ meta_parts.extend(format_model_params(m.model_params))
72
62
  meta_str = " · ".join(meta_parts)
73
63
  title = [
74
64
  ("class:meta", f"{idx:>{num_width}}. "),
@@ -76,8 +66,8 @@ def build_model_select_items(models: list[Any]) -> list[SelectItem[str]]:
76
66
  ("class:msg bold", model_id),
77
67
  ("class:meta", f" {meta_str}\n"),
78
68
  ]
79
- search_text = f"{m.model_name} {model_id} {m.provider}"
80
- items.append(SelectItem(title=title, value=m.model_name, search_text=search_text))
69
+ search_text = f"{m.selector} {m.model_name} {model_id} {m.provider}"
70
+ items.append(SelectItem(title=title, value=m.selector, search_text=search_text))
81
71
 
82
72
  return items
83
73
 
@@ -10,33 +10,9 @@ Terminal (Rich/prompt-toolkit) UI lives in `klaude_code.tui`.
10
10
  from .core.display import DisplayABC
11
11
  from .core.input import InputProviderABC
12
12
  from .debug_mode import DebugEventDisplay
13
- from .exec_mode import ExecDisplay, StreamJsonDisplay
14
-
15
-
16
- def create_exec_display(debug: bool = False, stream_json: bool = False) -> DisplayABC:
17
- """
18
- Create a display for exec (non-interactive) mode.
19
-
20
- Args:
21
- debug: If True, wrap the display with DebugEventDisplay to log all events.
22
- stream_json: If True, stream all events as JSON lines instead of normal output.
23
-
24
- Returns:
25
- A DisplayABC implementation that only outputs task results.
26
- """
27
- if stream_json:
28
- return StreamJsonDisplay()
29
- exec_display = ExecDisplay()
30
- if debug:
31
- return DebugEventDisplay(exec_display)
32
- return exec_display
33
-
34
13
 
35
14
  __all__ = [
36
15
  "DebugEventDisplay",
37
16
  "DisplayABC",
38
- "ExecDisplay",
39
17
  "InputProviderABC",
40
- "StreamJsonDisplay",
41
- "create_exec_display",
42
18
  ]
klaude_code/ui/common.py CHANGED
@@ -101,6 +101,7 @@ def format_model_params(model_params: "LLMConfigModelParameter") -> list[str]:
101
101
  - "reasoning medium"
102
102
  - "thinking budget 10000"
103
103
  - "verbosity 2"
104
+ - "image generation"
104
105
  - "provider-routing: {…}"
105
106
  """
106
107
  parts: list[str] = []
@@ -119,8 +120,8 @@ def format_model_params(model_params: "LLMConfigModelParameter") -> list[str]:
119
120
  if model_params.provider_routing:
120
121
  parts.append(f"provider routing {_format_provider_routing(model_params.provider_routing)}")
121
122
 
122
- if model_params.modalities:
123
- parts.append(f"modalities {','.join(model_params.modalities)}")
123
+ if model_params.modalities and any(m.casefold() == "image" for m in model_params.modalities):
124
+ parts.append("image generation")
124
125
 
125
126
  if model_params.image_config:
126
127
  if model_params.image_config.aspect_ratio:
@@ -10,8 +10,8 @@ class DisplayABC(ABC):
10
10
  Abstract base class for UI display implementations.
11
11
 
12
12
  A Display is responsible for rendering events from the executor to the user.
13
- Implementations can range from simple text output (ExecDisplay) to rich
14
- interactive terminals (TUIDisplay) or debugging wrappers (DebugEventDisplay).
13
+ Implementations can range from minimal text output to rich interactive
14
+ terminals (TUIDisplay) or debugging wrappers (DebugEventDisplay).
15
15
 
16
16
  Lifecycle:
17
17
  1. start() is called once before any events are consumed.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 2.1.1
3
+ Version: 2.3.0
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -25,21 +25,19 @@ Description-Content-Type: text/markdown
25
25
  Minimal code agent CLI.
26
26
 
27
27
  ## Features
28
- - **Multi-provider**: Anthropic, OpenAI Responses API, OpenRouter
28
+ - **Multi-provider**: Anthropic Message API, OpenAI Responses API, OpenRouter, Claude Max OAuth and ChatGPT Codex OAuth etc.
29
29
  - **Keep reasoning item in context**: Interleaved thinking support
30
- - **Model-aware tools**: Claude Code tools for Sonnet, `apply_patch` for GPT-5/Codex
31
- - **Structured sub-agent output**: Define JSON schema, get schema-compliant responses via constrained decoding
30
+ - **Model-aware tools**: Claude Code tool set for Opus, `apply_patch` for GPT-5/Codex
31
+ - **Reminders**: Cooldown-based todo tracking, instruction reinforcement and external file change reminder
32
+ - **Sub-agents**: Task, Explore, Web, ImageGen
33
+ - **Structured sub-agent output**: Main agent defines JSON schema and get schema-compliant responses via constrained decoding
32
34
  - **Recursive `@file` mentions**: Circular dependency protection, relative path resolution
33
- - **Reminders**: Cooldown-based todo tracking and instruction reinforcement
34
35
  - **External file sync**: Monitoring for external edits (linter, manual)
35
36
  - **Interrupt handling**: Ctrl+C preserves partial responses and synthesizes tool cancellation results
36
37
  - **Output truncation**: Large outputs saved to file system with snapshot links
37
- - **Skills**: Built-in + user + project Agent Skills (with implicit invocation by Skill tool or explicit invocation by typing `$`)
38
+ - **Agent Skills**: Built-in + user + project Agent Skills (with implicit invocation by Skill tool or explicit invocation by typing `$`)
38
39
  - **Sessions**: Resumable with `--continue`
39
- - **Cost tracking**: Automatic API cost calculation and display (USD/CNY)
40
- - **Version update check**: Background PyPI version check with upgrade prompts
41
- - **Terminal title**: Shows current directory and model name
42
- - **Mermaid diagrams**: Interactive local HTML viewer with zoom, pan, and SVG export
40
+ - **Mermaid diagrams**: Terminal image preview and Interactive local HTML viewer with zoom, pan, and SVG export
43
41
  - **Extras**: Slash commands, sub-agents, image paste, terminal notifications, auto-theming
44
42
 
45
43
  ## Installation
@@ -59,32 +57,23 @@ Or use the built-in alias command:
59
57
  ```bash
60
58
  klaude update
61
59
  klaude upgrade
62
- ```
63
-
64
- To show version:
65
-
66
- ```bash
67
60
  klaude --version
68
- klaude -v
69
- klaude version
61
+
70
62
  ```
71
63
 
72
64
  ## Usage
73
65
 
74
- ### Interactive Mode
75
-
76
66
  ```bash
77
67
  klaude [--model <name>] [--select-model]
78
68
  ```
79
69
 
80
70
  **Options:**
81
- - `--version`/`-V`/`-v`: Show version and exit.
82
71
  - `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
83
72
  - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
84
73
  - `--continue`/`-c`: Resume the most recent session.
85
74
  - `--resume`/`-r`: Select a session to resume for this project.
86
75
  - `--resume-by-id <id>`: Resume a session by its ID directly.
87
- - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit) and no system prompts.
76
+ - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit, Write) and no system prompts.
88
77
 
89
78
  **Model selection behavior:**
90
79
  - Default: uses `main_model` from config.
@@ -255,48 +244,16 @@ provider_list:
255
244
  context_limit: 128000
256
245
  ```
257
246
 
258
- ##### Full Example
259
-
260
- ```yaml
261
- # User configuration - merged with built-in config
262
- main_model: opus
263
-
264
- sub_agent_models:
265
- explore: sonnet
266
- task: opus
267
- webagent: sonnet
268
-
269
- provider_list:
270
- # Add models to built-in openrouter
271
- - provider_name: openrouter
272
- model_list:
273
- - model_name: qwen-coder
274
- model_params:
275
- model: qwen/qwen-2.5-coder-32b-instruct
276
- context_limit: 131072
277
-
278
- # Add a completely new provider
279
- - provider_name: local-ollama
280
- protocol: openai
281
- base_url: http://localhost:11434/v1
282
- api_key: ollama
283
- model_list:
284
- - model_name: local-llama
285
- model_params:
286
- model: llama3.2
287
- context_limit: 8192
288
- ```
289
-
290
247
  ##### Supported Protocols
291
248
 
292
- - `anthropic` - Anthropic Claude API
249
+ - `anthropic` - Anthropic Messages API
293
250
  - `claude_oauth` - Claude OAuth (for Claude Pro/Max subscribers)
294
- - `openai` - OpenAI-compatible API
251
+ - `openai` - OpenAI Chat Completion API
295
252
  - `responses` - OpenAI Responses API (for o-series, GPT-5, Codex)
296
- - `openrouter` - OpenRouter API
297
- - `google` - Google Gemini API
298
- - `bedrock` - AWS Bedrock (uses AWS credentials instead of api_key)
299
253
  - `codex_oauth` - OpenAI Codex CLI (OAuth-based, for ChatGPT Pro subscribers)
254
+ - `openrouter` - OpenRouter API (handling `reasoning_details` for interleaved thinking)
255
+ - `google` - Google Gemini API
256
+ - `bedrock` - AWS Bedrock for Claude(uses AWS credentials instead of api_key)
300
257
 
301
258
  List configured providers and models:
302
259
 
@@ -338,6 +295,7 @@ Inside the interactive session (`klaude`), use these commands to streamline your
338
295
  - `/model` - Switch the active LLM during the session.
339
296
  - `/thinking` - Configure model thinking/reasoning level.
340
297
  - `/clear` - Clear the current conversation context.
298
+ - `/copy` - Copy last assistant message.
341
299
  - `/status` - Show session usage statistics (cost, tokens, model breakdown).
342
300
  - `/resume` - Select and resume a previous session.
343
301
  - `/fork-session` - Fork current session to a new session ID (supports interactive fork point selection).
@@ -364,29 +322,6 @@ Inside the interactive session (`klaude`), use these commands to streamline your
364
322
  | `Backspace` | Delete character or selected text |
365
323
  | `c` (with selection) | Copy selected text to clipboard |
366
324
 
367
- ### Non-Interactive Headless Mode (exec)
368
-
369
- Execute a single command without starting the interactive REPL:
370
-
371
- ```bash
372
- # Direct input
373
- klaude exec "what is 2+2?"
374
-
375
- # Pipe input
376
- echo "hello world" | klaude exec
377
-
378
- # With model selection
379
-
380
- # Exact model name (non-interactive)
381
- echo "generate quicksort in python" | klaude exec --model gpt-5.1
382
-
383
- # Partial/ambiguous name opens the interactive selector (filtered)
384
- echo "generate quicksort in python" | klaude exec --model gpt
385
-
386
- # Stream all events as JSON lines (for programmatic processing)
387
- klaude exec "what is 2+2?" --stream-json
388
- ```
389
-
390
325
  ### Sub-Agents
391
326
 
392
327
  The main agent can spawn specialized sub-agents for specific tasks: