klaude-code 1.2.20__py3-none-any.whl → 1.2.21__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
klaude_code/cli/main.py CHANGED
@@ -194,6 +194,11 @@ def main_callback(
194
194
  ),
195
195
  continue_: bool = typer.Option(False, "--continue", "-c", help="Continue from latest session"),
196
196
  resume: bool = typer.Option(False, "--resume", "-r", help="Select a session to resume for this project"),
197
+ resume_by_id: str | None = typer.Option(
198
+ None,
199
+ "--resume-by-id",
200
+ help="Resume a session by its ID (must exist)",
201
+ ),
197
202
  select_model: bool = typer.Option(
198
203
  False,
199
204
  "--select-model",
@@ -224,6 +229,7 @@ def main_callback(
224
229
  if ctx.invoked_subcommand is None:
225
230
  from klaude_code.cli.runtime import AppInitConfig, run_interactive
226
231
  from klaude_code.config.select_model import select_model_from_config
232
+ from klaude_code.trace import log
227
233
 
228
234
  update_terminal_title()
229
235
 
@@ -236,6 +242,16 @@ def main_callback(
236
242
  # Resolve session id before entering asyncio loop
237
243
  # session_id=None means create a new session
238
244
  session_id: str | None = None
245
+
246
+ resume_by_id_value = resume_by_id.strip() if resume_by_id is not None else None
247
+ if resume_by_id_value == "":
248
+ log(("Error: --resume-by-id cannot be empty", "red"))
249
+ raise typer.Exit(2)
250
+
251
+ if resume_by_id_value is not None and (resume or continue_):
252
+ log(("Error: --resume-by-id cannot be combined with --resume/--continue", "red"))
253
+ raise typer.Exit(2)
254
+
239
255
  if resume:
240
256
  session_id = resume_select_session()
241
257
  if session_id is None:
@@ -243,6 +259,13 @@ def main_callback(
243
259
  # If user didn't pick, allow fallback to --continue
244
260
  if session_id is None and continue_:
245
261
  session_id = Session.most_recent_session_id()
262
+
263
+ if resume_by_id_value is not None:
264
+ if not Session.exists(resume_by_id_value):
265
+ log((f"Error: session id '{resume_by_id_value}' not found for this project", "red"))
266
+ log(("Hint: run `klaude --resume` to select an existing session", "yellow"))
267
+ raise typer.Exit(2)
268
+ session_id = resume_by_id_value
246
269
  # If still no session_id, leave as None to create a new session
247
270
 
248
271
  if session_id is not None and chosen_model is None:
@@ -17,7 +17,7 @@ from klaude_code.core.executor import Executor
17
17
  from klaude_code.core.manager import build_llm_clients
18
18
  from klaude_code.protocol import events, op
19
19
  from klaude_code.protocol.model import UserInputPayload
20
- from klaude_code.session.session import close_default_store
20
+ from klaude_code.session.session import Session, close_default_store
21
21
  from klaude_code.trace import DebugType, log, set_debug_logging
22
22
  from klaude_code.ui.modes.repl import build_repl_status_snapshot
23
23
  from klaude_code.ui.modes.repl.input_prompt_toolkit import REPLStatusSnapshot
@@ -212,6 +212,9 @@ async def _handle_keyboard_interrupt(executor: Executor) -> None:
212
212
  """Handle Ctrl+C by logging and sending a global interrupt."""
213
213
 
214
214
  log("Bye!")
215
+ session_id = executor.context.current_session_id()
216
+ if session_id and Session.exists(session_id):
217
+ log(("Resume with:", "dim"), (f"klaude --resume-by-id {session_id}", "green"))
215
218
  # Executor might already be stopping
216
219
  with contextlib.suppress(Exception):
217
220
  await executor.submit(op.InterruptOperation(target_session_id=None))
@@ -296,6 +299,8 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
296
299
 
297
300
  restore_sigint = install_sigint_double_press_exit(_show_toast_once, _hide_progress)
298
301
 
302
+ exit_hint_printed = False
303
+
299
304
  try:
300
305
  await initialize_session(components.executor, components.event_queue, session_id=session_id)
301
306
  _backfill_session_model_config(
@@ -347,8 +352,15 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
347
352
 
348
353
  except KeyboardInterrupt:
349
354
  await _handle_keyboard_interrupt(components.executor)
355
+ exit_hint_printed = True
350
356
  finally:
351
357
  # Restore original SIGINT handler
352
358
  with contextlib.suppress(Exception):
353
359
  restore_sigint()
354
360
  await cleanup_app_components(components)
361
+
362
+ if not exit_hint_printed:
363
+ active_session_id = components.executor.context.current_session_id()
364
+ if active_session_id and Session.exists(active_session_id):
365
+ log(f"Session ID: {active_session_id}")
366
+ log(f"Resume with: klaude --resume-by-id {active_session_id}")
@@ -10,6 +10,7 @@ RESPONSES_LEVELS = ["low", "medium", "high"]
10
10
  RESPONSES_GPT51_LEVELS = ["none", "low", "medium", "high"]
11
11
  RESPONSES_GPT52_LEVELS = ["none", "low", "medium", "high", "xhigh"]
12
12
  RESPONSES_CODEX_MAX_LEVELS = ["medium", "high", "xhigh"]
13
+ RESPONSES_GEMINI_FLASH_LEVELS = ["minimal", "low", "medium", "high"]
13
14
 
14
15
  ANTHROPIC_LEVELS: list[tuple[str, int | None]] = [
15
16
  ("off", 0),
@@ -48,6 +49,13 @@ def _is_codex_max_model(model_name: str | None) -> bool:
48
49
  return "codex-max" in model_name.lower()
49
50
 
50
51
 
52
+ def _is_gemini_flash_model(model_name: str | None) -> bool:
53
+ """Check if the model is Gemini 3 Flash."""
54
+ if not model_name:
55
+ return False
56
+ return "gemini-3-flash" in model_name.lower()
57
+
58
+
51
59
  def _get_levels_for_responses(model_name: str | None) -> list[str]:
52
60
  """Get thinking levels for responses protocol."""
53
61
  if _is_codex_max_model(model_name):
@@ -56,6 +64,8 @@ def _get_levels_for_responses(model_name: str | None) -> list[str]:
56
64
  return RESPONSES_GPT52_LEVELS
57
65
  if _is_gpt51_model(model_name):
58
66
  return RESPONSES_GPT51_LEVELS
67
+ if _is_gemini_flash_model(model_name):
68
+ return RESPONSES_GEMINI_FLASH_LEVELS
59
69
  return RESPONSES_LEVELS
60
70
 
61
71
 
@@ -5,6 +5,7 @@ import re
5
5
  import signal
6
6
  import subprocess
7
7
  from pathlib import Path
8
+ from typing import Any
8
9
 
9
10
  from pydantic import BaseModel
10
11
 
@@ -122,7 +123,7 @@ class BashTool(ToolABC):
122
123
  return
123
124
 
124
125
  try:
125
- if os.name == "posix" and proc.pid is not None:
126
+ if os.name == "posix":
126
127
  os.killpg(proc.pid, signal.SIGTERM)
127
128
  else:
128
129
  proc.terminate()
@@ -138,7 +139,7 @@ class BashTool(ToolABC):
138
139
 
139
140
  # Escalate to hard kill if it didn't exit quickly.
140
141
  with contextlib.suppress(Exception):
141
- if os.name == "posix" and proc.pid is not None:
142
+ if os.name == "posix":
142
143
  os.killpg(proc.pid, signal.SIGKILL)
143
144
  else:
144
145
  proc.kill()
@@ -148,7 +149,7 @@ class BashTool(ToolABC):
148
149
  try:
149
150
  # Create a dedicated process group so we can terminate the whole tree.
150
151
  # (macOS/Linux support start_new_session; Windows does not.)
151
- kwargs: dict[str, object] = {
152
+ kwargs: dict[str, Any] = {
152
153
  "stdin": asyncio.subprocess.DEVNULL,
153
154
  "stdout": asyncio.subprocess.PIPE,
154
155
  "stderr": asyncio.subprocess.PIPE,
@@ -17,5 +17,31 @@ Diagrams are especially valuable for visualizing:
17
17
  - Sequence and timing of operations
18
18
  - Decision trees and conditional logic
19
19
 
20
+ # Syntax
21
+ - ALWAYS wrap node labels in double quotes, especially when they contain spaces, special characters, or non-ASCII text
22
+ - This applies to all node types: regular nodes, subgraph titles, and edge labels
23
+
24
+ Examples:
25
+ ```mermaid
26
+ graph LR
27
+ A["User Input"] --> B["Process Data"]
28
+ B --> C["Output Result"]
29
+ ```
30
+
31
+ ```mermaid
32
+ flowchart TD
33
+ subgraph auth["Authentication Module"]
34
+ login["Login Service"]
35
+ oauth["OAuth Provider"]
36
+ end
37
+ ```
38
+
39
+ ```mermaid
40
+ sequenceDiagram
41
+ participant client as "Web Client"
42
+ participant server as "API Server"
43
+ client ->> server: "Send Request"
44
+ ```
45
+
20
46
  # Styling
21
47
  - When defining custom classDefs, always define fill color, stroke color, and text color ("fill", "stroke", "color") explicitly
@@ -86,6 +86,13 @@ class Session(BaseModel):
86
86
  def paths(cls) -> ProjectPaths:
87
87
  return get_default_store().paths
88
88
 
89
+ @classmethod
90
+ def exists(cls, id: str) -> bool:
91
+ """Return True if a persisted session exists for the current project."""
92
+
93
+ paths = cls.paths()
94
+ return paths.meta_file(id).exists() or paths.events_file(id).exists()
95
+
89
96
  @classmethod
90
97
  def create(cls, id: str | None = None, *, work_dir: Path | None = None) -> Session:
91
98
  session = Session(id=id or uuid.uuid4().hex, work_dir=work_dir or Path.cwd())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.20
3
+ Version: 1.2.21
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -10,8 +10,8 @@ klaude_code/cli/auth_cmd.py,sha256=UWMHjn9xZp2o8OZc-x8y9MnkZgRWOkFXk05iKJYcySE,2
10
10
  klaude_code/cli/config_cmd.py,sha256=SBFmBnHvkf5IJtpsDDuHsHWQCmYd2i4PtIMBOKpxmOM,2894
11
11
  klaude_code/cli/debug.py,sha256=vohQVqy6fB59p4NYoiQb8BiLcl5YiGvugDXc2hYGFTc,2417
12
12
  klaude_code/cli/list_model.py,sha256=9YOxhWE0J59NaY-SrgPA9_jA1A8rlOGwWmzK0TRuos4,8011
13
- klaude_code/cli/main.py,sha256=K6VkJOmxVPc0jGNJPG3wumupUCx69DSpLmvKlANw98s,9485
14
- klaude_code/cli/runtime.py,sha256=PqYK48EbK4d5Hm8P7SjtMR5p2UQDfPpsyEiNT8q4Zvc,13650
13
+ klaude_code/cli/main.py,sha256=pyU2W2X3lg7Z-4adiOzA9_2l-5QSejYm68HrhAiu470,10469
14
+ klaude_code/cli/runtime.py,sha256=0qYbtTP41m0K8eA2de_VFuERTV1NHn265O1-BMcdrw0,14238
15
15
  klaude_code/cli/self_update.py,sha256=fekLNRm3ivZ-Xbc-79rcgDBXbq-Zb-BkSQOGMRLeTAs,7986
16
16
  klaude_code/cli/session_cmd.py,sha256=jAopkqq_DGgoDIcGxT-RSzn9R4yqBC8NCaNgK1GLqnQ,2634
17
17
  klaude_code/command/__init__.py,sha256=FBsAJAxQRR9zy-0GEfVsa52dk3CGmJh6-L4cjZ9sfag,3218
@@ -35,7 +35,7 @@ klaude_code/command/registry.py,sha256=avTjsoyLv11SsLsY_qb3OpsRjsSyxIlu7uwJI0Nq6
35
35
  klaude_code/command/release_notes_cmd.py,sha256=FIrBRfKTlXEp8mBh15buNjgOrl_GMX7FeeMWxYYBn1o,2674
36
36
  klaude_code/command/status_cmd.py,sha256=MnHtNdXTMqCJfB4_seHXDJEHYo99D-4ITZcGDCX2ilA,5359
37
37
  klaude_code/command/terminal_setup_cmd.py,sha256=SivM1gX_anGY_8DCQNFZ5VblFqt4sVgCMEWPRlo6K5w,10911
38
- klaude_code/command/thinking_cmd.py,sha256=KSLHXRS0gE5-Z9g1RgHprmDlpqXEp_lu1Z2MrdKcG-o,8493
38
+ klaude_code/command/thinking_cmd.py,sha256=XDyq0q8eb3Os4FyWjr-moiKjmzGIaNhOC9h89y1AZ84,8854
39
39
  klaude_code/config/__init__.py,sha256=Qrqvi8nizkj6N77h2vDj0r4rbgCiqxvz2HLBPFuWulA,120
40
40
  klaude_code/config/config.py,sha256=2jvM6a8zoC-TdRFaLIw3OW5paxxeXC6l-o05ds4RysA,7263
41
41
  klaude_code/config/select_model.py,sha256=KCdFjaoHXyO9QidNna_OGdDrvlEXtRUXKfG-F8kdNLk,5188
@@ -82,7 +82,7 @@ klaude_code/core/tool/memory/skill_tool.py,sha256=8SC4asNZSKfExuhzbyGz4f2cr78PgC
82
82
  klaude_code/core/tool/report_back_tool.py,sha256=KRZzQAIxniwXe58SDJcfK_DCf9TFFAx8XC75wPEjmpY,3246
83
83
  klaude_code/core/tool/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
84
  klaude_code/core/tool/shell/bash_tool.md,sha256=ILKpnRCBTkU2uSDEdZQjNYo1l6hsM4TO-3RD5zWC61c,3935
85
- klaude_code/core/tool/shell/bash_tool.py,sha256=PEcpBiWPclaLa87SM8iIZF3EK0QGWIV9XNkkixCnaXs,8409
85
+ klaude_code/core/tool/shell/bash_tool.py,sha256=xgEEcZ5mV-Qyw2zwAdS7ULaJEKCNjJ_uAT0-uBQRvSE,8379
86
86
  klaude_code/core/tool/shell/command_safety.py,sha256=bGsooLovuzq8WmLcZ2v24AVBDj3bZv2p4GSL0IlixvM,13192
87
87
  klaude_code/core/tool/sub_agent_tool.py,sha256=5n0HDxv4cUzuwBhYiAe3gIJ0s3QgV4GSV12CIIkD_g0,3190
88
88
  klaude_code/core/tool/todo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -97,7 +97,7 @@ klaude_code/core/tool/tool_registry.py,sha256=VFB0Z4BWtYKIWtpZVGhjSLcgfK244gow_U
97
97
  klaude_code/core/tool/tool_runner.py,sha256=A_RviRFr8kF6TjdGOzdgCIingeyJLBxNbZpcTnzT64E,10695
98
98
  klaude_code/core/tool/truncation.py,sha256=YPKzelOM45rHW_OkcfX5_Ojg_pPi8yDZu7lSnwl9b_k,7334
99
99
  klaude_code/core/tool/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
- klaude_code/core/tool/web/mermaid_tool.md,sha256=Ketpxpr7lz8238p5Q7ZzcyWchWd4dU68u708-dxaZds,978
100
+ klaude_code/core/tool/web/mermaid_tool.md,sha256=gyNkf1rSra-_4EyDFJOyoLBg8CoADVkEcWEuJFFz2VM,1564
101
101
  klaude_code/core/tool/web/mermaid_tool.py,sha256=Ok0A27oHLnV1c__74bheUuy3wpqDJ1zaXUSxuuqsNPI,2630
102
102
  klaude_code/core/tool/web/web_fetch_tool.md,sha256=jIrW-EAmfl50bBevcfioQ3Vrg8kWlHSut8ze_sRgRGw,486
103
103
  klaude_code/core/tool/web/web_fetch_tool.py,sha256=7WzOsAHdfijROOlk3JixtHUV1D2Cuwnf-AhoznrqATw,8551
@@ -143,7 +143,7 @@ klaude_code/session/__init__.py,sha256=oXcDA5w-gJCbzmlF8yuWy3ezIW9DgFBNUs-gJHUJ-
143
143
  klaude_code/session/codec.py,sha256=ummbqT7t6uHHXtaS9lOkyhi1h0YpMk7SNSms8DyGAHU,2015
144
144
  klaude_code/session/export.py,sha256=NmIG2SI1ec6HpXglb3zI2xeN8A80rMlPWP_zJGw4uFs,27147
145
145
  klaude_code/session/selector.py,sha256=gijwWQkSV20XYP3Fxr27mFXuqP4ChY2DQm_YuBOTQKw,2888
146
- klaude_code/session/session.py,sha256=P3vkPtlTitS6_01ZAPLG9hDmeyoBQx6RrZmrQZNGgYc,15772
146
+ klaude_code/session/session.py,sha256=LDrRlxv35_jJGwxv6Lv_WdBYNY2UZZAZ4vippq8pN_o,16016
147
147
  klaude_code/session/store.py,sha256=MLNTE-HiwmE3foM7n3AUtPvsf_hdyMHYA66ludTR8KU,6872
148
148
  klaude_code/session/templates/export_session.html,sha256=VM3uSEIEKU4ewBeaTS-iO3iBswbyiEGfC9KuikGpka4,119113
149
149
  klaude_code/trace/__init__.py,sha256=q8uOYhWr2_Mia1aEK_vkqx91YAfFM25ItIB6J8n3_pM,352
@@ -193,7 +193,7 @@ klaude_code/ui/terminal/notifier.py,sha256=wkRM66d98Oh6PujnN4bB7NiQxIYEHqQXverMK
193
193
  klaude_code/ui/terminal/progress_bar.py,sha256=MDnhPbqCnN4GDgLOlxxOEVZPDwVC_XL2NM5sl1MFNcQ,2133
194
194
  klaude_code/ui/utils/__init__.py,sha256=YEsCLjbCPaPza-UXTPUMTJTrc9BmNBUP5CbFWlshyOQ,15
195
195
  klaude_code/ui/utils/common.py,sha256=tqHqwgLtAyP805kwRFyoAL4EgMutcNb3Y-GAXJ4IeuM,2263
196
- klaude_code-1.2.20.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
197
- klaude_code-1.2.20.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
198
- klaude_code-1.2.20.dist-info/METADATA,sha256=k01_8Ew_jz0ALaq8oMtAcp-nspPH-YHHre2deCPXFMY,7636
199
- klaude_code-1.2.20.dist-info/RECORD,,
196
+ klaude_code-1.2.21.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
197
+ klaude_code-1.2.21.dist-info/entry_points.txt,sha256=7CWKjolvs6dZiYHpelhA_FRJ-sVDh43eu3iWuOhKc_w,53
198
+ klaude_code-1.2.21.dist-info/METADATA,sha256=JE_mGv-hmffkbbF50FVxM_aroRwT2JM3Ht01Po8wXAs,7636
199
+ klaude_code-1.2.21.dist-info/RECORD,,