klaude-code 1.2.12__tar.gz → 1.2.14__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 (189) hide show
  1. {klaude_code-1.2.12 → klaude_code-1.2.14}/PKG-INFO +1 -1
  2. {klaude_code-1.2.12 → klaude_code-1.2.14}/pyproject.toml +9 -2
  3. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/codex/oauth.py +3 -3
  4. klaude_code-1.2.14/src/klaude_code/cli/auth_cmd.py +73 -0
  5. klaude_code-1.2.14/src/klaude_code/cli/config_cmd.py +88 -0
  6. klaude_code-1.2.14/src/klaude_code/cli/debug.py +72 -0
  7. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/cli/main.py +31 -142
  8. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/cli/runtime.py +19 -58
  9. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/cli/session_cmd.py +9 -9
  10. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/export_cmd.py +3 -3
  11. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/model_cmd.py +1 -1
  12. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/registry.py +1 -1
  13. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/terminal_setup_cmd.py +2 -2
  14. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/thinking_cmd.py +8 -6
  15. klaude_code-1.2.14/src/klaude_code/config/__init__.py +7 -0
  16. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/config/config.py +31 -4
  17. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/config/list_model.py +1 -1
  18. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/const/__init__.py +8 -3
  19. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/agent.py +14 -62
  20. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/executor.py +11 -10
  21. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/manager/agent_manager.py +4 -4
  22. klaude_code-1.2.14/src/klaude_code/core/manager/llm_clients.py +28 -0
  23. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/manager/llm_clients_builder.py +8 -21
  24. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/manager/sub_agent_manager.py +3 -3
  25. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompt.py +12 -7
  26. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/reminders.py +1 -1
  27. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/task.py +2 -2
  28. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/__init__.py +16 -25
  29. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/_utils.py +1 -1
  30. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/apply_patch.py +17 -25
  31. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/apply_patch_tool.py +4 -7
  32. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/edit_tool.py +4 -11
  33. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/multi_edit_tool.py +2 -3
  34. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/read_tool.py +3 -4
  35. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/write_tool.py +2 -3
  36. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/memory_tool.py +2 -8
  37. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/skill_loader.py +3 -2
  38. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/shell/command_safety.py +0 -1
  39. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/tool_context.py +1 -3
  40. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/tool_registry.py +2 -1
  41. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/tool_runner.py +1 -1
  42. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/truncation.py +2 -5
  43. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/turn.py +9 -3
  44. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/anthropic/client.py +6 -2
  45. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/client.py +5 -1
  46. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/codex/client.py +2 -2
  47. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/input_common.py +2 -2
  48. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openai_compatible/client.py +11 -8
  49. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openai_compatible/stream_processor.py +2 -1
  50. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openrouter/client.py +22 -9
  51. klaude_code-1.2.14/src/klaude_code/llm/openrouter/reasoning_handler.py +96 -0
  52. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/registry.py +6 -5
  53. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/responses/client.py +10 -5
  54. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/events.py +9 -2
  55. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/model.py +7 -1
  56. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/sub_agent.py +2 -2
  57. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/session/export.py +58 -0
  58. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/session/selector.py +2 -2
  59. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/session/session.py +37 -7
  60. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/session/templates/export_session.html +46 -0
  61. klaude_code-1.2.14/src/klaude_code/trace/__init__.py +3 -0
  62. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/trace/log.py +144 -5
  63. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/__init__.py +4 -9
  64. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/core/stage_manager.py +7 -4
  65. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/debug/display.py +2 -1
  66. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/__init__.py +1 -1
  67. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/completers.py +6 -7
  68. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/display.py +3 -4
  69. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/event_handler.py +63 -5
  70. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/key_bindings.py +2 -3
  71. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/renderer.py +52 -62
  72. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/diffs.py +1 -4
  73. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/tools.py +4 -0
  74. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/markdown.py +3 -3
  75. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/searchable_text.py +6 -6
  76. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/status.py +3 -4
  77. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/theme.py +2 -5
  78. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/terminal/control.py +7 -16
  79. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/terminal/notifier.py +2 -4
  80. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/utils/common.py +1 -1
  81. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/utils/debouncer.py +2 -2
  82. klaude_code-1.2.12/src/klaude_code/config/__init__.py +0 -11
  83. klaude_code-1.2.12/src/klaude_code/core/manager/llm_clients.py +0 -67
  84. klaude_code-1.2.12/src/klaude_code/llm/openrouter/reasoning_handler.py +0 -209
  85. klaude_code-1.2.12/src/klaude_code/trace/__init__.py +0 -3
  86. {klaude_code-1.2.12 → klaude_code-1.2.14}/README.md +0 -0
  87. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/__init__.py +0 -0
  88. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/__init__.py +0 -0
  89. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/codex/__init__.py +0 -0
  90. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/codex/exceptions.py +0 -0
  91. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  92. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/auth/codex/token_manager.py +0 -0
  93. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/cli/__init__.py +0 -0
  94. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/__init__.py +6 -6
  95. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/clear_cmd.py +0 -0
  96. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/command_abc.py +0 -0
  97. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/diff_cmd.py +0 -0
  98. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/help_cmd.py +0 -0
  99. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/prompt-deslop.md +0 -0
  100. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/prompt-dev-docs-update.md +0 -0
  101. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/prompt-dev-docs.md +0 -0
  102. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/prompt-init.md +0 -0
  103. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/prompt_command.py +0 -0
  104. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/refresh_cmd.py +0 -0
  105. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/release_notes_cmd.py +0 -0
  106. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/command/status_cmd.py +0 -0
  107. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/config/select_model.py +0 -0
  108. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/__init__.py +0 -0
  109. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/manager/__init__.py +0 -0
  110. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  111. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  112. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1.md +0 -0
  113. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  114. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  115. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-subagent-explore.md +0 -0
  116. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-subagent-oracle.md +0 -0
  117. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -0
  118. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/prompts/prompt-subagent.md +0 -0
  119. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/__init__.py +0 -0
  120. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  121. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  122. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/multi_edit_tool.md +0 -0
  123. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  124. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  125. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/__init__.py +0 -0
  126. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/memory_tool.md +0 -0
  127. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/skill_tool.md +0 -0
  128. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/memory/skill_tool.py +0 -0
  129. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  130. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  131. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  132. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  133. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  134. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  135. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  136. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  137. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  138. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  139. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/tool_abc.py +0 -0
  140. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/web/__init__.py +0 -0
  141. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  142. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  143. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  144. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  145. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/__init__.py +0 -0
  146. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  147. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/anthropic/input.py +0 -0
  148. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/codex/__init__.py +0 -0
  149. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  150. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  151. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  152. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  153. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/openrouter/input.py +0 -0
  154. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/responses/__init__.py +0 -0
  155. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/responses/input.py +0 -0
  156. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/llm/usage.py +0 -0
  157. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/__init__.py +0 -0
  158. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/commands.py +0 -0
  159. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/llm_param.py +0 -0
  160. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/op.py +0 -0
  161. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/op_handler.py +0 -0
  162. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/protocol/tools.py +0 -0
  163. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/session/__init__.py +0 -0
  164. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/core/__init__.py +0 -0
  165. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/core/display.py +0 -0
  166. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/core/input.py +0 -0
  167. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/__init__.py +0 -0
  168. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
  169. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
  170. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/exec/display.py +0 -0
  171. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
  172. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +0 -0
  173. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/__init__.py +0 -0
  174. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/assistant.py +0 -0
  175. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/common.py +0 -0
  176. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/developer.py +0 -0
  177. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/errors.py +0 -0
  178. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/metadata.py +0 -0
  179. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
  180. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/thinking.py +0 -0
  181. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/renderers/user_input.py +0 -0
  182. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/__init__.py +0 -0
  183. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/live.py +0 -0
  184. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/rich/quote.py +0 -0
  185. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/terminal/__init__.py +0 -0
  186. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/terminal/color.py +0 -0
  187. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
  188. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/ui/utils/__init__.py +0 -0
  189. {klaude_code-1.2.12 → klaude_code-1.2.14}/src/klaude_code/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.12
