klaude-code 1.2.23__tar.gz → 1.2.25__tar.gz

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 (203) hide show
  1. {klaude_code-1.2.23 → klaude_code-1.2.25}/PKG-INFO +2 -1
  2. {klaude_code-1.2.23 → klaude_code-1.2.25}/pyproject.toml +2 -1
  3. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/runtime.py +17 -1
  4. klaude_code-1.2.25/src/klaude_code/command/prompt-jj-describe.md +32 -0
  5. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/thinking_cmd.py +37 -28
  6. klaude_code-1.2.23/src/klaude_code/const/__init__.py → klaude_code-1.2.25/src/klaude_code/const.py +7 -6
  7. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/executor.py +46 -3
  8. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/read_tool.py +23 -1
  9. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/write_tool.py +7 -3
  10. klaude_code-1.2.25/src/klaude_code/llm/openai_compatible/client.py +119 -0
  11. klaude_code-1.2.25/src/klaude_code/llm/openai_compatible/stream.py +272 -0
  12. klaude_code-1.2.25/src/klaude_code/llm/openrouter/client.py +129 -0
  13. klaude_code-1.2.23/src/klaude_code/llm/openrouter/reasoning_handler.py → klaude_code-1.2.25/src/klaude_code/llm/openrouter/reasoning.py +24 -2
  14. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/model.py +13 -1
  15. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/op.py +11 -0
  16. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/op_handler.py +5 -0
  17. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/core/stage_manager.py +0 -3
  18. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/display.py +2 -0
  19. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/event_handler.py +97 -57
  20. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +25 -4
  21. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/renderer.py +119 -25
  22. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/assistant.py +1 -1
  23. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/metadata.py +2 -6
  24. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/sub_agent.py +28 -5
  25. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/thinking.py +16 -10
  26. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/tools.py +26 -2
  27. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/code_panel.py +24 -5
  28. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/live.py +17 -0
  29. klaude_code-1.2.25/src/klaude_code/ui/rich/markdown.py +391 -0
  30. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/status.py +19 -17
  31. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/theme.py +63 -12
  32. klaude_code-1.2.23/src/klaude_code/llm/openai_compatible/client.py +0 -192
  33. klaude_code-1.2.23/src/klaude_code/llm/openai_compatible/stream_processor.py +0 -83
  34. klaude_code-1.2.23/src/klaude_code/llm/openrouter/client.py +0 -209
  35. klaude_code-1.2.23/src/klaude_code/ui/rich/markdown.py +0 -313
  36. {klaude_code-1.2.23 → klaude_code-1.2.25}/README.md +0 -0
  37. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/__init__.py +0 -0
  38. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/__init__.py +0 -0
  39. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/codex/__init__.py +0 -0
  40. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/codex/exceptions.py +0 -0
  41. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  42. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/codex/oauth.py +0 -0
  43. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/auth/codex/token_manager.py +0 -0
  44. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/__init__.py +0 -0
  45. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/auth_cmd.py +0 -0
  46. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/config_cmd.py +0 -0
  47. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/debug.py +0 -0
  48. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/list_model.py +0 -0
  49. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/main.py +0 -0
  50. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/self_update.py +0 -0
  51. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/cli/session_cmd.py +0 -0
  52. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/__init__.py +0 -0
  53. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/clear_cmd.py +0 -0
  54. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/command_abc.py +0 -0
  55. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/debug_cmd.py +0 -0
  56. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/export_cmd.py +0 -0
  57. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/export_online_cmd.py +0 -0
  58. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/help_cmd.py +0 -0
  59. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/model_cmd.py +0 -0
  60. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/prompt-init.md +0 -0
  61. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/prompt_command.py +0 -0
  62. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/refresh_cmd.py +0 -0
  63. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/registry.py +0 -0
  64. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/release_notes_cmd.py +0 -0
  65. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/status_cmd.py +0 -0
  66. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
  67. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/config/__init__.py +0 -0
  68. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/config/config.py +0 -0
  69. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/config/select_model.py +0 -0
  70. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/__init__.py +0 -0
  71. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/agent.py +0 -0
  72. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/manager/__init__.py +0 -0
  73. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/manager/llm_clients.py +0 -0
  74. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  75. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  76. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompt.py +0 -0
  77. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  78. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  79. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
  80. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
  81. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  82. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  83. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  84. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
  85. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  86. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  87. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/reminders.py +0 -0
  88. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/task.py +0 -0
  89. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/__init__.py +0 -0
  90. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/__init__.py +0 -0
  91. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/_utils.py +0 -0
  92. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  93. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  94. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  95. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  96. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  97. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  98. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  99. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  100. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  101. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  102. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  103. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  104. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  105. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/skill/__init__.py +0 -0
  106. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
  107. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
  108. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  109. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  110. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  111. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  112. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  113. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  114. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  115. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/tool_abc.py +0 -0
  116. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/tool_context.py +0 -0
  117. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/tool_registry.py +0 -0
  118. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/tool_runner.py +0 -0
  119. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/truncation.py +0 -0
  120. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/__init__.py +0 -0
  121. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  122. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  123. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  124. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  125. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  126. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  127. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/core/turn.py +0 -0
  128. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/__init__.py +0 -0
  129. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  130. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/anthropic/client.py +0 -0
  131. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/anthropic/input.py +0 -0
  132. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/client.py +0 -0
  133. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/codex/__init__.py +0 -0
  134. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/codex/client.py +0 -0
  135. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/input_common.py +0 -0
  136. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  137. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  138. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  139. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  140. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/openrouter/input.py +0 -0
  141. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/registry.py +0 -0
  142. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/responses/__init__.py +0 -0
  143. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/responses/client.py +0 -0
  144. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/responses/input.py +0 -0
  145. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/llm/usage.py +0 -0
  146. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/__init__.py +0 -0
  147. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/commands.py +0 -0
  148. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/events.py +0 -0
  149. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/llm_param.py +0 -0
  150. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  151. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  152. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
  153. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  154. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  155. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/protocol/tools.py +0 -0
  156. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/__init__.py +0 -0
  157. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/codec.py +0 -0
  158. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/export.py +0 -0
  159. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/selector.py +0 -0
  160. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/session.py +0 -0
  161. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/store.py +0 -0
  162. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/session/templates/export_session.html +0 -0
  163. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/__init__.py +0 -0
  164. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  165. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
  166. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
  167. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
  168. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  169. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/loader.py +0 -0
  170. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/manager.py +0 -0
  171. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/skill/system_skills.py +0 -0
  172. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/trace/__init__.py +0 -0
  173. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/trace/log.py +0 -0
  174. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/__init__.py +0 -0
  175. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/core/__init__.py +0 -0
  176. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/core/display.py +0 -0
  177. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/core/input.py +0 -0
  178. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/__init__.py +0 -0
  179. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
  180. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/debug/display.py +0 -0
  181. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
  182. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/exec/display.py +0 -0
  183. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
  184. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
  185. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/completers.py +0 -0
  186. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/modes/repl/key_bindings.py +0 -0
  187. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/__init__.py +0 -0
  188. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/common.py +0 -0
  189. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/developer.py +0 -0
  190. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/diffs.py +0 -0
  191. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/errors.py +0 -0
  192. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/renderers/user_input.py +0 -0
  193. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/__init__.py +0 -0
  194. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
  195. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/quote.py +0 -0
  196. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/rich/searchable_text.py +0 -0
  197. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/terminal/__init__.py +0 -0
  198. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/terminal/color.py +0 -0
  199. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/terminal/control.py +0 -0
  200. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/terminal/notifier.py +0 -0
  201. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
  202. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/utils/__init__.py +0 -0
  203. {klaude_code-1.2.23 → klaude_code-1.2.25}/src/klaude_code/ui/utils/common.py +0 -0
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.23
3
+ Version: 1.2.25
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
7
7
  Requires-Dist: ddgs>=9.9.3
