klaude-code 2.0.0__tar.gz → 2.0.1__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 (228) hide show
  1. {klaude_code-2.0.0 → klaude_code-2.0.1}/PKG-INFO +1 -1
  2. {klaude_code-2.0.0 → klaude_code-2.0.1}/pyproject.toml +1 -1
  3. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/cost_cmd.py +1 -1
  4. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/assets/builtin_config.yaml +4 -0
  5. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/const.py +4 -3
  6. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/executor.py +0 -29
  7. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool.py +1 -2
  8. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/model.py +1 -4
  9. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/op.py +0 -13
  10. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/op_handler.py +0 -5
  11. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/event_handler.py +2 -5
  12. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/key_bindings.py +135 -1
  13. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/bash_syntax.py +36 -4
  14. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/common.py +8 -6
  15. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/tools.py +15 -20
  16. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/theme.py +13 -13
  17. {klaude_code-2.0.0 → klaude_code-2.0.1}/README.md +0 -0
  18. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/__init__.py +0 -0
  19. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/__init__.py +0 -0
  20. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/base.py +0 -0
  21. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/__init__.py +0 -0
  22. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/exceptions.py +0 -0
  23. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/oauth.py +0 -0
  24. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/token_manager.py +0 -0
  25. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/__init__.py +0 -0
  26. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/exceptions.py +0 -0
  27. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  28. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/oauth.py +0 -0
  29. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/token_manager.py +0 -0
  30. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/__init__.py +0 -0
  31. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/auth_cmd.py +0 -0
  32. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/config_cmd.py +0 -0
  33. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/debug.py +0 -0
  34. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/list_model.py +0 -0
  35. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/main.py +0 -0
  36. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/runtime.py +0 -0
  37. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/self_update.py +0 -0
  38. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/session_cmd.py +0 -0
  39. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/__init__.py +0 -0
  40. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/clear_cmd.py +0 -0
  41. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/command_abc.py +0 -0
  42. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/debug_cmd.py +0 -0
  43. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/export_cmd.py +0 -0
  44. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/export_online_cmd.py +0 -0
  45. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/fork_session_cmd.py +0 -0
  46. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/help_cmd.py +0 -0
  47. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/model_cmd.py +0 -0
  48. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/model_select.py +0 -0
  49. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt-commit.md +0 -0
  50. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt-init.md +0 -0
  51. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt_command.py +0 -0
  52. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/refresh_cmd.py +0 -0
  53. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/registry.py +0 -0
  54. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/release_notes_cmd.py +0 -0
  55. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/resume_cmd.py +0 -0
  56. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/status_cmd.py +0 -0
  57. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
  58. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/thinking_cmd.py +0 -0
  59. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/__init__.py +0 -0
  60. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/assets/__init__.py +0 -0
  61. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/builtin_config.py +0 -0
  62. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/config.py +0 -0
  63. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/select_model.py +0 -0
  64. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/thinking.py +0 -0
  65. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/__init__.py +0 -0
  66. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/agent.py +0 -0
  67. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/__init__.py +0 -0
  68. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/llm_clients.py +0 -0
  69. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  70. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  71. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompt.py +0 -0
  72. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  73. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  74. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
  75. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
  76. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  77. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  78. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  79. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-image-gen.md +0 -0
  80. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  81. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  82. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/reminders.py +0 -0
  83. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/task.py +0 -0
  84. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/__init__.py +0 -0
  85. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/__init__.py +0 -0
  86. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/_utils.py +0 -0
  87. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  88. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  89. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  90. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  91. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  92. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  93. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/move_tool.md +0 -0
  94. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/move_tool.py +0 -0
  95. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  96. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/read_tool.py +0 -0
  97. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  98. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  99. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  100. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  101. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  102. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  103. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  104. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/__init__.py +0 -0
  105. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
  106. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
  107. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  108. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  109. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  110. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  111. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  112. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  113. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_abc.py +0 -0
  114. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_context.py +0 -0
  115. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_registry.py +0 -0
  116. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_runner.py +0 -0
  117. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/truncation.py +0 -0
  118. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/__init__.py +0 -0
  119. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  120. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  121. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  122. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  123. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  124. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  125. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/turn.py +0 -0
  126. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/__init__.py +0 -0
  127. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  128. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/client.py +0 -0
  129. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/input.py +0 -0
  130. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/bedrock/__init__.py +0 -0
  131. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/bedrock/client.py +0 -0
  132. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/claude/__init__.py +0 -0
  133. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/claude/client.py +0 -0
  134. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/client.py +0 -0
  135. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/codex/__init__.py +0 -0
  136. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/codex/client.py +0 -0
  137. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/__init__.py +0 -0
  138. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/client.py +0 -0
  139. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/input.py +0 -0
  140. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/image.py +0 -0
  141. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/input_common.py +0 -0
  142. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  143. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/client.py +0 -0
  144. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  145. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
  146. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  147. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  148. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/client.py +0 -0
  149. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/input.py +0 -0
  150. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
  151. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/registry.py +0 -0
  152. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/__init__.py +0 -0
  153. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/client.py +0 -0
  154. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/input.py +0 -0
  155. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/usage.py +0 -0
  156. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/__init__.py +0 -0
  157. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/commands.py +0 -0
  158. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/events.py +0 -0
  159. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/llm_param.py +0 -0
  160. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/message.py +0 -0
  161. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  162. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  163. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/image_gen.py +0 -0
  164. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  165. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  166. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/tools.py +0 -0
  167. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/__init__.py +0 -0
  168. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/codec.py +0 -0
  169. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/export.py +0 -0
  170. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/selector.py +0 -0
  171. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/session.py +0 -0
  172. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/store.py +0 -0
  173. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/templates/export_session.html +0 -0
  174. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
  175. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/__init__.py +0 -0
  176. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  177. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
  178. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
  179. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
  180. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  181. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/loader.py +0 -0
  182. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/manager.py +0 -0
  183. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/system_skills.py +0 -0
  184. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/trace/__init__.py +0 -0
  185. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/trace/log.py +0 -0
  186. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/__init__.py +0 -0
  187. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/__init__.py +0 -0
  188. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/display.py +0 -0
  189. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/input.py +0 -0
  190. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/stage_manager.py +0 -0
  191. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/__init__.py +0 -0
  192. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
  193. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/debug/display.py +0 -0
  194. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
  195. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/exec/display.py +0 -0
  196. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
  197. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
  198. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/completers.py +0 -0
  199. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/display.py +0 -0
  200. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +0 -0
  201. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/renderer.py +0 -0
  202. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/__init__.py +0 -0
  203. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/assistant.py +0 -0
  204. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/developer.py +0 -0
  205. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/diffs.py +0 -0
  206. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/errors.py +0 -0
  207. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/mermaid_viewer.py +0 -0
  208. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/metadata.py +0 -0
  209. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
  210. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/thinking.py +0 -0
  211. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/user_input.py +0 -0
  212. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/__init__.py +0 -0
  213. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
  214. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/code_panel.py +0 -0
  215. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/live.py +0 -0
  216. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/markdown.py +0 -0
  217. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/quote.py +0 -0
  218. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/searchable_text.py +0 -0
  219. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/status.py +0 -0
  220. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/__init__.py +0 -0
  221. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/color.py +0 -0
  222. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/control.py +0 -0
  223. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/image.py +0 -0
  224. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/notifier.py +0 -0
  225. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
  226. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/selector.py +0 -0
  227. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/utils/__init__.py +0 -0
  228. {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/utils/common.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "2.0.0"
7
+ version = "2.0.1"
8
8
  description = "Minimal code agent CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -179,7 +179,7 @@ def render_cost_table(daily_stats: dict[str, DailyStats]) -> Table:
179
179
  show_header=True,
180
180
  header_style="bold",
181
181
  border_style="bright_black dim",
182
- padding=(0, 1, 0, 2),
182
+ padding=(0, 1, 0, 1),
183
183
  box=ASCII_HORIZONAL,
184
184
  )