3
+ Version: 1.2.14
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: openai>=1.102.0
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "1.2.12"
7
+ version = "1.2.14"
8
8
  description = "Add your description here"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -30,7 +30,6 @@ module-name = "klaude_code"
30
30
  [dependency-groups]
31
31
  dev = [
32
32
  "import-linter>=2.6",
33
- "isort>=6.0.1",
34
33
  "pyright>=1.1.407",
35
34
  "pytest>=8.4.1",
36
35
  "pytest-cov>=7.0.0",
@@ -45,6 +44,14 @@ markers = [
45
44
 
46
45
  [tool.ruff]
47
46
  line-length = 120
47
+ src = ["src"]
48
+
49
+ [tool.ruff.lint]
50
+ select = ["E", "F", "B", "I", "UP", "SIM", "RUF"]
51
+ ignore = ["RUF001", "RUF002", "RUF003", "E501"]
52
+
53
+ [tool.ruff.lint.isort]
54
+ known-first-party = ["klaude_code"]
48
55
 
49
56
  [tool.pyright]
50
57
  typeCheckingMode = "strict"
@@ -78,13 +78,13 @@ class OAuthCallbackHandler(BaseHTTPRequestHandler):
78
78
  self.end_headers()
79
79
 
80
80
  if OAuthCallbackHandler.error:
81
- html = """
81
+ html = f"""
82
82
  <html><body style="font-family: sans-serif; text-align: center; padding: 50px;">
83
83
  <h1>Authentication Failed</h1>
84
- <p>Error: {}</p>
84
+ <p>Error: {OAuthCallbackHandler.error}</p>
85
85
  <p>Please close this window and try again.</p>
86
86
  </body></html>
87
- """.format(OAuthCallbackHandler.error)
87
+ """
88
88
  else:
89
89
  html = """
90
90
  <html><body style="font-family: sans-serif; text-align: center; padding: 50px;">
@@ -0,0 +1,73 @@
1
+ """Authentication commands for CLI."""
2
+
3
+ import datetime
4
+
5
+ import typer
6
+
7
+ from klaude_code.trace import log
8
+
9
+
10
+ def login_command(
11
+ provider: str = typer.Argument("codex", help="Provider to login (codex)"),
12
+ ) -> None:
13
+ """Login to a provider using OAuth."""
14
+ if provider.lower() != "codex":
15
+ log((f"Error: Unknown provider '{provider}'. Currently only 'codex' is supported.", "red"))
16
+ raise typer.Exit(1)
17
+
18
+ from klaude_code.auth.codex.oauth import CodexOAuth
19
+ from klaude_code.auth.codex.token_manager import CodexTokenManager
20
+
21
+ token_manager = CodexTokenManager()
22
+
23
+ # Check if already logged in
24
+ if token_manager.is_logged_in():
25
+ state = token_manager.get_state()
26
+ if state and not state.is_expired():
27
+ log(("You are already logged in to Codex.", "green"))
28
+ log(f" Account ID: {state.account_id[:8]}...")
29
+ expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
30
+ log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
31
+ if not typer.confirm("Do you want to re-login?"):
32
+ return
33
+
34
+ log("Starting Codex OAuth login flow...")
35
+ log("A browser window will open for authentication.")
36
+
37
+ try:
38
+ oauth = CodexOAuth(token_manager)
39
+ state = oauth.login()
40
+ log(("Login successful!", "green"))
41
+ log(f" Account ID: {state.account_id[:8]}...")
42
+ expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
43
+ log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
44
+ except Exception as e:
45
+ log((f"Login failed: {e}", "red"))
46
+ raise typer.Exit(1) from None
47
+
48
+
49
+ def logout_command(
50
+ provider: str = typer.Argument("codex", help="Provider to logout (codex)"),
51
+ ) -> None:
52
+ """Logout from a provider."""
53
+ if provider.lower() != "codex":
54
+ log((f"Error: Unknown provider '{provider}'. Currently only 'codex' is supported.", "red"))
55
+ raise typer.Exit(1)
56
+
57
+ from klaude_code.auth.codex.token_manager import CodexTokenManager
58
+
59
+ token_manager = CodexTokenManager()
60
+
61
+ if not token_manager.is_logged_in():
62
+ log("You are not logged in to Codex.")
63
+ return
64
+
65
+ if typer.confirm("Are you sure you want to logout from Codex?"):
66
+ token_manager.delete()
67
+ log(("Logged out from Codex.", "green"))
68
+
69
+
70
+ def register_auth_commands(app: typer.Typer) -> None:
71
+ """Register auth commands to the given Typer app."""
72
+ app.command("login")(login_command)
73
+ app.command("logout")(logout_command)
@@ -0,0 +1,88 @@
1
+ """Configuration commands for CLI."""
2
+
3
+ import os
4
+ import subprocess
5
+ import sys
6
+
7
+ import typer
8
+
9
+ from klaude_code.config import config_path, load_config
10
+ from klaude_code.trace import log
11
+
12
+
13
+ def list_models() -> None:
14
+ """List all models and providers configuration"""
15
+ from klaude_code.config.list_model import display_models_and_providers
16
+ from klaude_code.ui.terminal.color import is_light_terminal_background
17
+
18
+ config = load_config()
19
+ if config is None:
20
+ raise typer.Exit(1)
21
+
22
+ # Auto-detect theme when not explicitly set in config, to match other CLI entrypoints.
23
+ if config.theme is None:
24
+ detected = is_light_terminal_background()
25
+ if detected is True:
26
+ config.theme = "light"
27
+ elif detected is False:
28
+ config.theme = "dark"
29
+
30
+ display_models_and_providers(config)
31
+
32
+
33
+ def edit_config() -> None:
34
+ """Open the configuration file in $EDITOR or default system editor"""
35
+ editor = os.environ.get("EDITOR")
36
+
37
+ # If no EDITOR is set, prioritize TextEdit on macOS
38
+ if not editor:
39
+ # Try common editors in order of preference on other platforms
40
+ for cmd in [
41
+ "code",
42
+ "nvim",
43
+ "vim",
44
+ "nano",
45
+ ]:
46
+ try:
47
+ subprocess.run(["which", cmd], check=True, capture_output=True)
48
+ editor = cmd
49
+ break
50
+ except (subprocess.CalledProcessError, FileNotFoundError):
51
+ continue
52
+
53
+ # If no editor found, try platform-specific defaults
54
+ if not editor:
55
+ if sys.platform == "darwin": # macOS
56
+ editor = "open"
57
+ elif sys.platform == "win32": # Windows
58
+ editor = "notepad"
59
+ else: # Linux and other Unix systems
60
+ editor = "xdg-open"
61
+
62
+ # Ensure config file exists
63
+ config = load_config()
64
+ if config is None:
65
+ raise typer.Exit(1)
66
+
67
+ try:
68
+ if editor == "open -a TextEdit":
69
+ subprocess.run(["open", "-a", "TextEdit", str(config_path)], check=True)
70
+ elif editor in ["open", "xdg-open"]:
71
+ # For open/xdg-open, we need to pass the file directly
72
+ subprocess.run([editor, str(config_path)], check=True)
73
+ else:
74
+ subprocess.run([editor, str(config_path)], check=True)
75
+ except subprocess.CalledProcessError as e:
76
+ log((f"Error: Failed to open editor: {e}", "red"))
77
+ raise typer.Exit(1) from None
78
+ except FileNotFoundError:
79
+ log((f"Error: Editor '{editor}' not found", "red"))
80
+ log("Please install a text editor or set your $EDITOR environment variable")
81
+ raise typer.Exit(1) from None
82
+
83
+
84
+ def register_config_commands(app: typer.Typer) -> None:
85
+ """Register config commands to the given Typer app."""
86
+ app.command("list")(list_models)
87
+ app.command("config")(edit_config)
88
+ app.command("conf", hidden=True)(edit_config)
@@ -0,0 +1,72 @@
1
+ """Debug utilities for CLI."""
2
+
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import typer
9
+
10
+ from klaude_code.trace import DebugType, log
11
+
12
+ DEBUG_FILTER_HELP = "Comma-separated debug types: " + ", ".join(dt.value for dt in DebugType)
13
+
14
+
15
+ def parse_debug_filters(raw: str | None) -> set[DebugType] | None:
16
+ """Parse comma-separated debug filter string into a set of DebugType."""
17
+ if raw is None:
18
+ return None
19
+ filters: set[DebugType] = set()
20
+ for chunk in raw.split(","):
21
+ normalized = chunk.strip().lower().replace("-", "_")
22
+ if not normalized:
23
+ continue
24
+ try:
25
+ filters.add(DebugType(normalized))
26
+ except ValueError: # pragma: no cover - user input validation
27
+ valid_options = ", ".join(dt.value for dt in DebugType)
28
+ log(
29
+ (
30
+ f"Invalid debug filter '{normalized}'. Valid options: {valid_options}",
31
+ "red",
32
+ )
33
+ )
34
+ raise typer.Exit(2) from None
35
+ return filters or None
36
+
37
+
38
+ def resolve_debug_settings(flag: bool, raw_filters: str | None) -> tuple[bool, set[DebugType] | None]:
39
+ """Resolve debug flag and filters into effective settings."""
40
+ filters = parse_debug_filters(raw_filters)
41
+ effective_flag = flag or (filters is not None)
42
+ return effective_flag, filters
43
+
44
+
45
+ def open_log_file_in_editor(path: Path) -> None:
46
+ """Open the given log file in a text editor without blocking the CLI."""
47
+
48
+ editor = os.environ.get("EDITOR")
49
+
50
+ if not editor:
51
+ for cmd in ["open", "xdg-open", "code", "nvim", "vim", "nano"]:
52
+ try:
53
+ subprocess.run(["which", cmd], check=True, capture_output=True)
54
+ editor = cmd
55
+ break
56
+ except (subprocess.CalledProcessError, FileNotFoundError):
57
+ continue
58
+
59
+ if not editor:
60
+ if sys.platform == "darwin":
61
+ editor = "open"
62
+ elif sys.platform == "win32":
63
+ editor = "notepad"
64
+ else:
65
+ editor = "xdg-open"
66
+
67
+ try:
68
+ subprocess.Popen([editor, str(path)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
69
+ except FileNotFoundError:
70
+ log((f"Error: Editor '{editor}' not found", "red"))
71
+ except Exception as exc: # pragma: no cover - best effort
72
+ log((f"Warning: failed to open log file in editor: {exc}", "yellow"))
@@ -1,19 +1,19 @@
1
1
  import asyncio
2
- import datetime
3
2
  import os
4
- import subprocess
5
3
  import sys
6
4
  from importlib.metadata import PackageNotFoundError
7
5
  from importlib.metadata import version as pkg_version
6
+ from pathlib import Path
8
7
 
9
8
  import typer
10
9
 
11
- from klaude_code.cli.runtime import DEBUG_FILTER_HELP, AppInitConfig, resolve_debug_settings, run_exec, run_interactive
10
+ from klaude_code.cli.auth_cmd import register_auth_commands
11
+ from klaude_code.cli.config_cmd import register_config_commands
12
+ from klaude_code.cli.debug import DEBUG_FILTER_HELP, open_log_file_in_editor, resolve_debug_settings
12
13
  from klaude_code.cli.session_cmd import register_session_commands
13
- from klaude_code.config import config_path, display_models_and_providers, load_config, select_model_from_config
14
+ from klaude_code.config import load_config
14
15
  from klaude_code.session import Session, resume_select_session
15
- from klaude_code.trace import log
16
- from klaude_code.ui.terminal.color import is_light_terminal_background
16
+ from klaude_code.trace import prepare_debug_log_file
17
17
 
18
18
 
19
19
  def set_terminal_title(title: str) -> None:
@@ -42,142 +42,10 @@ app = typer.Typer(
42
42
  no_args_is_help=False,
43
43
  )
44
44
 
45
- session_app = typer.Typer(help="Manage sessions for the current project")
46
- register_session_commands(session_app)
47
- app.add_typer(session_app, name="session")
48
-
49
-
50
- @app.command("login")
51
- def login_command(
52
- provider: str = typer.Argument("codex", help="Provider to login (codex)"),
53
- ) -> None:
54
- """Login to a provider using OAuth."""
55
- if provider.lower() != "codex":
56
- log((f"Error: Unknown provider '{provider}'. Currently only 'codex' is supported.", "red"))
57
- raise typer.Exit(1)
58
-
59
- from klaude_code.auth.codex.oauth import CodexOAuth
60
- from klaude_code.auth.codex.token_manager import CodexTokenManager
61
-
62
- token_manager = CodexTokenManager()
63
-
64
- # Check if already logged in
65
- if token_manager.is_logged_in():
66
- state = token_manager.get_state()
67
- if state and not state.is_expired():
68
- log(("You are already logged in to Codex.", "green"))
69
- log(f" Account ID: {state.account_id[:8]}...")
70
- expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.timezone.utc)
71
- log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
72
- if not typer.confirm("Do you want to re-login?"):
73
- return
74
-
75
- log("Starting Codex OAuth login flow...")
76
- log("A browser window will open for authentication.")
77
-
78
- try:
79
- oauth = CodexOAuth(token_manager)
80
- state = oauth.login()
81
- log(("Login successful!", "green"))
82
- log(f" Account ID: {state.account_id[:8]}...")
83
- expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.timezone.utc)
84
- log(f" Expires: {expires_dt.strftime('%Y-%m-%d %H:%M:%S UTC')}")
85
- except Exception as e:
86
- log((f"Login failed: {e}", "red"))
87
- raise typer.Exit(1)
88
-
89
-
90
- @app.command("logout")
91
- def logout_command(
92
- provider: str = typer.Argument("codex", help="Provider to logout (codex)"),
93
- ) -> None:
94
- """Logout from a provider."""
95
- if provider.lower() != "codex":
96
- log((f"Error: Unknown provider '{provider}'. Currently only 'codex' is supported.", "red"))
97
- raise typer.Exit(1)
98
-
99
- from klaude_code.auth.codex.token_manager import CodexTokenManager
100
-
101
- token_manager = CodexTokenManager()
102
-
103
- if not token_manager.is_logged_in():
104
- log("You are not logged in to Codex.")
105
- return
106
-
107
- if typer.confirm("Are you sure you want to logout from Codex?"):
108
- token_manager.delete()
109
- log(("Logged out from Codex.", "green"))
110
-
111
-
112
- @app.command("list")
113
- def list_models() -> None:
114
- """List all models and providers configuration"""
115
- config = load_config()
116
- if config is None:
117
- raise typer.Exit(1)
118
-
119
- # Auto-detect theme when not explicitly set in config, to match other CLI entrypoints.
120
- if config.theme is None:
121
- detected = is_light_terminal_background()
122
- if detected is True:
123
- config.theme = "light"
124
- elif detected is False:
125
- config.theme = "dark"
126
-
127
- display_models_and_providers(config)
128
-
129
-
130
- @app.command("config")
131
- @app.command("conf", hidden=True)
132
- def edit_config() -> None:
133
- """Open the configuration file in $EDITOR or default system editor"""
134
- editor = os.environ.get("EDITOR")
135
-
136
- # If no EDITOR is set, prioritize TextEdit on macOS
137
- if not editor:
138
- # Try common editors in order of preference on other platforms
139
- for cmd in [
140
- "code",
141
- "nvim",
142
- "vim",
143
- "nano",
144
- ]:
145
- try:
146
- subprocess.run(["which", cmd], check=True, capture_output=True)
147
- editor = cmd
148
- break
149
- except (subprocess.CalledProcessError, FileNotFoundError):
150
- continue
151
-
152
- # If no editor found, try platform-specific defaults
153
- if not editor:
154
- if sys.platform == "darwin": # macOS
155
- editor = "open"
156
- elif sys.platform == "win32": # Windows
157
- editor = "notepad"
158
- else: # Linux and other Unix systems
159
- editor = "xdg-open"
160
-
161
- # Ensure config file exists
162
- config = load_config()
163
- if config is None:
164
- raise typer.Exit(1)
165
-
166
- try:
167
- if editor == "open -a TextEdit":
168
- subprocess.run(["open", "-a", "TextEdit", str(config_path)], check=True)
169
- elif editor in ["open", "xdg-open"]:
170
- # For open/xdg-open, we need to pass the file directly
171
- subprocess.run([editor, str(config_path)], check=True)
172
- else:
173
- subprocess.run([editor, str(config_path)], check=True)
174
- except subprocess.CalledProcessError as e:
175
- log((f"Error: Failed to open editor: {e}", "red"))
176
- raise typer.Exit(1)
177
- except FileNotFoundError:
178
- log((f"Error: Editor '{editor}' not found", "red"))
179
- log("Please install a text editor or set your $EDITOR environment variable")
180
- raise typer.Exit(1)
45
+ # Register subcommands from modules
46
+ register_session_commands(app)
47
+ register_auth_commands(app)
48
+ register_config_commands(app)
181
49
 
182
50
 
183
51
  @app.command("exec")
@@ -222,6 +90,7 @@ def exec_command(
222
90
  ),
223
91
  ) -> None:
224
92
  """Execute non-interactively with provided input."""
93
+ from klaude_code.trace import log
225
94
 
226
95
  # Set terminal title with current folder name
227
96
  folder_name = os.path.basename(os.getcwd())
@@ -250,6 +119,9 @@ def exec_command(
250
119
  log(("Error: No input content provided", "red"))
251
120
  raise typer.Exit(1)
252
121
 
122
+ from klaude_code.cli.runtime import AppInitConfig, run_exec
123
+ from klaude_code.config.select_model import select_model_from_config
124
+
253
125
  chosen_model = model
254
126
  if select_model:
255
127
  # Prefer the explicitly provided model as default; otherwise main model
@@ -263,6 +135,10 @@ def exec_command(
263
135
 
264
136
  debug_enabled, debug_filters = resolve_debug_settings(debug, debug_filter)
265
137
 
138
+ log_path: Path | None = None
139
+ if debug_enabled:
140
+ log_path = prepare_debug_log_file()
141
+
266
142
  init_config = AppInitConfig(
267
143
  model=chosen_model,
268
144
  debug=debug_enabled,
@@ -272,6 +148,9 @@ def exec_command(
272
148
  stream_json=stream_json,
273
149
  )
274
150
 
151
+ if log_path:
152
+ open_log_file_in_editor(log_path)
153
+
275
154
  asyncio.run(
276
155
  run_exec(
277
156
  init_config=init_config,
@@ -328,6 +207,9 @@ def main_callback(
328
207
  ) -> None:
329
208
  # Only run interactive mode when no subcommand is invoked
330
209
  if ctx.invoked_subcommand is None:
210
+ from klaude_code.cli.runtime import AppInitConfig, run_interactive
211
+ from klaude_code.config.select_model import select_model_from_config
212
+
331
213
  # Set terminal title with current folder name
332
214
  folder_name = os.path.basename(os.getcwd())
333
215
  set_terminal_title(f"{folder_name}: klaude")
@@ -352,6 +234,10 @@ def main_callback(
352
234
 
353
235
  debug_enabled, debug_filters = resolve_debug_settings(debug, debug_filter)
354
236
 
237
+ log_path: Path | None = None
238
+ if debug_enabled:
239
+ log_path = prepare_debug_log_file()
240
+
355
241
  init_config = AppInitConfig(
356
242
  model=chosen_model,
357
243
  debug=debug_enabled,
@@ -359,6 +245,9 @@ def main_callback(
359
245
  debug_filters=debug_filters,
360
246
  )
361
247
 
248
+ if log_path:
249
+ open_log_file_in_editor(log_path)
250
+
362
251
  asyncio.run(
363
252
  run_interactive(
364
253
  init_config=init_config,
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import contextlib
2
3
  import sys
3
4
  from dataclasses import dataclass
4
5
  from typing import Any, Protocol
@@ -29,37 +30,6 @@ class PrintCapable(Protocol):
29
30
  def print(self, *objects: Any, style: Any | None = None, end: str = "\n") -> None: ...
30
31
 
31
32
 
32
- DEBUG_FILTER_HELP = "Comma-separated debug types: " + ", ".join(dt.value for dt in DebugType)
33
-
34
-
35
- def _parse_debug_filters(raw: str | None) -> set[DebugType] | None:
36
- if raw is None:
37
- return None
38
- filters: set[DebugType] = set()
39
- for chunk in raw.split(","):
40
- normalized = chunk.strip().lower().replace("-", "_")
41
- if not normalized:
42
- continue
43
- try:
44
- filters.add(DebugType(normalized))
45
- except ValueError: # pragma: no cover - user input validation
46
- valid_options = ", ".join(dt.value for dt in DebugType)
47
- log(
48
- (
49
- f"Invalid debug filter '{normalized}'. Valid options: {valid_options}",
50
- "red",
51
- )
52
- )
53
- raise typer.Exit(2) from None
54
- return filters or None
55
-
56
-
57
- def resolve_debug_settings(flag: bool, raw_filters: str | None) -> tuple[bool, set[DebugType] | None]:
58
- filters = _parse_debug_filters(raw_filters)
59
- effective_flag = flag or (filters is not None)
60
- return effective_flag, filters
61
-
62
-
63
33
  @dataclass
64
34
  class AppInitConfig:
65
35
  """Configuration for initializing the application components."""
@@ -169,32 +139,26 @@ async def cleanup_app_components(components: AppComponents) -> None:
169
139
  await components.display_task
170
140
  finally:
171
141
  # Always attempt to clear Ghostty progress bar and restore cursor visibility
172
- try:
142
+ # Best-effort only; never fail cleanup due to OSC errors
143
+ with contextlib.suppress(Exception):
173
144
  emit_osc94(OSC94States.HIDDEN)
174
- except Exception:
175
- # Best-effort only; never fail cleanup due to OSC errors
176
- pass
177
145
 
178
- try:
179
- # Ensure the terminal cursor is visible even if Rich's Status spinner
180
- # did not get a chance to stop cleanly (e.g. on KeyboardInterrupt).
146
+ # Ensure the terminal cursor is visible even if Rich's Status spinner
147
+ # did not get a chance to stop cleanly (e.g. on KeyboardInterrupt).
148
+ # If this fails the shell can still recover via `reset`/`stty sane`.
149
+ with contextlib.suppress(Exception):
181
150
  stream = getattr(sys, "__stdout__", None) or sys.stdout
182
151
  stream.write("\033[?25h")
183
152
  stream.flush()
184
- except Exception:
185
- # If this fails the shell can still recover via `reset`/`stty sane`.
186
- pass
187
153
 
188
154
 
189
155
  async def _handle_keyboard_interrupt(executor: Executor) -> None:
190
156
  """Handle Ctrl+C by logging and sending a global interrupt."""
191
157
 
192
158
  log("Bye!")
193
- try:
159
+ # Executor might already be stopping
160
+ with contextlib.suppress(Exception):
194
161
  await executor.submit(op.InterruptOperation(target_session_id=None))
195
- except Exception:
196
- # Executor might already be stopping
197
- pass
198
162
 
199
163
 
200
164
  async def run_exec(init_config: AppInitConfig, input_content: str) -> None:
@@ -259,9 +223,12 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
259
223
  if isinstance(components.display, ui.REPLDisplay):
260
224
  printer = components.display.renderer
261
225
  # Check if it's a DebugEventDisplay wrapping a REPLDisplay
262
- elif isinstance(components.display, ui.DebugEventDisplay) and components.display.wrapped_display:
263
- if isinstance(components.display.wrapped_display, ui.REPLDisplay):
264
- printer = components.display.wrapped_display.renderer
226
+ elif (
227
+ isinstance(components.display, ui.DebugEventDisplay)
228
+ and components.display.wrapped_display
229
+ and isinstance(components.display.wrapped_display, ui.REPLDisplay)
230
+ ):
231
+ printer = components.display.wrapped_display.renderer
265
232
 
266
233
  if printer is not None:
267
234
  printer.print(Text(f" {MSG} ", style="bold yellow reverse"))
@@ -272,10 +239,8 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
272
239
  print(MSG, file=sys.stderr)
273
240
 
274
241
  def _hide_progress() -> None:
275
- try:
242
+ with contextlib.suppress(Exception):
276
243
  emit_osc94(OSC94States.HIDDEN)
277
- except Exception:
278
- pass
279
244
 
280
245
  restore_sigint = install_sigint_double_press_exit(_show_toast_once, _hide_progress)
281
246
 
@@ -315,17 +280,13 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
315
280
  finally:
316
281
  # Stop ESC monitor and wait for it to finish cleaning up TTY
317
282
  stop_event.set()
318
- try:
283
+ with contextlib.suppress(Exception):
319
284
  await esc_task
320
- except Exception:
321
- pass
322
285
 
323
286
  except KeyboardInterrupt:
324
287
  await _handle_keyboard_interrupt(components.executor)
325
288
  finally:
326
- try:
327
- # Restore original SIGINT handler
289
+ # Restore original SIGINT handler
290
+ with contextlib.suppress(Exception):
328
291
  restore_sigint()
329
- except Exception:
330
- pass
331
292
  await cleanup_app_components(components)