klaude-code 2.6.0__py3-none-any.whl → 2.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- klaude_code/app/runtime.py +1 -1
- klaude_code/auth/AGENTS.md +325 -0
- klaude_code/auth/__init__.py +17 -1
- klaude_code/auth/antigravity/__init__.py +20 -0
- klaude_code/auth/antigravity/exceptions.py +17 -0
- klaude_code/auth/antigravity/oauth.py +320 -0
- klaude_code/auth/antigravity/pkce.py +25 -0
- klaude_code/auth/antigravity/token_manager.py +45 -0
- klaude_code/auth/base.py +4 -0
- klaude_code/auth/claude/oauth.py +29 -9
- klaude_code/auth/codex/exceptions.py +4 -0
- klaude_code/auth/env.py +19 -15
- klaude_code/cli/auth_cmd.py +54 -4
- klaude_code/cli/cost_cmd.py +83 -160
- klaude_code/cli/list_model.py +50 -0
- klaude_code/cli/main.py +99 -9
- klaude_code/config/assets/builtin_config.yaml +108 -0
- klaude_code/config/builtin_config.py +5 -11
- klaude_code/config/config.py +24 -10
- klaude_code/const.py +11 -1
- klaude_code/core/agent.py +5 -1
- klaude_code/core/agent_profile.py +28 -32
- klaude_code/core/compaction/AGENTS.md +112 -0
- klaude_code/core/compaction/__init__.py +11 -0
- klaude_code/core/compaction/compaction.py +707 -0
- klaude_code/core/compaction/overflow.py +30 -0
- klaude_code/core/compaction/prompts.py +97 -0
- klaude_code/core/executor.py +103 -2
- klaude_code/core/manager/llm_clients.py +5 -0
- klaude_code/core/manager/llm_clients_builder.py +14 -2
- klaude_code/core/prompts/prompt-antigravity.md +80 -0
- klaude_code/core/prompts/prompt-codex-gpt-5-2.md +335 -0
- klaude_code/core/reminders.py +11 -7
- klaude_code/core/task.py +126 -0
- klaude_code/core/tool/todo/todo_write_tool.py +1 -1
- klaude_code/core/turn.py +3 -1
- klaude_code/llm/antigravity/__init__.py +3 -0
- klaude_code/llm/antigravity/client.py +558 -0
- klaude_code/llm/antigravity/input.py +261 -0
- klaude_code/llm/registry.py +1 -0
- klaude_code/protocol/commands.py +0 -1
- klaude_code/protocol/events.py +18 -0
- klaude_code/protocol/llm_param.py +1 -0
- klaude_code/protocol/message.py +23 -1
- klaude_code/protocol/op.py +15 -1
- klaude_code/protocol/op_handler.py +5 -0
- klaude_code/session/session.py +36 -0
- klaude_code/skill/assets/create-plan/SKILL.md +6 -6
- klaude_code/skill/loader.py +12 -13
- klaude_code/skill/manager.py +3 -3
- klaude_code/tui/command/__init__.py +4 -4
- klaude_code/tui/command/compact_cmd.py +32 -0
- klaude_code/tui/command/copy_cmd.py +1 -1
- klaude_code/tui/command/fork_session_cmd.py +114 -18
- klaude_code/tui/command/model_picker.py +5 -1
- klaude_code/tui/command/thinking_cmd.py +1 -1
- klaude_code/tui/commands.py +6 -0
- klaude_code/tui/components/command_output.py +1 -1
- klaude_code/tui/components/rich/markdown.py +117 -1
- klaude_code/tui/components/rich/theme.py +18 -2
- klaude_code/tui/components/tools.py +39 -25
- klaude_code/tui/components/user_input.py +39 -28
- klaude_code/tui/input/AGENTS.md +44 -0
- klaude_code/tui/input/__init__.py +5 -2
- klaude_code/tui/input/completers.py +10 -14
- klaude_code/tui/input/drag_drop.py +146 -0
- klaude_code/tui/input/images.py +227 -0
- klaude_code/tui/input/key_bindings.py +183 -19
- klaude_code/tui/input/paste.py +71 -0
- klaude_code/tui/input/prompt_toolkit.py +32 -9
- klaude_code/tui/machine.py +26 -1
- klaude_code/tui/renderer.py +67 -4
- klaude_code/tui/runner.py +19 -3
- klaude_code/tui/terminal/image.py +103 -10
- klaude_code/tui/terminal/selector.py +81 -7
- {klaude_code-2.6.0.dist-info → klaude_code-2.8.0.dist-info}/METADATA +10 -10
- {klaude_code-2.6.0.dist-info → klaude_code-2.8.0.dist-info}/RECORD +79 -61
- klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -117
- klaude_code/tui/command/terminal_setup_cmd.py +0 -248
- klaude_code/tui/input/clipboard.py +0 -152
- {klaude_code-2.6.0.dist-info → klaude_code-2.8.0.dist-info}/WHEEL +0 -0
- {klaude_code-2.6.0.dist-info → klaude_code-2.8.0.dist-info}/entry_points.txt +0 -0
klaude_code/tui/runner.py
CHANGED
|
@@ -16,8 +16,9 @@ from klaude_code.app.runtime import (
|
|
|
16
16
|
)
|
|
17
17
|
from klaude_code.config import load_config
|
|
18
18
|
from klaude_code.const import SIGINT_DOUBLE_PRESS_EXIT_TEXT
|
|
19
|
+
from klaude_code.core.compaction import should_compact_threshold
|
|
19
20
|
from klaude_code.core.executor import Executor
|
|
20
|
-
from klaude_code.log import log
|
|
21
|
+
from klaude_code.log import get_current_log_file, log
|
|
21
22
|
from klaude_code.protocol import events, llm_param, op
|
|
22
23
|
from klaude_code.protocol.message import UserInputPayload
|
|
23
24
|
from klaude_code.session.session import Session
|
|
@@ -80,6 +81,19 @@ async def submit_user_input_payload(
|
|
|
80
81
|
for evt in cmd_result.events:
|
|
81
82
|
await executor.context.emit_event(evt)
|
|
82
83
|
|
|
84
|
+
if run_ops and should_compact_threshold(
|
|
85
|
+
session=agent.session,
|
|
86
|
+
config=None,
|
|
87
|
+
llm_config=agent.profile.llm_client.get_llm_config(),
|
|
88
|
+
):
|
|
89
|
+
await executor.submit_and_wait(
|
|
90
|
+
op.CompactSessionOperation(
|
|
91
|
+
session_id=agent.session.id,
|
|
92
|
+
reason="threshold",
|
|
93
|
+
will_retry=False,
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
83
97
|
submitted_ids: list[str] = []
|
|
84
98
|
for operation_item in operations:
|
|
85
99
|
submitted_ids.append(await executor.submit(operation_item))
|
|
@@ -124,7 +138,9 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
124
138
|
|
|
125
139
|
def _status_provider() -> REPLStatusSnapshot:
|
|
126
140
|
update_message = get_update_message()
|
|
127
|
-
|
|
141
|
+
debug_log = get_current_log_file()
|
|
142
|
+
debug_log_path = str(debug_log) if debug_log else None
|
|
143
|
+
return build_repl_status_snapshot(update_message, debug_log_path=debug_log_path)
|
|
128
144
|
|
|
129
145
|
def _stop_rich_bottom_ui() -> None:
|
|
130
146
|
active_display = components.display
|
|
@@ -312,4 +328,4 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
312
328
|
active_session_id = components.executor.context.current_session_id()
|
|
313
329
|
if active_session_id and Session.exists(active_session_id):
|
|
314
330
|
log(f"Session ID: {active_session_id}")
|
|
315
|
-
log(f"Resume with: klaude --resume
|
|
331
|
+
log(f"Resume with: klaude --resume {active_session_id}")
|
|
@@ -1,34 +1,127 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import base64
|
|
4
|
+
import shutil
|
|
5
|
+
import struct
|
|
6
|
+
import subprocess
|
|
3
7
|
import sys
|
|
8
|
+
import tempfile
|
|
4
9
|
from pathlib import Path
|
|
5
10
|
from typing import IO
|
|
6
11
|
|
|
12
|
+
# Kitty graphics protocol chunk size (4096 is the recommended max)
|
|
13
|
+
_CHUNK_SIZE = 4096
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
# Max columns for non-wide images
|
|
16
|
+
_MAX_COLS = 120
|
|
17
|
+
|
|
18
|
+
# Image formats that need conversion to PNG
|
|
19
|
+
_NEEDS_CONVERSION = {".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".tiff", ".tif"}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _convert_to_png(path: Path) -> bytes | None:
|
|
23
|
+
"""Convert image to PNG using sips (macOS) or convert (ImageMagick)."""
|
|
24
|
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=True) as tmp:
|
|
25
|
+
tmp_path = tmp.name
|
|
26
|
+
# Try sips first (macOS built-in)
|
|
27
|
+
result = subprocess.run(
|
|
28
|
+
["sips", "-s", "format", "png", str(path), "--out", tmp_path],
|
|
29
|
+
capture_output=True,
|
|
30
|
+
)
|
|
31
|
+
if result.returncode == 0:
|
|
32
|
+
return Path(tmp_path).read_bytes()
|
|
33
|
+
# Fallback to ImageMagick convert
|
|
34
|
+
result = subprocess.run(
|
|
35
|
+
["convert", str(path), tmp_path],
|
|
36
|
+
capture_output=True,
|
|
37
|
+
)
|
|
38
|
+
if result.returncode == 0:
|
|
39
|
+
return Path(tmp_path).read_bytes()
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_png_dimensions(data: bytes) -> tuple[int, int] | None:
|
|
44
|
+
"""Extract width and height from PNG file header."""
|
|
45
|
+
# PNG: 8-byte signature + IHDR chunk (4 len + 4 type + 4 width + 4 height)
|
|
46
|
+
if len(data) < 24 or data[:8] != b"\x89PNG\r\n\x1a\n":
|
|
47
|
+
return None
|
|
48
|
+
width, height = struct.unpack(">II", data[16:24])
|
|
49
|
+
return width, height
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def print_kitty_image(file_path: str | Path, *, file: IO[str] | None = None) -> None:
|
|
9
53
|
"""Print an image to the terminal using Kitty graphics protocol.
|
|
10
54
|
|
|
11
55
|
This intentionally bypasses Rich rendering to avoid interleaving Live refreshes
|
|
12
|
-
with raw escape sequences.
|
|
13
|
-
|
|
56
|
+
with raw escape sequences. Image size adapts based on aspect ratio:
|
|
57
|
+
- Landscape images: fill terminal width
|
|
58
|
+
- Portrait images: limit height to avoid oversized display
|
|
14
59
|
|
|
60
|
+
Args:
|
|
61
|
+
file_path: Path to the image file (PNG recommended).
|
|
62
|
+
file: Output file stream. Defaults to stdout.
|
|
63
|
+
"""
|
|
15
64
|
path = Path(file_path) if isinstance(file_path, str) else file_path
|
|
16
65
|
if not path.exists():
|
|
17
66
|
print(f"Image not found: {path}", file=file or sys.stdout, flush=True)
|
|
18
67
|
return
|
|
19
68
|
|
|
20
69
|
try:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
70
|
+
# Convert non-PNG formats to PNG for Kitty graphics protocol compatibility
|
|
71
|
+
if path.suffix.lower() in _NEEDS_CONVERSION:
|
|
72
|
+
data = _convert_to_png(path)
|
|
73
|
+
if data is None:
|
|
74
|
+
print(f"Saved image: {path}", file=file or sys.stdout, flush=True)
|
|
75
|
+
return
|
|
76
|
+
else:
|
|
77
|
+
data = path.read_bytes()
|
|
27
78
|
|
|
79
|
+
encoded = base64.standard_b64encode(data).decode("ascii")
|
|
28
80
|
out = file or sys.stdout
|
|
81
|
+
|
|
82
|
+
term_size = shutil.get_terminal_size()
|
|
83
|
+
dimensions = _get_png_dimensions(data)
|
|
84
|
+
|
|
85
|
+
# Determine sizing strategy based on aspect ratio
|
|
86
|
+
if dimensions is not None:
|
|
87
|
+
img_width, img_height = dimensions
|
|
88
|
+
if img_width > 2 * img_height:
|
|
89
|
+
# Wide landscape (width > 2x height): fill terminal width
|
|
90
|
+
size_param = f"c={term_size.columns}"
|
|
91
|
+
else:
|
|
92
|
+
# Other images: limit width to 80% of terminal
|
|
93
|
+
size_param = f"c={min(_MAX_COLS, term_size.columns * 4 // 5)}"
|
|
94
|
+
else:
|
|
95
|
+
# Fallback: limit width to 80% of terminal
|
|
96
|
+
size_param = f"c={min(_MAX_COLS, term_size.columns * 4 // 5)}"
|
|
29
97
|
print("", file=out)
|
|
30
|
-
|
|
98
|
+
_write_kitty_graphics(out, encoded, size_param=size_param)
|
|
31
99
|
print("", file=out)
|
|
32
100
|
out.flush()
|
|
33
101
|
except Exception:
|
|
34
102
|
print(f"Saved image: {path}", file=file or sys.stdout, flush=True)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _write_kitty_graphics(out: IO[str], encoded_data: str, *, size_param: str) -> None:
|
|
106
|
+
"""Write Kitty graphics protocol escape sequences.
|
|
107
|
+
|
|
108
|
+
Protocol format: ESC _ G <control>;<payload> ESC \\
|
|
109
|
+
- a=T: direct transmission (data in payload)
|
|
110
|
+
- f=100: PNG format (auto-detected by Kitty)
|
|
111
|
+
- c=N: display width in columns
|
|
112
|
+
- r=N: display height in rows
|
|
113
|
+
- m=1: more data follows, m=0: last chunk
|
|
114
|
+
"""
|
|
115
|
+
total_len = len(encoded_data)
|
|
116
|
+
|
|
117
|
+
for i in range(0, total_len, _CHUNK_SIZE):
|
|
118
|
+
chunk = encoded_data[i : i + _CHUNK_SIZE]
|
|
119
|
+
is_last = i + _CHUNK_SIZE >= total_len
|
|
120
|
+
|
|
121
|
+
if i == 0:
|
|
122
|
+
# First chunk: include control parameters
|
|
123
|
+
ctrl = f"a=T,f=100,{size_param},m={0 if is_last else 1}"
|
|
124
|
+
out.write(f"\033_G{ctrl};{chunk}\033\\")
|
|
125
|
+
else:
|
|
126
|
+
# Subsequent chunks: only m parameter needed
|
|
127
|
+
out.write(f"\033_Gm={0 if is_last else 1};{chunk}\033\\")
|
|
@@ -81,13 +81,13 @@ def build_model_select_items(models: list[Any]) -> list[SelectItem[str]]:
|
|
|
81
81
|
|
|
82
82
|
items: list[SelectItem[str]] = []
|
|
83
83
|
model_idx = 0
|
|
84
|
-
separator_base_len =
|
|
84
|
+
separator_base_len = 80
|
|
85
85
|
for provider, provider_models in grouped.items():
|
|
86
86
|
provider_text = provider.lower()
|
|
87
87
|
count_text = f"({len(provider_models)})"
|
|
88
88
|
header_len = len(provider_text) + 1 + len(count_text)
|
|
89
89
|
separator_len = separator_base_len + max_header_len - header_len
|
|
90
|
-
separator = "
|
|
90
|
+
separator = "-" * separator_len
|
|
91
91
|
items.append(
|
|
92
92
|
SelectItem(
|
|
93
93
|
title=[
|
|
@@ -389,7 +389,7 @@ def _build_search_container(
|
|
|
389
389
|
frame: bool = True,
|
|
390
390
|
) -> tuple[Window, Container]:
|
|
391
391
|
"""Build the search input container with placeholder."""
|
|
392
|
-
placeholder_text = f"{search_placeholder} · ↑↓ to select · esc to quit"
|
|
392
|
+
placeholder_text = f"{search_placeholder} · ↑↓ to select · enter/tab to confirm · esc to quit"
|
|
393
393
|
|
|
394
394
|
search_prefix_window = Window(
|
|
395
395
|
FormattedTextControl([("class:search_prefix", "/ ")]),
|
|
@@ -522,6 +522,23 @@ def select_one[T](
|
|
|
522
522
|
return
|
|
523
523
|
event.app.exit(result=value)
|
|
524
524
|
|
|
525
|
+
@kb.add(Keys.Tab, eager=True)
|
|
526
|
+
def _(event: KeyPressEvent) -> None:
|
|
527
|
+
"""Accept the currently pointed item."""
|
|
528
|
+
indices, _ = _filter_items(items, get_filter_text())
|
|
529
|
+
if not indices:
|
|
530
|
+
event.app.exit(result=None)
|
|
531
|
+
return
|
|
532
|
+
|
|
533
|
+
nonlocal pointed_at
|
|
534
|
+
pointed_at = _coerce_pointed_at_to_selectable(items, indices, pointed_at)
|
|
535
|
+
idx = indices[pointed_at % len(indices)]
|
|
536
|
+
value = items[idx].value
|
|
537
|
+
if value is None:
|
|
538
|
+
event.app.exit(result=None)
|
|
539
|
+
return
|
|
540
|
+
event.app.exit(result=value)
|
|
541
|
+
|
|
525
542
|
@kb.add(Keys.Escape, eager=True)
|
|
526
543
|
def _(event: KeyPressEvent) -> None:
|
|
527
544
|
nonlocal pointed_at
|
|
@@ -557,7 +574,10 @@ def select_one[T](
|
|
|
557
574
|
)
|
|
558
575
|
list_window = Window(
|
|
559
576
|
FormattedTextControl(get_choices_tokens),
|
|
560
|
-
|
|
577
|
+
# Keep 1 line of context above the cursor so non-selectable header rows
|
|
578
|
+
# (e.g. provider group labels) remain visible when wrapping back to the
|
|
579
|
+
# first selectable item in a scrolled list.
|
|
580
|
+
scroll_offsets=ScrollOffsets(top=1, bottom=2),
|
|
561
581
|
allow_scroll_beyond_bottom=True,
|
|
562
582
|
dont_extend_height=Always(),
|
|
563
583
|
always_hide_cursor=Always(),
|
|
@@ -702,6 +722,28 @@ class SelectOverlay[T]:
|
|
|
702
722
|
if hasattr(result, "__await__"):
|
|
703
723
|
event.app.create_background_task(cast(Coroutine[Any, Any, None], result))
|
|
704
724
|
|
|
725
|
+
@kb.add(Keys.Tab, filter=is_open_filter, eager=True)
|
|
726
|
+
def _(event: KeyPressEvent) -> None:
|
|
727
|
+
indices, _ = self._get_visible_indices()
|
|
728
|
+
if not indices:
|
|
729
|
+
self.close()
|
|
730
|
+
return
|
|
731
|
+
|
|
732
|
+
self._pointed_at = _coerce_pointed_at_to_selectable(self._items, indices, self._pointed_at)
|
|
733
|
+
idx = indices[self._pointed_at % len(indices)]
|
|
734
|
+
value = self._items[idx].value
|
|
735
|
+
if value is None:
|
|
736
|
+
self.close()
|
|
737
|
+
return
|
|
738
|
+
self.close()
|
|
739
|
+
|
|
740
|
+
if self._on_select is None:
|
|
741
|
+
return
|
|
742
|
+
|
|
743
|
+
result = self._on_select(value)
|
|
744
|
+
if hasattr(result, "__await__"):
|
|
745
|
+
event.app.create_background_task(cast(Coroutine[Any, Any, None], result))
|
|
746
|
+
|
|
705
747
|
@kb.add(Keys.Escape, filter=is_open_filter, eager=True)
|
|
706
748
|
def _(event: KeyPressEvent) -> None:
|
|
707
749
|
if self._use_search_filter and self._search_buffer is not None and self._search_buffer.text:
|
|
@@ -757,11 +799,43 @@ class SelectOverlay[T]:
|
|
|
757
799
|
dont_extend_height=Always(),
|
|
758
800
|
always_hide_cursor=Always(),
|
|
759
801
|
)
|
|
802
|
+
|
|
803
|
+
def get_list_height() -> int:
|
|
804
|
+
# Dynamic height: min of configured height and available terminal space
|
|
805
|
+
# Overhead: header(1) + spacer(1) + search(1) + frame borders(2) + prompt area(3)
|
|
806
|
+
overhead = 8
|
|
807
|
+
try:
|
|
808
|
+
terminal_height = get_app().output.get_size().rows
|
|
809
|
+
available = max(3, terminal_height - overhead)
|
|
810
|
+
cap = min(self._list_height, available)
|
|
811
|
+
except Exception:
|
|
812
|
+
cap = self._list_height
|
|
813
|
+
|
|
814
|
+
# Shrink list height when content is shorter than the configured cap.
|
|
815
|
+
# This is especially helpful for small pickers (e.g. thinking level)
|
|
816
|
+
# where a fixed list_height would otherwise render extra blank rows.
|
|
817
|
+
indices, _ = self._get_visible_indices()
|
|
818
|
+
if not indices:
|
|
819
|
+
return max(1, cap)
|
|
820
|
+
|
|
821
|
+
visible_lines = 0
|
|
822
|
+
for idx in indices:
|
|
823
|
+
item = self._items[idx]
|
|
824
|
+
newlines = sum(text.count("\n") for _style, text in item.title)
|
|
825
|
+
visible_lines += max(1, newlines)
|
|
826
|
+
if visible_lines >= cap:
|
|
827
|
+
break
|
|
828
|
+
|
|
829
|
+
return max(1, min(cap, visible_lines))
|
|
830
|
+
|
|
760
831
|
list_window = Window(
|
|
761
832
|
FormattedTextControl(get_choices_tokens),
|
|
762
|
-
height=
|
|
763
|
-
|
|
764
|
-
|
|
833
|
+
height=get_list_height,
|
|
834
|
+
# See select_one(): keep header rows visible when wrapping.
|
|
835
|
+
# For embedded overlays, avoid reserving extra blank lines near the
|
|
836
|
+
# bottom when the list height is tight (e.g. short pickers).
|
|
837
|
+
scroll_offsets=ScrollOffsets(top=1, bottom=0),
|
|
838
|
+
allow_scroll_beyond_bottom=False,
|
|
765
839
|
dont_extend_height=Always(),
|
|
766
840
|
always_hide_cursor=Always(),
|
|
767
841
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: klaude-code
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0
|
|
4
4
|
Summary: Minimal code agent CLI
|
|
5
5
|
Requires-Dist: anthropic>=0.66.0
|
|
6
6
|
Requires-Dist: chardet>=5.2.0
|
|
@@ -9,15 +9,13 @@ Requires-Dist: diff-match-patch>=20241021
|
|
|
9
9
|
Requires-Dist: google-genai>=1.56.0
|
|
10
10
|
Requires-Dist: markdown-it-py>=4.0.0
|
|
11
11
|
Requires-Dist: openai>=1.102.0
|
|
12
|
-
Requires-Dist: pillow>=9.1,<11.0
|
|
13
12
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
14
13
|
Requires-Dist: pydantic>=2.11.7
|
|
15
14
|
Requires-Dist: pyyaml>=6.0.2
|
|
16
15
|
Requires-Dist: rich>=14.1.0
|
|
17
|
-
Requires-Dist: term-image>=0.7.2
|
|
18
16
|
Requires-Dist: trafilatura>=2.0.0
|
|
19
17
|
Requires-Dist: typer>=0.17.3
|
|
20
|
-
Requires-Python: >=3.13
|
|
18
|
+
Requires-Python: >=3.13
|
|
21
19
|
Description-Content-Type: text/markdown
|
|
22
20
|
|
|
23
21
|
# Klaude Code
|
|
@@ -61,20 +59,22 @@ klaude upgrade
|
|
|
61
59
|
## Usage
|
|
62
60
|
|
|
63
61
|
```bash
|
|
64
|
-
klaude [--model <name>] [--
|
|
62
|
+
klaude [--model [<name>]] [--continue] [--resume [<id>]]
|
|
65
63
|
```
|
|
66
64
|
|
|
67
65
|
**Options:**
|
|
68
|
-
- `--model`/`-m`:
|
|
69
|
-
- `--
|
|
66
|
+
- `--model`/`-m`: Choose a model.
|
|
67
|
+
- `--model` (no value): opens the interactive selector.
|
|
68
|
+
- `--model <value>`: resolves `<value>` to a single model; if it can't, it opens the interactive selector filtered by `<value>`.
|
|
70
69
|
- `--continue`/`-c`: Resume the most recent session.
|
|
71
|
-
- `--resume`/`-r`:
|
|
72
|
-
- `--resume
|
|
70
|
+
- `--resume`/`-r`: Resume a session.
|
|
71
|
+
- `--resume` (no value): select a session to resume for this project.
|
|
72
|
+
- `--resume <id>`: resume a session by its ID directly.
|
|
73
73
|
- `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit, Write) and no system prompts.
|
|
74
74
|
|
|
75
75
|
**Model selection behavior:**
|
|
76
76
|
- Default: uses `main_model` from config.
|
|
77
|
-
- `--
|
|
77
|
+
- `--model` (no value): always prompts you to pick.
|
|
78
78
|
- `--model <value>`: tries to resolve `<value>` to a single model; if it can't, it prompts with a filtered list (and falls back to showing all models if there are no matches).
|
|
79
79
|
|
|
80
80
|
**Debug Options:**
|