185
185
 
@@ -347,6 +347,10 @@ provider_list:
347
347
  reasoning_effort: medium
348
348
  context_limit: 400000
349
349
  max_tokens: 128000
350
+ cost:
351
+ input: 1.75
352
+ output: 14.0
353
+ cache_read: 0.17
350
354
 
351
355
  sub_agent_models:
352
356
  ImageGen: nano-banana-pro@or
@@ -122,13 +122,14 @@ TOOL_OUTPUT_TRUNCATION_DIR = "/tmp/klaude" # Directory for saving full truncate
122
122
  TAB_EXPAND_WIDTH = 8 # Tab expansion width for text rendering
123
123
  DIFF_PREFIX_WIDTH = 4 # Width of line number prefix in diff display
124
124
  MAX_DIFF_LINES = 500 # Maximum lines to show in diff output
125
- INVALID_TOOL_CALL_MAX_LENGTH = 500 # Maximum length for invalid tool call display
126
- TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 1000 # Maximum line length for truncated display
127
- TRUNCATE_DISPLAY_MAX_LINES = 6 # Maximum lines for truncated display
125
+ INVALID_TOOL_CALL_MAX_LENGTH = 200 # Maximum length for invalid tool call display
126
+ TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 200 # Maximum line length for truncated display
127
+ TRUNCATE_DISPLAY_MAX_LINES = 4 # Maximum lines for truncated display
128
128
  MIN_HIDDEN_LINES_FOR_INDICATOR = 5 # Minimum hidden lines before showing truncation indicator