8
8
  Requires-Dist: diff-match-patch>=20241021
9
+ Requires-Dist: markdown-it-py>=4.0.0
9
10
  Requires-Dist: openai>=1.102.0
10
11
  Requires-Dist: pillow>=12.0.0
11
12
  Requires-Dist: prompt-toolkit>=3.0.52
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "1.2.23"
7
+ version = "1.2.25"
8
8
  description = "Add your description here"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -13,6 +13,7 @@ dependencies = [
13
13
  "chardet>=5.2.0",
14
14
  "ddgs>=9.9.3",
15
15
  "diff-match-patch>=20241021",
16
+ "markdown-it-py>=4.0.0",
16
17
  "openai>=1.102.0",
17
18
  "pillow>=12.0.0",
18
19
  "prompt-toolkit>=3.0.52",
@@ -265,7 +265,23 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
265
265
  )
266
266
 
267
267
  # Set up input provider for interactive mode
268
- input_provider: ui.InputProviderABC = ui.PromptToolkitInput(status_provider=_status_provider)
268
+ def _stop_rich_bottom_ui() -> None:
269
+ display = components.display
270
+ if isinstance(display, ui.REPLDisplay):
271
+ display.renderer.spinner_stop()
272
+ display.renderer.stop_bottom_live()
273
+ elif (
274
+ isinstance(display, ui.DebugEventDisplay)
275
+ and display.wrapped_display
276
+ and isinstance(display.wrapped_display, ui.REPLDisplay)
277
+ ):
278
+ display.wrapped_display.renderer.spinner_stop()
279
+ display.wrapped_display.renderer.stop_bottom_live()
280
+
281
+ input_provider: ui.InputProviderABC = ui.PromptToolkitInput(
282
+ status_provider=_status_provider,
283
+ pre_prompt=_stop_rich_bottom_ui,
284
+ )
269
285
 
