klaude-code 1.2.6__py3-none-any.whl → 1.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.
Files changed (205) hide show
  1. klaude_code/auth/__init__.py +24 -0
  2. klaude_code/auth/codex/__init__.py +20 -0
  3. klaude_code/auth/codex/exceptions.py +17 -0
  4. klaude_code/auth/codex/jwt_utils.py +45 -0
  5. klaude_code/auth/codex/oauth.py +229 -0
  6. klaude_code/auth/codex/token_manager.py +84 -0
  7. klaude_code/cli/auth_cmd.py +73 -0
  8. klaude_code/cli/config_cmd.py +91 -0
  9. klaude_code/cli/cost_cmd.py +338 -0
  10. klaude_code/cli/debug.py +78 -0
  11. klaude_code/cli/list_model.py +307 -0
  12. klaude_code/cli/main.py +233 -134
  13. klaude_code/cli/runtime.py +309 -117
  14. klaude_code/{version.py → cli/self_update.py} +114 -5
  15. klaude_code/cli/session_cmd.py +37 -21
  16. klaude_code/command/__init__.py +88 -27
  17. klaude_code/command/clear_cmd.py +8 -7
  18. klaude_code/command/command_abc.py +31 -31
  19. klaude_code/command/debug_cmd.py +79 -0
  20. klaude_code/command/export_cmd.py +19 -53
  21. klaude_code/command/export_online_cmd.py +154 -0
  22. klaude_code/command/fork_session_cmd.py +267 -0
  23. klaude_code/command/help_cmd.py +7 -8
  24. klaude_code/command/model_cmd.py +60 -10
  25. klaude_code/command/model_select.py +84 -0
  26. klaude_code/command/prompt-jj-describe.md +32 -0
  27. klaude_code/command/prompt_command.py +19 -11
  28. klaude_code/command/refresh_cmd.py +8 -10
  29. klaude_code/command/registry.py +139 -40
  30. klaude_code/command/release_notes_cmd.py +84 -0
  31. klaude_code/command/resume_cmd.py +111 -0
  32. klaude_code/command/status_cmd.py +104 -60
  33. klaude_code/command/terminal_setup_cmd.py +7 -9
  34. klaude_code/command/thinking_cmd.py +98 -0
  35. klaude_code/config/__init__.py +14 -6
  36. klaude_code/config/assets/__init__.py +1 -0
  37. klaude_code/config/assets/builtin_config.yaml +303 -0
  38. klaude_code/config/builtin_config.py +38 -0
  39. klaude_code/config/config.py +378 -109
  40. klaude_code/config/select_model.py +117 -53
  41. klaude_code/config/thinking.py +269 -0
  42. klaude_code/{const/__init__.py → const.py} +50 -19
  43. klaude_code/core/agent.py +20 -28
  44. klaude_code/core/executor.py +327 -112
  45. klaude_code/core/manager/__init__.py +2 -4
  46. klaude_code/core/manager/llm_clients.py +1 -15
  47. klaude_code/core/manager/llm_clients_builder.py +10 -11
  48. klaude_code/core/manager/sub_agent_manager.py +37 -6
  49. klaude_code/core/prompt.py +63 -44
  50. klaude_code/core/prompts/prompt-claude-code.md +2 -13
  51. klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +117 -0
  52. klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +117 -0
  53. klaude_code/core/prompts/prompt-codex.md +9 -42
  54. klaude_code/core/prompts/prompt-minimal.md +12 -0
  55. klaude_code/core/prompts/{prompt-subagent-explore.md → prompt-sub-agent-explore.md} +16 -3
  56. klaude_code/core/prompts/{prompt-subagent-oracle.md → prompt-sub-agent-oracle.md} +1 -2
  57. klaude_code/core/prompts/prompt-sub-agent-web.md +51 -0
  58. klaude_code/core/reminders.py +283 -95
  59. klaude_code/core/task.py +113 -75
  60. klaude_code/core/tool/__init__.py +24 -31
  61. klaude_code/core/tool/file/_utils.py +36 -0
  62. klaude_code/core/tool/file/apply_patch.py +17 -25
  63. klaude_code/core/tool/file/apply_patch_tool.py +57 -77
  64. klaude_code/core/tool/file/diff_builder.py +151 -0
  65. klaude_code/core/tool/file/edit_tool.py +50 -63
  66. klaude_code/core/tool/file/move_tool.md +41 -0
  67. klaude_code/core/tool/file/move_tool.py +435 -0
  68. klaude_code/core/tool/file/read_tool.md +1 -1
  69. klaude_code/core/tool/file/read_tool.py +86 -86
  70. klaude_code/core/tool/file/write_tool.py +59 -69
  71. klaude_code/core/tool/report_back_tool.py +84 -0
  72. klaude_code/core/tool/shell/bash_tool.py +265 -22
  73. klaude_code/core/tool/shell/command_safety.py +3 -6
  74. klaude_code/core/tool/{memory → skill}/skill_tool.py +16 -26
  75. klaude_code/core/tool/sub_agent_tool.py +13 -2
  76. klaude_code/core/tool/todo/todo_write_tool.md +0 -157
  77. klaude_code/core/tool/todo/todo_write_tool.py +1 -1
  78. klaude_code/core/tool/todo/todo_write_tool_raw.md +182 -0
  79. klaude_code/core/tool/todo/update_plan_tool.py +1 -1
  80. klaude_code/core/tool/tool_abc.py +18 -0
  81. klaude_code/core/tool/tool_context.py +27 -12
  82. klaude_code/core/tool/tool_registry.py +7 -7
  83. klaude_code/core/tool/tool_runner.py +44 -36
  84. klaude_code/core/tool/truncation.py +29 -14
  85. klaude_code/core/tool/web/mermaid_tool.md +43 -0
  86. klaude_code/core/tool/web/mermaid_tool.py +2 -5
  87. klaude_code/core/tool/web/web_fetch_tool.md +1 -1
  88. klaude_code/core/tool/web/web_fetch_tool.py +112 -22
  89. klaude_code/core/tool/web/web_search_tool.md +23 -0
  90. klaude_code/core/tool/web/web_search_tool.py +130 -0
  91. klaude_code/core/turn.py +168 -66
  92. klaude_code/llm/__init__.py +2 -10
  93. klaude_code/llm/anthropic/client.py +190 -178
  94. klaude_code/llm/anthropic/input.py +39 -15
  95. klaude_code/llm/bedrock/__init__.py +3 -0
  96. klaude_code/llm/bedrock/client.py +60 -0
  97. klaude_code/llm/client.py +7 -21
  98. klaude_code/llm/codex/__init__.py +5 -0
  99. klaude_code/llm/codex/client.py +149 -0
  100. klaude_code/llm/google/__init__.py +3 -0
  101. klaude_code/llm/google/client.py +309 -0
  102. klaude_code/llm/google/input.py +215 -0
  103. klaude_code/llm/input_common.py +3 -9
  104. klaude_code/llm/openai_compatible/client.py +72 -164
  105. klaude_code/llm/openai_compatible/input.py +6 -4
  106. klaude_code/llm/openai_compatible/stream.py +273 -0
  107. klaude_code/llm/openai_compatible/tool_call_accumulator.py +17 -1
  108. klaude_code/llm/openrouter/client.py +89 -160
  109. klaude_code/llm/openrouter/input.py +18 -30
  110. klaude_code/llm/openrouter/reasoning.py +118 -0
  111. klaude_code/llm/registry.py +39 -7
  112. klaude_code/llm/responses/client.py +184 -171
  113. klaude_code/llm/responses/input.py +20 -1
  114. klaude_code/llm/usage.py +17 -12
  115. klaude_code/protocol/commands.py +17 -1
  116. klaude_code/protocol/events.py +31 -4
  117. klaude_code/protocol/llm_param.py +13 -10
  118. klaude_code/protocol/model.py +232 -29
  119. klaude_code/protocol/op.py +90 -1
  120. klaude_code/protocol/op_handler.py +35 -1
  121. klaude_code/protocol/sub_agent/__init__.py +117 -0
  122. klaude_code/protocol/sub_agent/explore.py +63 -0
  123. klaude_code/protocol/sub_agent/oracle.py +91 -0
  124. klaude_code/protocol/sub_agent/task.py +61 -0
  125. klaude_code/protocol/sub_agent/web.py +79 -0
  126. klaude_code/protocol/tools.py +4 -2
  127. klaude_code/session/__init__.py +2 -2
  128. klaude_code/session/codec.py +71 -0
  129. klaude_code/session/export.py +293 -86
  130. klaude_code/session/selector.py +89 -67
  131. klaude_code/session/session.py +320 -309
  132. klaude_code/session/store.py +220 -0
  133. klaude_code/session/templates/export_session.html +595 -83
  134. klaude_code/session/templates/mermaid_viewer.html +926 -0
  135. klaude_code/skill/__init__.py +27 -0
  136. klaude_code/skill/assets/deslop/SKILL.md +17 -0
  137. klaude_code/skill/assets/dev-docs/SKILL.md +108 -0
  138. klaude_code/skill/assets/handoff/SKILL.md +39 -0
  139. klaude_code/skill/assets/jj-workspace/SKILL.md +20 -0
  140. klaude_code/skill/assets/skill-creator/SKILL.md +139 -0
  141. klaude_code/{core/tool/memory/skill_loader.py → skill/loader.py} +55 -15
  142. klaude_code/skill/manager.py +70 -0
  143. klaude_code/skill/system_skills.py +192 -0
  144. klaude_code/trace/__init__.py +20 -2
  145. klaude_code/trace/log.py +150 -5
  146. klaude_code/ui/__init__.py +4 -9
  147. klaude_code/ui/core/input.py +1 -1
  148. klaude_code/ui/core/stage_manager.py +7 -7
  149. klaude_code/ui/modes/debug/display.py +2 -1
  150. klaude_code/ui/modes/repl/__init__.py +3 -48
  151. klaude_code/ui/modes/repl/clipboard.py +5 -5
  152. klaude_code/ui/modes/repl/completers.py +487 -123
  153. klaude_code/ui/modes/repl/display.py +5 -4
  154. klaude_code/ui/modes/repl/event_handler.py +370 -117
  155. klaude_code/ui/modes/repl/input_prompt_toolkit.py +552 -105
  156. klaude_code/ui/modes/repl/key_bindings.py +146 -23
  157. klaude_code/ui/modes/repl/renderer.py +189 -99
  158. klaude_code/ui/renderers/assistant.py +9 -2
  159. klaude_code/ui/renderers/bash_syntax.py +178 -0
  160. klaude_code/ui/renderers/common.py +78 -0
  161. klaude_code/ui/renderers/developer.py +104 -48
  162. klaude_code/ui/renderers/diffs.py +87 -6
  163. klaude_code/ui/renderers/errors.py +11 -6
  164. klaude_code/ui/renderers/mermaid_viewer.py +57 -0
  165. klaude_code/ui/renderers/metadata.py +112 -76
  166. klaude_code/ui/renderers/sub_agent.py +92 -7
  167. klaude_code/ui/renderers/thinking.py +40 -18
  168. klaude_code/ui/renderers/tools.py +405 -227
  169. klaude_code/ui/renderers/user_input.py +73 -13
  170. klaude_code/ui/rich/__init__.py +10 -1
  171. klaude_code/ui/rich/cjk_wrap.py +228 -0
  172. klaude_code/ui/rich/code_panel.py +131 -0
  173. klaude_code/ui/rich/live.py +17 -0
  174. klaude_code/ui/rich/markdown.py +305 -170
  175. klaude_code/ui/rich/searchable_text.py +10 -13
  176. klaude_code/ui/rich/status.py +190 -49
  177. klaude_code/ui/rich/theme.py +135 -39
  178. klaude_code/ui/terminal/__init__.py +55 -0
  179. klaude_code/ui/terminal/color.py +1 -1
  180. klaude_code/ui/terminal/control.py +13 -22
  181. klaude_code/ui/terminal/notifier.py +44 -4
  182. klaude_code/ui/terminal/selector.py +658 -0
  183. klaude_code/ui/utils/common.py +0 -18
  184. klaude_code-1.8.0.dist-info/METADATA +377 -0
  185. klaude_code-1.8.0.dist-info/RECORD +219 -0
  186. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/entry_points.txt +1 -0
  187. klaude_code/command/diff_cmd.py +0 -138
  188. klaude_code/command/prompt-dev-docs-update.md +0 -56
  189. klaude_code/command/prompt-dev-docs.md +0 -46
  190. klaude_code/config/list_model.py +0 -162
  191. klaude_code/core/manager/agent_manager.py +0 -127
  192. klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -46
  193. klaude_code/core/tool/file/multi_edit_tool.md +0 -42
  194. klaude_code/core/tool/file/multi_edit_tool.py +0 -199
  195. klaude_code/core/tool/memory/memory_tool.md +0 -16
  196. klaude_code/core/tool/memory/memory_tool.py +0 -462
  197. klaude_code/llm/openrouter/reasoning_handler.py +0 -209
  198. klaude_code/protocol/sub_agent.py +0 -348
  199. klaude_code/ui/utils/debouncer.py +0 -42
  200. klaude_code-1.2.6.dist-info/METADATA +0 -178
  201. klaude_code-1.2.6.dist-info/RECORD +0 -167
  202. /klaude_code/core/prompts/{prompt-subagent.md → prompt-sub-agent.md} +0 -0
  203. /klaude_code/core/tool/{memory → skill}/__init__.py +0 -0
  204. /klaude_code/core/tool/{memory → skill}/skill_tool.md +0 -0
  205. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,220 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import json