129
129
  SUB_AGENT_RESULT_MAX_LINES = 10 # Maximum lines for sub-agent result display
130
130
  TRUNCATE_HEAD_MAX_LINES = 2 # Maximum lines for sub-agent error display
131
131
  BASH_OUTPUT_PANEL_THRESHOLD = 10 # Bash output line threshold for CodePanel display
132
+ BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES = 2 # Max lines shown for heredoc / multiline string tokens in bash tool calls
132
133
  URL_TRUNCATE_MAX_LENGTH = 400 # Maximum length for URL truncation in display
133
134
  QUERY_DISPLAY_TRUNCATE_LENGTH = 80 # Maximum length for search query display
134
135
  NOTIFY_COMPACT_LIMIT = 160 # Maximum length for notification body text
@@ -176,35 +176,6 @@ class ExecutorContext:
176
176
  """Initialize an agent for a session and replay history to UI."""
177
177
  await self._ensure_agent(operation.session_id)
178
178
 
179
- async def handle_user_input(self, operation: op.UserInputOperation) -> None:
180
- """Handle a user input operation.
181
-
182
- Core should not parse slash commands. The UI/CLI layer is responsible for
183
- turning raw user input into one or more operations.
184
- """
185
-
186
- if operation.session_id is None:
187
- raise ValueError("session_id cannot be None")
188
-
189
- session_id = operation.session_id
190
- agent = await self._ensure_agent(session_id)
191
- user_input = operation.input
192
-
193
- await self.emit_event(
194
- events.UserMessageEvent(content=user_input.text, session_id=session_id, images=user_input.images)
195
- )
196
- agent.session.append_history(
197
- [message.UserMessage(parts=message.parts_from_text_and_images(user_input.text, user_input.images))]
198
- )
199
-
200
- await self.handle_run_agent(
201
- op.RunAgentOperation(
202
- id=operation.id,
203
- session_id=session_id,
204
- input=user_input,
205
- )
206
- )
207
-
208
179
  async def handle_run_agent(self, operation: op.RunAgentOperation) -> None:
209
180
  agent = await self._ensure_agent(operation.session_id)
210
181
  existing_active = self.task_manager.get(operation.id)
@@ -63,9 +63,8 @@ class TodoWriteTool(ToolABC):
63
63
  "type": "string",
64
64
  "enum": ["pending", "in_progress", "completed"],
65
65
  },
66
- "activeForm": {"type": "string", "minLength": 1},
67
66
  },
68
- "required": ["content", "status", "activeForm"],
67
+ "required": ["content", "status"],
69
68
  "additionalProperties": False,
70
69
  },
71
70
  "description": "The updated todo list",
@@ -2,7 +2,7 @@ from datetime import datetime
2
2
  from enum import Enum
3
3
  from typing import Annotated, Any, Literal
4
4
 
5
- from pydantic import BaseModel, ConfigDict, Field, computed_field
5
+ from pydantic import BaseModel, Field, computed_field
6
6
 
7
7
  from klaude_code.const import DEFAULT_MAX_TOKENS
8
8
  from klaude_code.protocol.commands import CommandName
@@ -150,11 +150,8 @@ class TaskMetadataItem(BaseModel):
150
150
 
151
151
 
152
152
  class TodoItem(BaseModel):
153
- model_config = ConfigDict(populate_by_name=True)
154
-
155
153
  content: str
156
154
  status: TodoStatusType
157
- active_form: str = Field(default="", alias="activeForm")
158
155
 
159
156
 
160
157
  class FileStatus(BaseModel):
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
23
23
  class OperationType(Enum):
24
24
  """Enumeration of supported operation types."""
25
25
 
26
- USER_INPUT = "user_input"
27
26
  RUN_AGENT = "run_agent"
28
27
  CHANGE_MODEL = "change_model"
29
28
  CHANGE_THINKING = "change_thinking"
@@ -46,18 +45,6 @@ class Operation(BaseModel):
46
45
  raise NotImplementedError("Subclasses must implement execute()")
47
46
 
48
47
 
49
- class UserInputOperation(Operation):
50
- """Operation for handling user input (text and optional images) that should be processed by an agent."""
51
-
52
- type: OperationType = OperationType.USER_INPUT
53
- input: UserInputPayload
54
- session_id: str | None = None
55
-
56
- async def execute(self, handler: OperationHandler) -> None:
57
- """Execute user input by running it through an agent."""
58
- await handler.handle_user_input(self)
59
-
60
-
61
48
  class RunAgentOperation(Operation):