270
286
  # --- Custom Ctrl+C handler: double-press within 2s to exit, single press shows toast ---
271
287
  def _show_toast_once() -> None:
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: Add description for current jj change
3
+ ---
4
+
5
+ Run `jj status` and `jj diff --git` to see the current changes and add a description for the it.
6
+
7
+ In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:<example>
8
+ jj describe -m "$(cat <<'EOF'
9
+ Commit message here.
10
+ EOF
11
+ )"
12
+ </example>
13
+
14
+ Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
15
+ ```
16
+ <type>(<scope>): <description>
17
+ ```
18
+
19
+ Types:
20
+ - `feat`: New feature
21
+ - `fix`: Bug fix
22
+ - `docs`: Documentation changes
23
+ - `style`: Code style changes (formatting, no logic change)
24
+ - `refactor`: Code refactoring (no feature or fix)
25
+ - `test`: Adding or updating tests
26
+ - `chore`: Build process, dependencies, or tooling changes
27
+
28
+ Examples:
29
+ - `feat(cli): add --verbose flag for debug output`
30
+ - `fix(llm): handle API timeout errors gracefully`
31
+ - `docs(readme): update installation instructions`
32
+ - `refactor(core): simplify session state management`
@@ -56,6 +56,14 @@ def _is_gemini_flash_model(model_name: str | None) -> bool:
56
56
  return "gemini-3-flash" in model_name.lower()
57
57
 
58
58
 
59
+ def should_auto_trigger_thinking(model_name: str | None) -> bool:
60
+ """Check if model should auto-trigger thinking selection on switch."""
61
+ if not model_name:
62
+ return False
63
+ model_lower = model_name.lower()
64
+ return "gpt-5" in model_lower or "gemini-3" in model_lower or "opus" in model_lower
65
+
66
+
59
67
  def _get_levels_for_responses(model_name: str | None) -> list[str]:
60
68
  """Get thinking levels for responses protocol."""
61
69
  if _is_codex_max_model(model_name):
@@ -69,7 +77,7 @@ def _get_levels_for_responses(model_name: str | None) -> list[str]:
69
77
  return RESPONSES_LEVELS
70
78
 
71
79
 
72
- def _format_current_thinking(config: llm_param.LLMConfigParameter) -> str:
80
+ def format_current_thinking(config: llm_param.LLMConfigParameter) -> str:
73
81
  """Format the current thinking configuration for display."""
74
82
  thinking = config.thinking
75
83
  if not thinking:
@@ -164,6 +172,31 @@ def _select_anthropic_thinking_sync() -> llm_param.Thinking | None:
164
172
  return None
165
173
 
166
174
 