5
+ import shutil
6
+ from collections.abc import Iterable, Sequence
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Any, cast
10
+
11
+ from klaude_code.protocol import llm_param, model
12
+ from klaude_code.session.codec import decode_jsonl_line, encode_jsonl_line
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class ProjectPaths:
17
+ project_key: str
18
+
19
+ @property
20
+ def base_dir(self) -> Path:
21
+ return Path.home() / ".klaude" / "projects" / self.project_key
22
+
23
+ @property
24
+ def sessions_dir(self) -> Path:
25
+ return self.base_dir / "sessions"
26
+
27
+ @property
28
+ def exports_dir(self) -> Path:
29
+ return self.base_dir / "exports"
30
+
31
+ def session_dir(self, session_id: str) -> Path:
32
+ return self.sessions_dir / session_id
33
+
34
+ def events_file(self, session_id: str) -> Path:
35
+ return self.session_dir(session_id) / "events.jsonl"
36
+
37
+ def meta_file(self, session_id: str) -> Path:
38
+ return self.session_dir(session_id) / "meta.json"
39
+
40
+
41
+ class _WriterClosedError(RuntimeError):
42
+ pass
43
+
44
+
45
+ @dataclass
46
+ class _WriteBatch:
47
+ session_id: str
48
+ event_lines: list[str]
49
+ meta: dict[str, Any]
50
+ done: asyncio.Future[None]
51
+
52
+
53
+ class JsonlSessionWriter:
54
+ def __init__(self, paths: ProjectPaths) -> None:
55
+ self._paths = paths
56
+ self._queue: asyncio.Queue[_WriteBatch | None] = asyncio.Queue()
57
+ self._task: asyncio.Task[None] | None = None
58
+ self._closed = False
59
+
60
+ def ensure_started(self) -> None:
61
+ if self._closed:
62
+ raise _WriterClosedError("writer is closed")
63
+ if self._task is not None:
64
+ return
65
+ loop = asyncio.get_running_loop()
66
+ self._task = loop.create_task(self._run())
67
+
68
+ def enqueue(self, batch: _WriteBatch) -> None:
69
+ if self._closed:
70
+ raise _WriterClosedError("writer is closed")
71
+ self.ensure_started()
72
+ self._queue.put_nowait(batch)
73
+
74
+ async def aclose(self) -> None:
75
+ if self._closed:
76
+ return
77
+ self._closed = True
78
+ task = self._task
79
+ if task is None:
80
+ return
81
+ await self._queue.put(None)
82
+ await task
83
+ self._task = None
84
+
85
+ async def _run(self) -> None:
86
+ while True:
87
+ msg = await self._queue.get()
88
+ try:
89
+ if msg is None:
90
+ return
91
+ try:
92
+ await asyncio.to_thread(self._write_batch_sync, msg)
93
+ except Exception as exc:
94
+ if not msg.done.done():
95
+ msg.done.set_exception(exc)
96
+ finally:
97
+ self._queue.task_done()
98
+
99
+ def _write_batch_sync(self, batch: _WriteBatch) -> None:
100
+ session_dir = self._paths.session_dir(batch.session_id)
101
+ session_dir.mkdir(parents=True, exist_ok=True)
102
+
103
+ events_path = self._paths.events_file(batch.session_id)
104
+ with events_path.open("a", encoding="utf-8") as f:
105
+ for line in batch.event_lines:
106
+ f.write(line)
107
+ f.flush()
108
+
109
+ meta_path = self._paths.meta_file(batch.session_id)
110
+ tmp_path = meta_path.with_suffix(".json.tmp")
111
+ tmp_path.write_text(json.dumps(batch.meta, ensure_ascii=False, indent=2), encoding="utf-8")
112
+ tmp_path.replace(meta_path)
113
+
114
+ if not batch.done.done():
115
+ batch.done.set_result(None)
116
+
117
+
118
+ class JsonlSessionStore:
119
+ def __init__(self, *, project_key: str) -> None:
120
+ self._paths = ProjectPaths(project_key=project_key)
121
+ self._writer = JsonlSessionWriter(self._paths)
122
+ self._last_flush: dict[str, asyncio.Future[None]] = {}
123
+
124
+ @property
125
+ def paths(self) -> ProjectPaths:
126
+ return self._paths
127
+
128
+ def load_meta(self, session_id: str) -> dict[str, Any] | None:
129
+ meta_path = self._paths.meta_file(session_id)
130
+ if not meta_path.exists():
131
+ return None
132
+ try:
133
+ raw = json.loads(meta_path.read_text(encoding="utf-8"))
134
+ except (json.JSONDecodeError, OSError):
135
+ return None
136
+ return cast(dict[str, Any], raw) if isinstance(raw, dict) else None
137
+
138
+ def load_history(self, session_id: str) -> list[model.ConversationItem]:
139
+ events_path = self._paths.events_file(session_id)
140
+ if not events_path.exists():
141
+ return []
142
+ try:
143
+ lines = events_path.read_text(encoding="utf-8").splitlines()
144
+ except OSError:
145
+ return []
146
+ items: list[model.ConversationItem] = []
147
+ for line in lines:
148
+ item = decode_jsonl_line(line)
149
+ if item is None:
150
+ continue
151
+ items.append(item)
152
+ return items
153
+
154
+ def append_and_flush(
155
+ self, *, session_id: str, items: Sequence[model.ConversationItem], meta: dict[str, Any]
156
+ ) -> None:
157
+ if not items:
158
+ return
159
+ loop = asyncio.get_running_loop()
160
+ done: asyncio.Future[None] = loop.create_future()
161
+ self._last_flush[session_id] = done
162
+ batch = _WriteBatch(
163
+ session_id=session_id,
164
+ event_lines=[encode_jsonl_line(item) for item in items],
165
+ meta=meta,
166
+ done=done,
167
+ )
168
+ self._writer.enqueue(batch)
169
+
170
+ async def wait_for_flush(self, session_id: str) -> None:
171
+ fut = self._last_flush.get(session_id)
172
+ if fut is None:
173
+ return
174
+ await fut
175
+
176
+ def iter_meta_files(self) -> Iterable[Path]:
177
+ sessions_dir = self._paths.sessions_dir
178
+ if not sessions_dir.exists():
179
+ return []
180
+ return sessions_dir.glob("*/meta.json")
181
+
182
+ def delete_session(self, session_id: str) -> None:
183
+ shutil.rmtree(self._paths.session_dir(session_id), ignore_errors=True)
184
+
185
+ async def aclose(self) -> None:
186
+ await self._writer.aclose()
187
+
188
+
189
+ def build_meta_snapshot(
190
+ *,
191
+ session_id: str,
192
+ work_dir: Path,
193
+ sub_agent_state: model.SubAgentState | None,
194
+ file_tracker: dict[str, model.FileStatus],
195
+ todos: list[model.TodoItem],
196
+ user_messages: list[str],
197
+ created_at: float,
198
+ updated_at: float,
199
+ messages_count: int,
200
+ model_name: str | None,
201
+ model_config_name: str | None,
202
+ model_thinking: llm_param.Thinking | None,
203
+ ) -> dict[str, Any]:
204
+ return {
205
+ "id": session_id,
206
+ "work_dir": str(work_dir),
207
+ "sub_agent_state": sub_agent_state.model_dump(mode="json") if sub_agent_state else None,
208
+ "file_tracker": {path: status.model_dump(mode="json") for path, status in file_tracker.items()},
209
+ "todos": [todo.model_dump(mode="json", exclude_defaults=True) for todo in todos],
210
+ # Cache user messages to avoid scanning events.jsonl during session listing.
211
+ "user_messages": list(user_messages),
212
+ "created_at": created_at,
213
+ "updated_at": updated_at,
214
+ "messages_count": messages_count,
215
+ "model_name": model_name,
216
+ "model_config_name": model_config_name,
217
+ "model_thinking": model_thinking.model_dump(mode="json", exclude_defaults=True, exclude_none=True)
218
+ if model_thinking
219
+ else None,
220
+ }