62
49
  """Operation for launching an agent task for a given session."""
63
50
 
@@ -18,17 +18,12 @@ if TYPE_CHECKING:
18
18
  InterruptOperation,
19
19
  ResumeSessionOperation,
20
20
  RunAgentOperation,
21
- UserInputOperation,
22
21
  )
23
22
 
24
23
 
25
24
  class OperationHandler(Protocol):
26
25
  """Protocol defining the interface for handling operations."""
27
26
 
28
- async def handle_user_input(self, operation: UserInputOperation) -> None:
29
- """Handle a user input operation."""
30
- ...
31
-
32
27
  async def handle_run_agent(self, operation: RunAgentOperation) -> None:
33
28
  """Handle a run agent operation."""
34
29
  ...
@@ -624,11 +624,8 @@ class DisplayEventHandler:
624
624
  def _extract_active_form_text(self, todo_event: events.TodoChangeEvent) -> str | None:
625
625
  status_text: str | None = None
626
626
  for todo in todo_event.todos:
627
- if todo.status == "in_progress":
628
- if len(todo.active_form) > 0:
629
- status_text = todo.active_form
630
- if len(todo.content) > 0:
631
- status_text = todo.content
627
+ if todo.status == "in_progress" and len(todo.content) > 0:
628
+ status_text = todo.content
632
629
 
633
630
  if status_text is None:
634
631
  return None
@@ -11,8 +11,9 @@ import re
11
11
  from collections.abc import Callable
12
12
  from typing import cast
13
13
 
14
+ from prompt_toolkit.application.current import get_app
14
15
  from prompt_toolkit.buffer import Buffer
15
- from prompt_toolkit.filters import Always, Filter
16
+ from prompt_toolkit.filters import Always, Condition, Filter
16
17
  from prompt_toolkit.filters.app import has_completions
17
18
  from prompt_toolkit.key_binding import KeyBindings
18
19
  from prompt_toolkit.key_binding.key_processor import KeyPressEvent