175
+ async def select_thinking_for_protocol(config: llm_param.LLMConfigParameter) -> llm_param.Thinking | None:
176
+ """Select thinking configuration based on the LLM protocol.
177
+
178
+ Returns the selected Thinking config, or None if user cancelled.
179
+ """
180
+ protocol = config.protocol
181
+ model_name = config.model
182
+
183
+ if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.CODEX):
184
+ return await asyncio.to_thread(_select_responses_thinking_sync, model_name)
185
+
186
+ if protocol == llm_param.LLMClientProtocol.ANTHROPIC:
187
+ return await asyncio.to_thread(_select_anthropic_thinking_sync)
188
+
189
+ if protocol == llm_param.LLMClientProtocol.OPENROUTER:
190
+ if _is_openrouter_model_with_reasoning_effort(model_name):
191
+ return await asyncio.to_thread(_select_responses_thinking_sync, model_name)
192
+ return await asyncio.to_thread(_select_anthropic_thinking_sync)
193
+
194
+ if protocol == llm_param.LLMClientProtocol.OPENAI:
195
+ return await asyncio.to_thread(_select_anthropic_thinking_sync)
196
+
197
+ return None
198
+
199
+
167
200
  class ThinkingCommand(CommandABC):
168
201
  """Configure model thinking/reasoning level."""
169
202
 
@@ -185,40 +218,16 @@ class ThinkingCommand(CommandABC):
185
218
  return self._no_change_result(agent, "No profile configured")
186
219
 
187
220
  config = agent.profile.llm_client.get_llm_config()
188
- protocol = config.protocol
189
- model_name = config.model
190
-
191
- current = _format_current_thinking(config)
192
-
193
- # Select new thinking configuration based on protocol
194
- new_thinking: llm_param.Thinking | None = None
195
-
196
- if protocol in (llm_param.LLMClientProtocol.RESPONSES, llm_param.LLMClientProtocol.CODEX):
197
- new_thinking = await asyncio.to_thread(_select_responses_thinking_sync, model_name)
198
-
199
- elif protocol == llm_param.LLMClientProtocol.ANTHROPIC:
200
- new_thinking = await asyncio.to_thread(_select_anthropic_thinking_sync)
201
-
202
- elif protocol == llm_param.LLMClientProtocol.OPENROUTER:
203
- if _is_openrouter_model_with_reasoning_effort(model_name):
204
- new_thinking = await asyncio.to_thread(_select_responses_thinking_sync, model_name)
205
- else:
206
- new_thinking = await asyncio.to_thread(_select_anthropic_thinking_sync)
207
-
208
- elif protocol == llm_param.LLMClientProtocol.OPENAI:
209
- # openai_compatible uses anthropic style
210
- new_thinking = await asyncio.to_thread(_select_anthropic_thinking_sync)
211
-
212
- else:
213
- return self._no_change_result(agent, f"Unsupported protocol: {protocol}")
221
+ current = format_current_thinking(config)
214
222
 
223
+ new_thinking = await select_thinking_for_protocol(config)
215
224
  if new_thinking is None:
216
225
  return self._no_change_result(agent, "(no change)")
217
226
 
218
227
  # Apply the new thinking configuration
219
228
  config.thinking = new_thinking
220
229
  agent.session.model_thinking = new_thinking
221
- new_status = _format_current_thinking(config)
230
+ new_status = format_current_thinking(config)
222
231
 
223
232
  return CommandResult(
224
233
  events=[
@@ -93,7 +93,7 @@ TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 1000
93
93
  TRUNCATE_DISPLAY_MAX_LINES = 8
94
94
 
95
95
  # Maximum lines for sub-agent result display
96
- SUB_AGENT_RESULT_MAX_LINES = 20
96
+ SUB_AGENT_RESULT_MAX_LINES = 50
97
97
 
98
98
 
99
99
  # UI refresh rate (frames per second) for debounced content streaming
@@ -111,19 +111,20 @@ MARKDOWN_RIGHT_MARGIN = 2
111
111
  # Status hint text shown after spinner status
112
112
  STATUS_HINT_TEXT = " (esc to interrupt)"
113
113
 
114
+ # Default spinner status text when idle/thinking
115
+ STATUS_DEFAULT_TEXT = "Thinking …"
116
+
114
117
  # Status shimmer animation
115
118
  # Horizontal padding used when computing shimmer band position
116
119
  STATUS_SHIMMER_PADDING = 10
117
- # Duration in seconds for one full shimmer sweep across the text
118
- STATUS_SHIMMER_SWEEP_SECONDS = 2
119
120
  # Half-width of the shimmer band in characters
120
121
  STATUS_SHIMMER_BAND_HALF_WIDTH = 5.0
121
122
  # Scale factor applied to shimmer intensity when blending colors
122
123
  STATUS_SHIMMER_ALPHA_SCALE = 0.7
123
124
 
124
- # Spinner breathing animation
125
- # Duration in seconds for one full breathe-in + breathe-out cycle
126
- # Keep in sync with STATUS_SHIMMER_SWEEP_SECONDS for visual consistency
125
+ # Spinner breathing and shimmer animation period
126
+ # Duration in seconds for one full breathe-in + breathe-out cycle (breathing)
127
+ # and one full shimmer sweep across the text (shimmer)
127
128
  SPINNER_BREATH_PERIOD_SECONDS: float = 2.0
128
129
 
129
130
 
@@ -14,6 +14,11 @@ from dataclasses import dataclass
14
14
  from pathlib import Path
15
15
 
16
16
  from klaude_code.command import dispatch_command
17
+ from klaude_code.command.thinking_cmd import (
18
+ format_current_thinking,
19
+ select_thinking_for_protocol,
20
+ should_auto_trigger_thinking,
21
+ )
17
22
  from klaude_code.config import load_config
18
23
  from klaude_code.core.agent import Agent, DefaultModelProfileProvider, ModelProfileProvider
19
24
  from klaude_code.core.manager import LLMClients, SubAgentManager
@@ -235,17 +240,55 @@ class ExecutorContext:
235
240
  agent.session.model_thinking = llm_config.thinking
236
241
 
237
242
  developer_item = model.DeveloperMessageItem(
238
- content=f"switched to model: {operation.model_name}",
243
+ content=f"Switched to: {llm_config.model}",
239
244
  command_output=model.CommandOutput(command_name=commands.CommandName.MODEL),
240
245
  )
241
246
  agent.session.append_history([developer_item])
242
247
 
243
248
  await self.emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
244
- await self.emit_event(events.WelcomeEvent(llm_config=llm_config, work_dir=str(agent.session.work_dir)))
245
249
 
246
250
  if self._on_model_change is not None:
247
251
  self._on_model_change(llm_client.model_name)
248
252
 
253
+ if should_auto_trigger_thinking(llm_config.model):
254
+ thinking_op = op.ChangeThinkingOperation(session_id=operation.session_id)
255
+ await thinking_op.execute(handler=self)
256
+ # WelcomeEvent is already handled by the thinking change
257
+ else:
258
+ await self.emit_event(events.WelcomeEvent(llm_config=llm_config, work_dir=str(agent.session.work_dir)))
259
+
260
+ async def handle_change_thinking(self, operation: op.ChangeThinkingOperation) -> None:
261
+ """Handle a change thinking operation by prompting user to select thinking level."""
262
+ agent = await self._ensure_agent(operation.session_id)
263
+ if not agent.profile:
264
+ return
265
+
266
+ config = agent.profile.llm_client.get_llm_config()
267
+ current = format_current_thinking(config)
268
+
269
+ new_thinking = await select_thinking_for_protocol(config)
270
+
271
+ if new_thinking is None:
272
+ developer_item = model.DeveloperMessageItem(
273
+ content="(thinking unchanged)",
274
+ command_output=model.CommandOutput(command_name=commands.CommandName.THINKING),
275
+ )
276
+ await self.emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
277
+ return
278
+
279
+ config.thinking = new_thinking
280
+ agent.session.model_thinking = new_thinking
281
+ new_status = format_current_thinking(config)
282
+
283
+ developer_item = model.DeveloperMessageItem(
284
+ content=f"Thinking changed: {current} -> {new_status}",
285
+ command_output=model.CommandOutput(command_name=commands.CommandName.THINKING),
286
+ )
287
+ agent.session.append_history([developer_item])
288
+
289
+ await self.emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
290
+ await self.emit_event(events.WelcomeEvent(work_dir=str(agent.session.work_dir), llm_config=config))
291
+
249
292
  async def handle_clear_session(self, operation: op.ClearSessionOperation) -> None:
250
293
  agent = await self._ensure_agent(operation.session_id)
251
294
  new_session = Session.create(work_dir=agent.session.work_dir)
@@ -327,7 +370,7 @@ class ExecutorContext:
327
370
  log_debug(traceback.format_exc(), style="red", debug_type=DebugType.EXECUTION)
328
371
  await self.emit_event(
329
372
  events.ErrorEvent(
330
- error_message=f"Agent task failed: [{e.__class__.__name__}] {e!s}",
373
+ error_message=f"Agent task failed: [{e.__class__.__name__}] {e!s} {traceback.format_exc()}",
331
374
  can_retry=False,
332
375
  )
333
376
  )
@@ -25,6 +25,18 @@ _IMAGE_MIME_TYPES: dict[str, str] = {
25
25
  ".webp": "image/webp",
26
26
  }
27
27
 
28
+ _BINARY_CHECK_SIZE = 8192
29
+
30
+
31
+ def _is_binary_file(file_path: str) -> bool:
32
+ """Check if a file is binary by looking for null bytes in the first chunk."""
33
+ try:
34
+ with open(file_path, "rb") as f:
35
+ chunk = f.read(_BINARY_CHECK_SIZE)
36
+ return b"\x00" in chunk
37
+ except OSError:
38
+ return False
39
+
28
40
 
29
41
  def _format_numbered_line(line_no: int, content: str) -> str:
30
42
  # 6-width right-aligned line number followed by a right arrow
@@ -218,12 +230,22 @@ class ReadTool(ToolABC):
218
230
  ),
219
231
  )