@@ -40,6 +41,119 @@ def create_key_bindings(
40
41
  kb = KeyBindings()
41
42
  enabled = input_enabled if input_enabled is not None else Always()
42
43
 
44
+ def _can_move_cursor_visually_within_wrapped_line(delta_visible_y: int) -> bool:
45
+ """Return True when Up/Down should move within a wrapped visual line.
46
+
47
+ prompt_toolkit's default Up/Down behavior operates on logical lines
48
+ (split by '\n'). When a single logical line wraps across terminal
49
+ rows, pressing Up/Down should move within those wrapped rows instead of
50
+ triggering history navigation.
51
+
52
+ We only intercept when the cursor can move to an adjacent *visible*
53
+ line that maps to the same input line.
54
+ """
55
+
56
+ try:
57
+ app = get_app()
58
+ window = app.layout.current_window
59
+ ri = window.render_info
60
+ if ri is None:
61
+ return False
62
+
63
+ current_visible_y = int(ri.cursor_position.y)
64
+ target_visible_y = current_visible_y + delta_visible_y
65
+ if target_visible_y < 0:
66
+ return False
67
+
68
+ current_input_line = ri.visible_line_to_input_line.get(current_visible_y)
69
+ target_input_line = ri.visible_line_to_input_line.get(target_visible_y)
70
+ return current_input_line is not None and current_input_line == target_input_line
71
+ except Exception:
72
+ return False
73
+
74
+ def _move_cursor_visually_within_wrapped_line(event: KeyPressEvent, *, delta_visible_y: int) -> None:
75
+ """Move the cursor Up/Down by one wrapped screen row, keeping column."""
76
+
77
+ buf = event.current_buffer
78
+ try:
79
+ window = event.app.layout.current_window
80
+ ri = window.render_info
81
+ if ri is None:
82
+ return
83
+
84
+ rowcol_to_yx = getattr(ri, "_rowcol_to_yx", None)
85
+ x_offset = getattr(ri, "_x_offset", None)
86
+ y_offset = getattr(ri, "_y_offset", None)
87
+ if not isinstance(rowcol_to_yx, dict) or not isinstance(x_offset, int) or not isinstance(y_offset, int):
88
+ return
89
+ rowcol_to_yx_typed = cast(dict[tuple[int, int], tuple[int, int]], rowcol_to_yx)
90
+
91
+ current_visible_y = int(ri.cursor_position.y)
92
+ target_visible_y = current_visible_y + delta_visible_y
93
+ mapping = ri.visible_line_to_row_col
94
+ if current_visible_y not in mapping or target_visible_y not in mapping:
95
+ return
96
+
97
+ current_row, _ = mapping[current_visible_y]
98
+ target_row, _ = mapping[target_visible_y]
99
+
100
+ # Only handle wrapped rows within the same input line.
101
+ if current_row != target_row:
102
+ return
103
+
104
+ current_abs_y = y_offset + current_visible_y
105
+ target_abs_y = y_offset + target_visible_y
106
+ cursor_abs_x = x_offset + int(ri.cursor_position.x)
107
+
108
+ def _segment_start_abs_x(row: int, abs_y: int) -> int | None:
109
+ xs: list[int] = []
110
+ for (r, _col), (y, x) in rowcol_to_yx_typed.items():
111
+ if r == row and y == abs_y:
112
+ xs.append(x)
113
+ return min(xs) if xs else None
114
+
115
+ current_start_x = _segment_start_abs_x(current_row, current_abs_y)
116
+ target_start_x = _segment_start_abs_x(target_row, target_abs_y)
117
+ if current_start_x is None or target_start_x is None:
118
+ return
119
+
120
+ offset_in_segment_cells = max(0, cursor_abs_x - current_start_x)
121
+ desired_abs_x = target_start_x + offset_in_segment_cells
122
+
123
+ candidates: list[tuple[int, int]] = []
124
+ for (r, col), (y, x) in rowcol_to_yx_typed.items():
125
+ if r == target_row and y == target_abs_y:
126
+ candidates.append((col, x))
127
+ if not candidates:
128
+ return
129
+
130
+ # Pick the closest column at/before the desired X. If the desired
131
+ # position is before the first character, snap to the first.
132
+ candidates.sort(key=lambda t: t[1])
133
+ chosen_display_col = candidates[0][0]
134
+ for col, x in candidates:
135
+ if x <= desired_abs_x:
136
+ chosen_display_col = col
137
+ else:
138
+ break
139
+
140
+ control = event.app.layout.current_control
141
+ get_processed_line = getattr(control, "_last_get_processed_line", None)
142
+ target_source_col = chosen_display_col
143
+ if callable(get_processed_line):
144
+ processed_line = get_processed_line(target_row)
145
+ display_to_source = getattr(processed_line, "display_to_source", None)
146
+ if callable(display_to_source):
147
+ display_to_source_fn = cast(Callable[[int], int], display_to_source)
148
+ target_source_col = display_to_source_fn(chosen_display_col)
149
+
150
+ doc = buf.document # type: ignore[reportUnknownMemberType]
151
+ new_index = doc.translate_row_col_to_index(target_row, target_source_col) # type: ignore[reportUnknownMemberType]
152
+ buf.cursor_position = new_index # type: ignore[reportUnknownMemberType]
153
+ event.app.invalidate() # type: ignore[reportUnknownMemberType]
154
+ except Exception:
155
+ return
156
+
43
157
  def _should_submit_instead_of_accepting_completion(buf: Buffer) -> bool:
44
158
  """Return True when Enter should submit even if completions are visible.
45
159
 
@@ -174,6 +288,26 @@ def create_key_bindings(
174
288
  _cycle_completion(buf, delta=-1)
175
289
  event.app.invalidate() # type: ignore[reportUnknownMemberType]
176
290
 
291
+ @kb.add(
292
+ "up",
293
+ filter=enabled
294
+ & ~has_completions
295
+ & Condition(lambda: _can_move_cursor_visually_within_wrapped_line(delta_visible_y=-1)),
296
+ eager=True,
297
+ )
298
+ def _(event: KeyPressEvent) -> None:
299
+ _move_cursor_visually_within_wrapped_line(event, delta_visible_y=-1)
300
+
301
+ @kb.add(
302
+ "down",
303
+ filter=enabled
304
+ & ~has_completions
305
+ & Condition(lambda: _can_move_cursor_visually_within_wrapped_line(delta_visible_y=1)),
306
+ eager=True,
307
+ )
308
+ def _(event: KeyPressEvent) -> None:
309
+ _move_cursor_visually_within_wrapped_line(event, delta_visible_y=1)
310
+
177
311
  @kb.add("c-j", filter=enabled)
178
312
  def _(event: KeyPressEvent) -> None:
179
313
  event.current_buffer.insert_text("\n") # type: ignore
@@ -7,6 +7,8 @@ from pygments.lexers import BashLexer # pyright: ignore[reportUnknownVariableTy
7
7
  from pygments.token import Token
8
8
  from rich.text import Text
9
9
 
10
+ from klaude_code.const import BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES
11
+ from klaude_code.ui.renderers.common import truncate_head
10
12
  from klaude_code.ui.rich.theme import ThemeKey
11
13
 
12
14
  # Token types for bash syntax highlighting
@@ -110,13 +112,34 @@ def _append_heredoc(result: Text, token_value: str) -> None:
110
112
  # Extra content on first line (e.g., "> file.py")
111
113
  if extra:
112
114
  result.append(extra, style=ThemeKey.BASH_ARGUMENT)
113
- # Body content
114
- result.append(body, style=ThemeKey.BASH_STRING)
115
+
116
+ # Body content (truncate to keep tool call rendering compact)
117
+ body_inner = body.strip("\n")
118
+ result.append("\n")
119
+ if body_inner:
120
+ body_text = truncate_head(
121
+ body_inner,
122
+ max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
123
+ base_style=ThemeKey.BASH_STRING,
124
+ truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
125
+ )
126
+ result.append_text(body_text)
127
+ result.append("\n")
128
+
115
129
  # End delimiter
116
130
  result.append(end_delimiter, style=ThemeKey.BASH_HEREDOC_DELIMITER)
117
131
  else:
118
132
  # Fallback: couldn't parse heredoc structure
119
- result.append(token_value, style=ThemeKey.BASH_STRING)
133
+ if "\n" in token_value and len(token_value.splitlines()) > BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES:
134
+ truncated = truncate_head(
135
+ token_value,
136
+ max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
137
+ base_style=ThemeKey.BASH_STRING,
138
+ truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
139
+ )
140
+ result.append_text(truncated)
141
+ else:
142
+ result.append(token_value, style=ThemeKey.BASH_STRING)
120
143
 
121
144
 
122
145
  def highlight_bash_command(command: str) -> Text:
@@ -145,7 +168,16 @@ def highlight_bash_command(command: str) -> Text:
145
168
  if token_value.startswith("<<"):
146
169
  _append_heredoc(result, token_value)
147
170
  else:
148
- result.append(token_value, style=ThemeKey.BASH_STRING)
171
+ if "\n" in token_value and len(token_value.splitlines()) > BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES:
172
+ truncated = truncate_head(
173
+ token_value,
174
+ max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
175
+ base_style=ThemeKey.BASH_STRING,
176
+ truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
177
+ )
178
+ result.append_text(truncated)
179
+ else:
180
+ result.append(token_value, style=ThemeKey.BASH_STRING)
149
181
  expect_subcommand = False
150
182
  elif token_type in _OPERATOR_TOKENS:
151
183
  result.append(token_value, style=ThemeKey.BASH_OPERATOR)
@@ -1,3 +1,5 @@
1
+ from typing import Literal
2
+
1
3
  from rich.style import Style
2
4
  from rich.table import Table
3
5
  from rich.text import Text
@@ -12,10 +14,10 @@ from klaude_code.const import (
12
14
  from klaude_code.ui.rich.theme import ThemeKey
13
15
 
14
16
 
15
- def create_grid() -> Table:
17
+ def create_grid(*, overflow: Literal["fold", "crop", "ellipsis", "ignore"] = "fold") -> Table:
16
18
  grid = Table.grid(padding=(0, 1))
17
19
  grid.add_column(no_wrap=True)
18
- grid.add_column(overflow="fold")
20
+ grid.add_column(overflow=overflow)
19
21
  return grid
20
22
 
21
23
 
@@ -36,7 +38,7 @@ def truncate_middle(
36
38
  if max_lines <= 0:
37
39
  truncated_lines = text.split("\n")
38
40
  remaining = max(0, len(truncated_lines))
39
- return Text(f"… (more {remaining} lines)", style=ThemeKey.TOOL_RESULT_TRUNCATED)
41
+ return Text(f" … (more {remaining} lines)", style=ThemeKey.TOOL_RESULT_TRUNCATED)
40
42
 
41
43
  lines = text.split("\n")
42
44
  truncated_lines = 0
@@ -65,7 +67,7 @@ def truncate_middle(
65
67
  out.append(line[:max_line_length])
66
68
  out.append_text(
67
69
  Text(
68
- f"… (more {extra_chars} characters in this line)",
70
+ f" … (more {extra_chars} characters in this line)",
69
71
  style=ThemeKey.TOOL_RESULT_TRUNCATED,
70
72
  )
71
73
  )
@@ -82,7 +84,7 @@ def truncate_middle(
82
84
  out.append("\n")
83
85
 
84
86
  if truncated_lines > 0:
85
- out.append_text(Text(f" (more {truncated_lines} lines)\n", style=ThemeKey.TOOL_RESULT_TRUNCATED))
87
+ out.append_text(Text(f" (more {truncated_lines} lines)\n", style=ThemeKey.TOOL_RESULT_TRUNCATED))
86
88
 
87
89
  for idx, line in enumerate(tail_lines):
88
90
  append_line(out, line)
@@ -139,6 +141,6 @@ def truncate_head(
139
141
  out.append("\n")
140
142
 
141
143
  remaining = len(lines) - max_lines
142
- out.append_text(Text(f"… more {remaining} lines", style=truncated_style or ThemeKey.TOOL_RESULT_TRUNCATED))
144
+ out.append_text(Text(f" (more {remaining} lines)", style=truncated_style or ThemeKey.TOOL_RESULT_TRUNCATED))
143
145
 
144
146
  return out
@@ -68,9 +68,7 @@ def _render_tool_call_tree(
68
68
  tool_name: str,
69
69
  details: RenderableType | None,
70
70
  ) -> RenderableType:
71
- # Keep the original 2-column layout (tool name on the left, details on the right),
72
- # but move the tool mark into the tree prefix so it can connect to the tool result.
73
- grid = create_grid()
71
+ grid = create_grid(overflow="ellipsis")
74
72
  grid.add_row(
75
73
  Text(tool_name, style=ThemeKey.TOOL_NAME),
76
74
  details if details is not None else Text(""),
@@ -138,15 +136,13 @@ def render_bash_tool_call(arguments: str) -> RenderableType:
138
136
  command = payload.get("command")
139
137
  timeout_ms = payload.get("timeout_ms")
140
138
 
141
- # Build the command display with optional timeout suffix
142
139
  if isinstance(command, str) and command.strip():
143
140
  cmd_str = command.strip()
144
- line_count = len(cmd_str.splitlines())
145
-
146
141
  highlighted = highlight_bash_command(cmd_str)
147
142
 
148
- # For commands > threshold lines, use CodePanel for better display
149
- if line_count > BASH_OUTPUT_PANEL_THRESHOLD:
143
+ display_line_count = len(highlighted.plain.splitlines())
144
+
145
+ if display_line_count > BASH_OUTPUT_PANEL_THRESHOLD:
150
146
  code_panel = CodePanel(highlighted, border_style=ThemeKey.LINES)
151
147
  if isinstance(timeout_ms, int):
152
148
  if timeout_ms >= 1000 and timeout_ms % 1000 == 0:
@@ -298,7 +294,6 @@ def render_move_tool_call(arguments: str) -> RenderableType:
298
294
  start_line = payload.get("start_line", "")
299
295
  end_line = payload.get("end_line", "")
300
296
 
301
- # Build display: source:start-end -> target
302
297
  parts = Text()
303
298
  if source_path:
304
299
  parts.append_text(render_path(source_path, ThemeKey.TOOL_PARAM_FILE_PATH))
@@ -386,15 +381,17 @@ def render_todo(tr: events.ToolResultEvent) -> RenderableType:
386
381
  def render_generic_tool_result(result: str, *, is_error: bool = False) -> RenderableType:
387
382
  """Render a generic tool result as truncated text."""
388
383
  style = ThemeKey.ERROR if is_error else ThemeKey.TOOL_RESULT
389
- return truncate_middle(result, base_style=style)
384
+ text = truncate_middle(result, base_style=style)
385
+ # Tool results should not reflow/wrap; use ellipsis when exceeding terminal width.
386
+ text.no_wrap = True
387
+ text.overflow = "ellipsis"
388
+ return text
390
389
 
391
390
 
392
391
  def _extract_mermaid_link(
393
392
  ui_extra: model.ToolResultUIExtra | None,
394
393
  ) -> model.MermaidLinkUIExtra | None:
395
- if isinstance(ui_extra, model.MermaidLinkUIExtra):
396
- return ui_extra
397
- return None
394
+ return ui_extra if isinstance(ui_extra, model.MermaidLinkUIExtra) else None
398
395
 
399
396
 
400
397
  def render_mermaid_tool_call(arguments: str) -> RenderableType:
@@ -443,7 +440,7 @@ def _render_mermaid_viewer_link(
443
440
  ) -> RenderableType:
444
441
  viewer_path = r_mermaid_viewer.build_viewer(code=link_info.code, link=link_info.link, tool_call_id=tr.tool_call_id)
445
442
  if viewer_path is None:
446
- return Text(link_info.link, style=ThemeKey.TOOL_RESULT_MERMAID, overflow="fold")
443
+ return Text(link_info.link, style=ThemeKey.TOOL_RESULT_MERMAID, overflow="ellipsis", no_wrap=True)
447
444
 
448
445
  display_path = str(viewer_path)
449
446
 
@@ -534,9 +531,7 @@ def render_mermaid_tool_result(
534
531
  def _extract_truncation(
535
532
  ui_extra: model.ToolResultUIExtra | None,
536
533
  ) -> model.TruncationUIExtra | None:
537
- if isinstance(ui_extra, model.TruncationUIExtra):
538
- return ui_extra
539
- return None
534
+ return ui_extra if isinstance(ui_extra, model.TruncationUIExtra) else None
540
535
 
541
536
 
542
537
  def render_truncation_info(ui_extra: model.TruncationUIExtra) -> RenderableType:
@@ -548,6 +543,8 @@ def render_truncation_info(ui_extra: model.TruncationUIExtra) -> RenderableType:
548
543
  (ui_extra.saved_file_path, ThemeKey.TOOL_RESULT_TRUNCATED),
549
544
  (f", {truncated_kb:.1f}KB truncated", ThemeKey.TOOL_RESULT_TRUNCATED),
550
545
  )
546
+ text.no_wrap = True
547
+ text.overflow = "ellipsis"
551
548
  return text
552
549
 
553
550
 
@@ -685,7 +682,7 @@ def render_tool_result(
685
682
 
686
683
  # Handle error case
687
684
  if e.status == "error" and e.ui_extra is None:
688
- return wrap(truncate_middle(e.result, base_style=ThemeKey.ERROR))
685
+ return wrap(render_generic_tool_result(e.result, is_error=True))
689
686
 
690
687
  # Render multiple ui blocks if present
691
688
  if isinstance(e.ui_extra, model.MultiUIExtra) and e.ui_extra.items:
@@ -737,8 +734,6 @@ def render_tool_result(
737
734
  case tools.MERMAID:
738
735
  return wrap(render_mermaid_tool_result(e, session_id=session_id))
739
736
  case tools.BASH:
740
- if e.result.startswith("diff --git"):
741
- return wrap(r_diffs.render_diff_panel(e.result, show_file_name=True))
742
737
  return _render_fallback()
743
738
  case _:
744
739
  return _render_fallback()
@@ -60,17 +60,17 @@ LIGHT_PALETTE = Palette(
60
60
  diff_remove="#82071e on #ffecec",
61
61
  diff_remove_char="#82071e on #ffcfcf",
62
62
  code_theme="ansi_light",
63
- code_background="#e0e0e0",
64
- green_background="#e8f1e9",
65
- blue_grey_background="#e8e9f1",
66
- cyan_background="#e0f0f0",
67
- green_sub_background="#e0f0e0",
68
- blue_sub_background="#e0e8f5",
69
- purple_background="#ede0f5",
70
- orange_background="#f5ebe0",
71
- red_background="#f5e0e0",
72
- grey_background="#e8e8e8",
73
- yellow_background="#f5f5e0",
63
+ code_background="#ebebeb",
64
+ green_background="#f0f7f1",
65
+ blue_grey_background="#f0f1f7",
66
+ cyan_background="#ecf7f7",
67
+ green_sub_background="#ecf7ec",
68
+ blue_sub_background="#ecf1f9",
69
+ purple_background="#f5ecf9",
70
+ orange_background="#f9f3ec",
71
+ red_background="#f9ecec",
72
+ grey_background="#f0f0f0",
73
+ yellow_background="#f9f9ec",
74
74
  )
75
75
 
76
76
  DARK_PALETTE = Palette(
@@ -270,11 +270,11 @@ def get_theme(theme: str | None = None) -> Themes:
270
270
  ThemeKey.TOOL_RESULT.value: palette.grey_green,
271
271
  ThemeKey.TOOL_RESULT_TREE_PREFIX.value: palette.grey_green + " dim",
272
272
  ThemeKey.TOOL_RESULT_BOLD.value: "bold " + palette.grey_green,
273
- ThemeKey.TOOL_RESULT_TRUNCATED.value: palette.yellow + " dim",
273
+ ThemeKey.TOOL_RESULT_TRUNCATED.value: palette.grey1,
274
274
  ThemeKey.TOOL_MARK.value: "bold",
275
275
  ThemeKey.TOOL_APPROVED.value: palette.green + " bold reverse",
276
276
  ThemeKey.TOOL_REJECTED.value: palette.red + " bold reverse",
277
- ThemeKey.TOOL_TIMEOUT.value: palette.yellow,
277
+ ThemeKey.TOOL_TIMEOUT.value: palette.grey2,
278
278
  ThemeKey.TOOL_RESULT_MERMAID: palette.blue + " underline",
279
279
  ThemeKey.SUB_AGENT_FOOTER.value: "dim " + palette.grey2,
280
280
  # BASH SYNTAX
File without changes