220
232
 
233
+ is_image_file = _is_supported_image_file(file_path)
234
+ # Check for binary files (skip for images which are handled separately)
235
+ if not is_image_file and _is_binary_file(file_path):
236
+ return model.ToolResultItem(
237
+ status="error",
238
+ output=(
239
+ "<tool_use_error>This appears to be a binary file and cannot be read as text. "
240
+ "Use appropriate tools or libraries to handle binary files.</tool_use_error>"
241
+ ),
242
+ )
243
+
221
244
  try:
222
245
  size_bytes = Path(file_path).stat().st_size
223
246
  except OSError:
224
247
  size_bytes = 0
225
248
 
226
- is_image_file = _is_supported_image_file(file_path)
227
249
  if is_image_file:
228
250
  if size_bytes > const.READ_MAX_IMAGE_BYTES:
229
251
  size_mb = size_bytes / (1024 * 1024)
@@ -124,9 +124,13 @@ class WriteTool(ToolABC):
124
124
  is_memory=is_mem,
125
125
  )
126
126
 
127
- # Build diff between previous and new content
128
- after = args.content
129
- ui_extra = build_structured_diff(before, after, file_path=file_path)
127
+ # For markdown files, use MarkdownDocUIExtra to render content as markdown
128
+ # Otherwise, build diff between previous and new content
129
+ ui_extra: model.ToolResultUIExtra | None
130
+ if file_path.endswith(".md"):
131
+ ui_extra = model.MarkdownDocUIExtra(file_path=file_path, content=args.content)
132
+ else:
133
+ ui_extra = build_structured_diff(before, args.content, file_path=file_path)
130
134
 
131
135
  message = f"File {'overwritten' if exists else 'created'} successfully at: {file_path}"
132
136
  return model.ToolResultItem(status="success", output=message, ui_extra=ui_extra)
@@ -0,0 +1,119 @@
1
+ import json
2
+ from collections.abc import AsyncGenerator
3
+ from typing import Any, override
4
+
5
+ import httpx
6
+ import openai
7
+ from openai.types.chat.completion_create_params import CompletionCreateParamsStreaming
8
+
9
+ from klaude_code.llm.client import LLMClientABC
10
+ from klaude_code.llm.input_common import apply_config_defaults
11
+ from klaude_code.llm.openai_compatible.input import convert_history_to_input, convert_tool_schema
12
+ from klaude_code.llm.openai_compatible.stream import DefaultReasoningHandler, parse_chat_completions_stream
13
+ from klaude_code.llm.registry import register
14
+ from klaude_code.llm.usage import MetadataTracker
15
+ from klaude_code.protocol import llm_param, model
16
+ from klaude_code.trace import DebugType, log_debug
17
+
18
+
19
+ def build_payload(param: llm_param.LLMCallParameter) -> tuple[CompletionCreateParamsStreaming, dict[str, object]]:
20
+ """Build OpenAI API request parameters."""
21
+ messages = convert_history_to_input(param.input, param.system, param.model)
22
+ tools = convert_tool_schema(param.tools)
23
+
24
+ extra_body: dict[str, object] = {}
25
+
26
+ if param.thinking and param.thinking.type == "enabled":
27
+ extra_body["thinking"] = {
28
+ "type": param.thinking.type,
29
+ "budget": param.thinking.budget_tokens,
30
+ }
31
+
32
+ payload: CompletionCreateParamsStreaming = {
33
+ "model": str(param.model),
34
+ "tool_choice": "auto",
35
+ "parallel_tool_calls": True,
36
+ "stream": True,
37
+ "messages": messages,
38
+ "temperature": param.temperature,
39
+ "max_tokens": param.max_tokens,
40
+ "tools": tools,
41
+ "reasoning_effort": param.thinking.reasoning_effort if param.thinking else None,
42
+ "verbosity": param.verbosity,
43
+ }
44
+
45
+ return payload, extra_body
46
+
47
+
48
+ @register(llm_param.LLMClientProtocol.OPENAI)
49
+ class OpenAICompatibleClient(LLMClientABC):
50
+ def __init__(self, config: llm_param.LLMConfigParameter):
51
+ super().__init__(config)
52
+ if config.is_azure:
53
+ if not config.base_url:
54
+ raise ValueError("Azure endpoint is required")
55
+ client = openai.AsyncAzureOpenAI(
56
+ api_key=config.api_key,
57
+ azure_endpoint=str(config.base_url),
58
+ api_version=config.azure_api_version,
59
+ timeout=httpx.Timeout(300.0, connect=15.0, read=285.0),
60
+ )
61
+ else:
62
+ client = openai.AsyncOpenAI(
63
+ api_key=config.api_key,
64
+ base_url=config.base_url,
65
+ timeout=httpx.Timeout(300.0, connect=15.0, read=285.0),
66
+ )
67
+ self.client: openai.AsyncAzureOpenAI | openai.AsyncOpenAI = client
68
+
69
+ @classmethod
70
+ @override
71
+ def create(cls, config: llm_param.LLMConfigParameter) -> "LLMClientABC":
72
+ return cls(config)
73
+
74
+ @override
75
+ async def call(self, param: llm_param.LLMCallParameter) -> AsyncGenerator[model.ConversationItem]:
76
+ param = apply_config_defaults(param, self.get_llm_config())
77
+
78
+ metadata_tracker = MetadataTracker(cost_config=self.get_llm_config().cost)
79
+
80
+ payload, extra_body = build_payload(param)
81
+ extra_headers: dict[str, str] = {"extra": json.dumps({"session_id": param.session_id}, sort_keys=True)}
82
+
83
+ log_debug(
84
+ json.dumps({**payload, **extra_body}, ensure_ascii=False, default=str),
85
+ style="yellow",
86
+ debug_type=DebugType.LLM_PAYLOAD,
87
+ )
88
+
89
+ try:
90
+ stream = await self.client.chat.completions.create(
91
+ **payload,
92
+ extra_body=extra_body,
93
+ extra_headers=extra_headers,
94
+ )
95
+ except (openai.OpenAIError, httpx.HTTPError) as e:
96
+ yield model.StreamErrorItem(error=f"{e.__class__.__name__} {e!s}")
97
+ yield metadata_tracker.finalize()
98
+ return
99
+
100
+ reasoning_handler = DefaultReasoningHandler(
101
+ param_model=str(param.model),
102
+ response_id=None,
103
+ )
104
+
105
+ def on_event(event: Any) -> None:
106
+ log_debug(
107
+ event.model_dump_json(exclude_none=True),
108
+ style="blue",
109
+ debug_type=DebugType.LLM_STREAM,
110
+ )
111
+
112
+ async for item in parse_chat_completions_stream(
113
+ stream,
114
+ param=param,
115
+ metadata_tracker=metadata_tracker,
116
+ reasoning_handler=reasoning_handler,
117
+ on_event=on_event,
118
+ ):
119
+ yield item