klaude-code 2.5.3__tar.gz → 2.7.0__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 (245) hide show
  1. {klaude_code-2.5.3 → klaude_code-2.7.0}/PKG-INFO +32 -40
  2. {klaude_code-2.5.3 → klaude_code-2.7.0}/README.md +30 -36
  3. {klaude_code-2.5.3 → klaude_code-2.7.0}/pyproject.toml +2 -4
  4. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/app/runtime.py +1 -1
  5. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/__init__.py +10 -0
  6. klaude_code-2.7.0/src/klaude_code/auth/env.py +81 -0
  7. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/auth_cmd.py +87 -8
  8. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/config_cmd.py +5 -5
  9. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/cost_cmd.py +159 -60
  10. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/main.py +146 -65
  11. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/self_update.py +7 -7
  12. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/builtin_config.py +23 -9
  13. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/config.py +19 -9
  14. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/const.py +10 -1
  15. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/reminders.py +4 -5
  16. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/turn.py +8 -9
  17. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/google/client.py +12 -0
  18. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openai_compatible/stream.py +5 -1
  19. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openrouter/client.py +1 -0
  20. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/commands.py +0 -1
  21. klaude_code-2.7.0/src/klaude_code/protocol/events.py +214 -0
  22. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/image_gen.py +0 -4
  23. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/session.py +51 -18
  24. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/loader.py +12 -13
  25. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/manager.py +3 -3
  26. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/__init__.py +1 -4
  27. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/copy_cmd.py +1 -1
  28. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/fork_session_cmd.py +4 -4
  29. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/commands.py +0 -5
  30. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/command_output.py +1 -1
  31. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/metadata.py +4 -5
  32. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/markdown.py +60 -0
  33. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/theme.py +8 -0
  34. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/sub_agent.py +6 -0
  35. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/user_input.py +38 -27
  36. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/display.py +11 -1
  37. klaude_code-2.7.0/src/klaude_code/tui/input/AGENTS.md +44 -0
  38. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/input/completers.py +21 -21
  39. klaude_code-2.7.0/src/klaude_code/tui/input/drag_drop.py +197 -0
  40. klaude_code-2.7.0/src/klaude_code/tui/input/images.py +227 -0
  41. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/input/key_bindings.py +173 -19
  42. klaude_code-2.7.0/src/klaude_code/tui/input/paste.py +71 -0
  43. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/input/prompt_toolkit.py +13 -3
  44. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/machine.py +90 -56
  45. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/renderer.py +1 -62
  46. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/runner.py +1 -1
  47. klaude_code-2.7.0/src/klaude_code/tui/terminal/image.py +65 -0
  48. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/selector.py +52 -2
  49. klaude_code-2.5.3/src/klaude_code/cli/session_cmd.py +0 -87
  50. klaude_code-2.5.3/src/klaude_code/protocol/events/__init__.py +0 -63
  51. klaude_code-2.5.3/src/klaude_code/protocol/events/base.py +0 -18
  52. klaude_code-2.5.3/src/klaude_code/protocol/events/chat.py +0 -30
  53. klaude_code-2.5.3/src/klaude_code/protocol/events/lifecycle.py +0 -23
  54. klaude_code-2.5.3/src/klaude_code/protocol/events/metadata.py +0 -16
  55. klaude_code-2.5.3/src/klaude_code/protocol/events/streaming.py +0 -43
  56. klaude_code-2.5.3/src/klaude_code/protocol/events/system.py +0 -56
  57. klaude_code-2.5.3/src/klaude_code/protocol/events/tools.py +0 -27
  58. klaude_code-2.5.3/src/klaude_code/tui/command/terminal_setup_cmd.py +0 -248
  59. klaude_code-2.5.3/src/klaude_code/tui/input/clipboard.py +0 -152
  60. klaude_code-2.5.3/src/klaude_code/tui/terminal/image.py +0 -34
  61. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/.DS_Store +0 -0
  62. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/__init__.py +0 -0
  63. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/app/__init__.py +0 -0
  64. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/base.py +0 -0
  65. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/claude/__init__.py +0 -0
  66. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/claude/exceptions.py +0 -0
  67. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/claude/oauth.py +0 -0
  68. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/claude/token_manager.py +0 -0
  69. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/codex/__init__.py +0 -0
  70. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/codex/exceptions.py +0 -0
  71. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  72. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/codex/oauth.py +0 -0
  73. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/auth/codex/token_manager.py +0 -0
  74. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/__init__.py +0 -0
  75. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/debug.py +0 -0
  76. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/cli/list_model.py +0 -0
  77. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/__init__.py +0 -0
  78. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/assets/__init__.py +0 -0
  79. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/assets/builtin_config.yaml +0 -0
  80. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/model_matcher.py +0 -0
  81. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/sub_agent_model_helper.py +0 -0
  82. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/config/thinking.py +0 -0
  83. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/__init__.py +0 -0
  84. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/agent.py +0 -0
  85. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/agent_profile.py +0 -0
  86. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/executor.py +0 -0
  87. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/loaded_skills.py +0 -0
  88. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/manager/__init__.py +0 -0
  89. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/manager/llm_clients.py +0 -0
  90. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  91. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  92. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  93. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  94. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
  95. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
  96. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  97. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  98. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  99. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-image-gen.md +0 -0
  100. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  101. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  102. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/task.py +0 -0
  103. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/__init__.py +0 -0
  104. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/context.py +0 -0
  105. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/__init__.py +0 -0
  106. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/_utils.py +0 -0
  107. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  108. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  109. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  110. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  111. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  112. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  113. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  114. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/read_tool.py +0 -0
  115. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  116. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  117. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/offload.py +0 -0
  118. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  119. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  120. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  121. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  122. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  123. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  124. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  125. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  126. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  127. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  128. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  129. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  130. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/tool_abc.py +0 -0
  131. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/tool_registry.py +0 -0
  132. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/tool_runner.py +0 -0
  133. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/__init__.py +0 -0
  134. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  135. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  136. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  137. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  138. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  139. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  140. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/__init__.py +0 -0
  141. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  142. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/anthropic/client.py +0 -0
  143. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/anthropic/input.py +0 -0
  144. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/bedrock/__init__.py +0 -0
  145. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/bedrock/client.py +0 -0
  146. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/claude/__init__.py +0 -0
  147. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/claude/client.py +0 -0
  148. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/client.py +0 -0
  149. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/codex/__init__.py +0 -0
  150. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/codex/client.py +0 -0
  151. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/google/__init__.py +0 -0
  152. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/google/input.py +0 -0
  153. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/image.py +0 -0
  154. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/input_common.py +0 -0
  155. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  156. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openai_compatible/client.py +0 -0
  157. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  158. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  159. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  160. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openrouter/input.py +0 -0
  161. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
  162. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/partial_message.py +0 -0
  163. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/registry.py +0 -0
  164. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/responses/__init__.py +0 -0
  165. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/responses/client.py +0 -0
  166. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/responses/input.py +0 -0
  167. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/stream_parts.py +0 -0
  168. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/llm/usage.py +0 -0
  169. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/log.py +0 -0
  170. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/__init__.py +0 -0
  171. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/llm_param.py +0 -0
  172. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/message.py +0 -0
  173. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/model.py +0 -0
  174. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/op.py +0 -0
  175. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/op_handler.py +0 -0
  176. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/AGENTS.md +0 -0
  177. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  178. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  179. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  180. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  181. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/protocol/tools.py +0 -0
  182. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/__init__.py +0 -0
  183. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/codec.py +0 -0
  184. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/export.py +0 -0
  185. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/selector.py +0 -0
  186. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/store.py +0 -0
  187. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/templates/export_session.html +0 -0
  188. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
  189. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/.DS_Store +0 -0
  190. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/__init__.py +0 -0
  191. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/assets/.DS_Store +0 -0
  192. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/assets/create-plan/SKILL.md +0 -0
  193. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  194. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
  195. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  196. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/skill/system_skills.py +0 -0
  197. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/__init__.py +0 -0
  198. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/clear_cmd.py +0 -0
  199. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/command_abc.py +0 -0
  200. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/debug_cmd.py +0 -0
  201. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/export_cmd.py +0 -0
  202. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/export_online_cmd.py +0 -0
  203. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/model_cmd.py +0 -0
  204. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/model_picker.py +0 -0
  205. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/prompt-init.md +0 -0
  206. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/prompt_command.py +0 -0
  207. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/refresh_cmd.py +0 -0
  208. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/registry.py +0 -0
  209. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/resume_cmd.py +0 -0
  210. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/status_cmd.py +0 -0
  211. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/sub_agent_model_cmd.py +0 -0
  212. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/command/thinking_cmd.py +0 -0
  213. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/__init__.py +0 -0
  214. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/assistant.py +0 -0
  215. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/bash_syntax.py +0 -0
  216. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/common.py +0 -0
  217. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/developer.py +0 -0
  218. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/diffs.py +0 -0
  219. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/errors.py +0 -0
  220. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/mermaid_viewer.py +0 -0
  221. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/__init__.py +0 -0
  222. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/cjk_wrap.py +0 -0
  223. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/code_panel.py +0 -0
  224. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/live.py +0 -0
  225. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/quote.py +0 -0
  226. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/searchable_text.py +0 -0
  227. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/rich/status.py +0 -0
  228. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/thinking.py +0 -0
  229. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/tools.py +0 -0
  230. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/components/welcome.py +0 -0
  231. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/input/__init__.py +0 -0
  232. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/__init__.py +0 -0
  233. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/color.py +0 -0
  234. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/control.py +0 -0
  235. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/notifier.py +0 -0
  236. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/tui/terminal/progress_bar.py +0 -0
  237. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/__init__.py +0 -0
  238. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/common.py +0 -0
  239. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/core/__init__.py +0 -0
  240. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/core/display.py +0 -0
  241. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/core/input.py +0 -0
  242. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/debug_mode.py +0 -0
  243. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/terminal/__init__.py +0 -0
  244. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/ui/terminal/title.py +0 -0
  245. {klaude_code-2.5.3 → klaude_code-2.7.0}/src/klaude_code/update.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 2.5.3
3
+ Version: 2.7.0
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -9,15 +9,13 @@ Requires-Dist: diff-match-patch>=20241021
9
9
  Requires-Dist: google-genai>=1.56.0
10
10
  Requires-Dist: markdown-it-py>=4.0.0
11
11
  Requires-Dist: openai>=1.102.0
12
- Requires-Dist: pillow>=9.1,<11.0
13
12
  Requires-Dist: prompt-toolkit>=3.0.52
14
13
  Requires-Dist: pydantic>=2.11.7
15
14
  Requires-Dist: pyyaml>=6.0.2
16
15
  Requires-Dist: rich>=14.1.0
17
- Requires-Dist: term-image>=0.7.2
18
16
  Requires-Dist: trafilatura>=2.0.0
19
17
  Requires-Dist: typer>=0.17.3
20
- Requires-Python: >=3.13, <3.14
18
+ Requires-Python: >=3.13
21
19
  Description-Content-Type: text/markdown
22
20
 
23
21
  # Klaude Code
@@ -52,32 +50,31 @@ To update:
52
50
  uv tool upgrade klaude-code
53
51
  ```
54
52
 
55
- Or use the built-in alias command:
53
+ Or use the built-in command:
56
54
 
57
55
  ```bash
58
- klaude update
59
56
  klaude upgrade
60
- klaude --version
61
-
62
57
  ```
63
58
 
64
59
  ## Usage
65
60
 
66
61
  ```bash
67
- klaude [--model <name>] [--select-model]
62
+ klaude [--model [<name>]] [--continue] [--resume [<id>]]
68
63
  ```
69
64
 
70
65
  **Options:**
71
- - `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
72
- - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
66
+ - `--model`/`-m`: Choose a model.
67
+ - `--model` (no value): opens the interactive selector.
68
+ - `--model <value>`: resolves `<value>` to a single model; if it can't, it opens the interactive selector filtered by `<value>`.
73
69
  - `--continue`/`-c`: Resume the most recent session.
74
- - `--resume`/`-r`: Select a session to resume for this project.
75
- - `--resume-by-id <id>`: Resume a session by its ID directly.
70
+ - `--resume`/`-r`: Resume a session.
71
+ - `--resume` (no value): select a session to resume for this project.
72
+ - `--resume <id>`: resume a session by its ID directly.
76
73
  - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit, Write) and no system prompts.
77
74
 
78
75
  **Model selection behavior:**
79
76
  - Default: uses `main_model` from config.
80
- - `--select-model`: always prompts you to pick.
77
+ - `--model` (no value): always prompts you to pick.
81
78
  - `--model <value>`: tries to resolve `<value>` to a single model; if it can't, it prompts with a filtered list (and falls back to showing all models if there are no matches).
82
79
 
83
80
  **Debug Options:**
@@ -125,24 +122,34 @@ klaude list
125
122
 
126
123
  Models from providers without a valid API key are shown as dimmed/unavailable.
127
124
 
128
- #### OAuth Login
125
+ #### Authentication
129
126
 
130
- For subscription-based providers (Claude Pro/Max, ChatGPT Pro), use the login command:
127
+ Use the auth command to configure API keys or login to subscription-based providers:
131
128
 
132
129
  ```bash
133
130
  # Interactive provider selection
134
- klaude login
135
-
136
- # Or specify provider directly
137
- klaude login claude # Claude Pro/Max subscription
138
- klaude login codex # ChatGPT Pro subscription
131
+ klaude auth login
132
+
133
+ # Configure API keys
134
+ klaude auth login anthropic # Set ANTHROPIC_API_KEY
135
+ klaude auth login openai # Set OPENAI_API_KEY
136
+ klaude auth login google # Set GOOGLE_API_KEY
137
+ klaude auth login openrouter # Set OPENROUTER_API_KEY
138
+ klaude auth login deepseek # Set DEEPSEEK_API_KEY
139
+ klaude auth login moonshot # Set MOONSHOT_API_KEY
140
+
141
+ # OAuth login for subscription-based providers
142
+ klaude auth login claude # Claude Pro/Max subscription
143
+ klaude auth login codex # ChatGPT Pro subscription
139
144
  ```
140
145
 
141
- To logout:
146
+ API keys are stored in `~/.klaude/klaude-auth.json` and used as fallback when environment variables are not set.
147
+
148
+ To logout from OAuth providers:
142
149
 
143
150
  ```bash
144
- klaude logout claude
145
- klaude logout codex
151
+ klaude auth logout claude
152
+ klaude auth logout codex
146
153
  ```
147
154
 
148
155
  #### Custom Configuration
@@ -152,7 +159,7 @@ User config file: `~/.klaude/klaude-config.yaml`
152
159
  Open in editor:
153
160
 
154
161
  ```bash
155
- klaude config
162
+ klaude conf
156
163
  ```
157
164
 
158
165
  ##### Model Configuration
@@ -208,21 +215,6 @@ List configured providers and models:
208
215
  klaude list
209
216
  ```
210
217
 
211
- ### Session Management
212
-
213
- Clean up sessions with few messages:
214
-
215
- ```bash
216
- # Remove sessions with fewer than 5 messages (default)
217
- klaude session clean
218
-
219
- # Remove sessions with fewer than 10 messages
220
- klaude session clean --min 10
221
-
222
- # Remove all sessions for the current project
223
- klaude session clean-all
224
- ```
225
-
226
218
  ### Cost Tracking
227
219
 
228
220
  View aggregated usage statistics across all sessions:
@@ -30,32 +30,31 @@ To update:
30
30
  uv tool upgrade klaude-code
31
31
  ```
32
32
 
33
- Or use the built-in alias command:
33
+ Or use the built-in command:
34
34
 
35
35
  ```bash
36
- klaude update
37
36
  klaude upgrade
38
- klaude --version
39
-
40
37
  ```
41
38
 
42
39
  ## Usage
43
40
 
44
41
  ```bash
45
- klaude [--model <name>] [--select-model]
42
+ klaude [--model [<name>]] [--continue] [--resume [<id>]]
46
43
  ```
47
44
 
48
45
  **Options:**
49
- - `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
50
- - `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
46
+ - `--model`/`-m`: Choose a model.
47
+ - `--model` (no value): opens the interactive selector.
48
+ - `--model <value>`: resolves `<value>` to a single model; if it can't, it opens the interactive selector filtered by `<value>`.
51
49
  - `--continue`/`-c`: Resume the most recent session.
52
- - `--resume`/`-r`: Select a session to resume for this project.
53
- - `--resume-by-id <id>`: Resume a session by its ID directly.
50
+ - `--resume`/`-r`: Resume a session.
51
+ - `--resume` (no value): select a session to resume for this project.
52
+ - `--resume <id>`: resume a session by its ID directly.
54
53
  - `--vanilla`: Minimal mode with only basic tools (Bash, Read, Edit, Write) and no system prompts.
55
54
 
56
55
  **Model selection behavior:**
57
56
  - Default: uses `main_model` from config.
58
- - `--select-model`: always prompts you to pick.
57
+ - `--model` (no value): always prompts you to pick.
59
58
  - `--model <value>`: tries to resolve `<value>` to a single model; if it can't, it prompts with a filtered list (and falls back to showing all models if there are no matches).
60
59
 
61
60
  **Debug Options:**
@@ -103,24 +102,34 @@ klaude list
103
102
 
104
103
  Models from providers without a valid API key are shown as dimmed/unavailable.
105
104
 
106
- #### OAuth Login
105
+ #### Authentication
107
106
 
108
- For subscription-based providers (Claude Pro/Max, ChatGPT Pro), use the login command:
107
+ Use the auth command to configure API keys or login to subscription-based providers:
109
108
 
110
109
  ```bash
111
110
  # Interactive provider selection
112
- klaude login
113
-
114
- # Or specify provider directly
115
- klaude login claude # Claude Pro/Max subscription
116
- klaude login codex # ChatGPT Pro subscription
111
+ klaude auth login
112
+
113
+ # Configure API keys
114
+ klaude auth login anthropic # Set ANTHROPIC_API_KEY
115
+ klaude auth login openai # Set OPENAI_API_KEY
116
+ klaude auth login google # Set GOOGLE_API_KEY
117
+ klaude auth login openrouter # Set OPENROUTER_API_KEY
118
+ klaude auth login deepseek # Set DEEPSEEK_API_KEY
119
+ klaude auth login moonshot # Set MOONSHOT_API_KEY
120
+
121
+ # OAuth login for subscription-based providers
122
+ klaude auth login claude # Claude Pro/Max subscription
123
+ klaude auth login codex # ChatGPT Pro subscription
117
124
  ```
118
125
 
119
- To logout:
126
+ API keys are stored in `~/.klaude/klaude-auth.json` and used as fallback when environment variables are not set.
127
+
128
+ To logout from OAuth providers:
120
129
 
121
130
  ```bash
122
- klaude logout claude
123
- klaude logout codex
131
+ klaude auth logout claude
132
+ klaude auth logout codex
124
133
  ```
125
134
 
126
135
  #### Custom Configuration
@@ -130,7 +139,7 @@ User config file: `~/.klaude/klaude-config.yaml`
130
139
  Open in editor:
131
140
 
132
141
  ```bash
133
- klaude config
142
+ klaude conf
134
143
  ```
135
144
 
136
145
  ##### Model Configuration
@@ -186,21 +195,6 @@ List configured providers and models:
186
195
  klaude list
187
196
  ```
188
197
 
189
- ### Session Management
190
-
191
- Clean up sessions with few messages:
192
-
193
- ```bash
194
- # Remove sessions with fewer than 5 messages (default)
195
- klaude session clean
196
-
197
- # Remove sessions with fewer than 10 messages
198
- klaude session clean --min 10
199
-
200
- # Remove all sessions for the current project
201
- klaude session clean-all
202
- ```
203
-
204
198
  ### Cost Tracking
205
199
 
206
200
  View aggregated usage statistics across all sessions:
@@ -4,10 +4,10 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "2.5.3"
7
+ version = "2.7.0"
8
8
  description = "Minimal code agent CLI"
9
9
  readme = "README.md"
10
- requires-python = ">=3.13,<3.14"
10
+ requires-python = ">=3.13"
11
11
  dependencies = [
12
12
  "anthropic>=0.66.0",
13
13
  "chardet>=5.2.0",
@@ -16,12 +16,10 @@ dependencies = [
16
16
  "google-genai>=1.56.0",
17
17
  "markdown-it-py>=4.0.0",
18
18
  "openai>=1.102.0",
19
- "pillow>=9.1,<11.0",
20
19
  "prompt-toolkit>=3.0.52",
21
20
  "pydantic>=2.11.7",
22
21
  "pyyaml>=6.0.2",
23
22
  "rich>=14.1.0",
24
- "term-image>=0.7.2",
25
23
  "trafilatura>=2.0.0",
26
24
  "typer>=0.17.3",
27
25
  ]
@@ -178,6 +178,6 @@ async def handle_keyboard_interrupt(executor: Executor) -> None:
178
178
  log("Bye!")
179
179
  session_id = executor.context.current_session_id()
180
180
  if session_id and Session.exists(session_id):
181
- log(("Resume with:", "dim"), (f"klaude --resume-by-id {session_id}", "green"))
181
+ log(("Resume with:", "dim"), (f"klaude --resume {session_id}", "green"))
182
182
  with contextlib.suppress(Exception):
183
183
  await executor.submit(op.InterruptOperation(target_session_id=None))
@@ -12,6 +12,12 @@ from klaude_code.auth.codex import (
12
12
  CodexTokenExpiredError,
13
13
  CodexTokenManager,
14
14
  )
15
+ from klaude_code.auth.env import (
16
+ delete_auth_env,
17
+ get_auth_env,
18
+ list_auth_env,
19
+ set_auth_env,
20
+ )
15
21
 
16
22
  __all__ = [
17
23
  "CodexAuthError",
@@ -21,4 +27,8 @@ __all__ = [
21
27
  "CodexOAuthError",
22
28
  "CodexTokenExpiredError",
23
29
  "CodexTokenManager",
30
+ "delete_auth_env",
31
+ "get_auth_env",
32
+ "list_auth_env",
33
+ "set_auth_env",
24
34
  ]
@@ -0,0 +1,81 @@
1
+ """Environment variable configuration stored in klaude-auth.json."""
2
+
3
+ import json
4
+ from typing import Any, cast
5
+
6
+ from klaude_code.auth.base import KLAUDE_AUTH_FILE
7
+
8
+
9
+ def _load_store() -> dict[str, Any]:
10
+ """Load the auth store from file."""
11
+ if not KLAUDE_AUTH_FILE.exists():
12
+ return {}
13
+ try:
14
+ data = json.loads(KLAUDE_AUTH_FILE.read_text())
15
+ if isinstance(data, dict):
16
+ return cast(dict[str, Any], data)
17
+ return {}
18
+ except (json.JSONDecodeError, ValueError):
19
+ return {}
20
+
21
+
22
+ def _save_store(data: dict[str, Any]) -> None:
23
+ """Save the auth store to file."""
24
+ KLAUDE_AUTH_FILE.parent.mkdir(parents=True, exist_ok=True)
25
+ KLAUDE_AUTH_FILE.write_text(json.dumps(data, indent=2))
26
+
27
+
28
+ def _get_env_section(store: dict[str, Any]) -> dict[str, Any] | None:
29
+ """Extract and validate the 'env' section from store."""
30
+ env_section = store.get("env")
31
+ if isinstance(env_section, dict):
32
+ return cast(dict[str, Any], env_section)
33
+ return None
34
+
35
+
36
+ def get_auth_env(env_var: str) -> str | None:
37
+ """Get environment variable value from klaude-auth.json 'env' section.
38
+
39
+ This provides a fallback for API keys when real environment variables are not set.
40
+ Priority: os.environ > klaude-auth.json env
41
+ """
42
+ env_section = _get_env_section(_load_store())
43
+ if env_section is None:
44
+ return None
45
+ value = env_section.get(env_var)
46
+ return str(value) if value is not None else None
47
+
48
+
49
+ def set_auth_env(env_var: str, value: str) -> None:
50
+ """Set environment variable value in klaude-auth.json 'env' section."""
51
+ store = _load_store()
52
+ env_section = _get_env_section(store) or {}
53
+ env_section[env_var] = value
54
+ store["env"] = env_section
55
+ _save_store(store)
56
+
57
+
58
+ def delete_auth_env(env_var: str) -> None:
59
+ """Delete environment variable from klaude-auth.json 'env' section."""
60
+ store = _load_store()
61
+ env_section = _get_env_section(store)
62
+ if env_section is None:
63
+ return
64
+ env_section.pop(env_var, None)
65
+ if len(env_section) == 0:
66
+ store.pop("env", None)
67
+ else:
68
+ store["env"] = env_section
69
+ if len(store) == 0:
70
+ if KLAUDE_AUTH_FILE.exists():
71
+ KLAUDE_AUTH_FILE.unlink()
72
+ else:
73
+ _save_store(store)
74
+
75
+
76
+ def list_auth_env() -> dict[str, str]:
77
+ """List all environment variables in klaude-auth.json 'env' section."""
78
+ env_section = _get_env_section(_load_store())
79
+ if env_section is None:
80
+ return {}
81
+ return {k: str(v) for k, v in env_section.items() if v is not None}
@@ -11,10 +11,30 @@ from klaude_code.tui.terminal.selector import DEFAULT_PICKER_STYLE, SelectItem,
11
11
 
12
12
  def _select_provider() -> str | None:
13
13
  """Display provider selection menu and return selected provider."""
14
+ from klaude_code.config.builtin_config import SUPPORTED_API_KEYS
15
+
14
16
  items: list[SelectItem[str]] = [
15
- SelectItem(title=[("class:text", "Claude Max/Pro Subscription\n")], value="claude", search_text="claude"),
16
- SelectItem(title=[("class:text", "ChatGPT Codex Subscription\n")], value="codex", search_text="codex"),
17
+ SelectItem(
18
+ title=[("", "Claude Max/Pro Subscription "), ("ansibrightblack", "[OAuth]\n")],
19
+ value="claude",
20
+ search_text="claude",
21
+ ),
22
+ SelectItem(
23
+ title=[("", "ChatGPT Codex Subscription "), ("ansibrightblack", "[OAuth]\n")],
24
+ value="codex",
25
+ search_text="codex",
26
+ ),
17
27
  ]
28
+ # Add API key options
29
+ for key_info in SUPPORTED_API_KEYS:
30
+ items.append(
31
+ SelectItem(
32
+ title=[("", f"{key_info.name} "), ("ansibrightblack", "[API key]\n")],
33
+ value=key_info.env_var,
34
+ search_text=key_info.env_var,
35
+ )
36
+ )
37
+
18
38
  return select_one(
19
39
  message="Select provider to login:",
20
40
  items=items,
@@ -24,10 +44,41 @@ def _select_provider() -> str | None:
24
44
  )
25
45
 
26
46
 
47
+ def _configure_api_key(env_var: str) -> None:
48
+ """Configure a specific API key."""
49
+ import os
50
+
51
+ from klaude_code.auth.env import get_auth_env, set_auth_env
52
+
53
+ # Check if already configured
54
+ current_value = os.environ.get(env_var) or get_auth_env(env_var)
55
+ if current_value:
56
+ masked = current_value[:8] + "..." if len(current_value) > 8 else "***"
57
+ log(f"Current {env_var}: {masked}")
58
+ if not typer.confirm("Do you want to update it?"):
59
+ return
60
+
61
+ api_key = typer.prompt(f"Enter {env_var}", hide_input=True)
62
+ if not api_key.strip():
63
+ log(("Error: API key cannot be empty", "red"))
64
+ raise typer.Exit(1)
65
+
66
+ set_auth_env(env_var, api_key.strip())
67
+ log((f"{env_var} saved successfully!", "green"))
68
+
69
+
70
+ def _build_provider_help() -> str:
71
+ from klaude_code.config.builtin_config import SUPPORTED_API_KEYS
72
+
73
+ # Use first word of name for brevity (e.g., "google" instead of "google gemini")
74
+ names = ["codex", "claude"] + [k.name.split()[0].lower() for k in SUPPORTED_API_KEYS]
75
+ return f"Provider name ({', '.join(names)})"
76
+
77
+
27
78
  def login_command(
28
- provider: str | None = typer.Argument(None, help="Provider to login (codex|claude)"),
79
+ provider: str | None = typer.Argument(None, help=_build_provider_help()),
29
80
  ) -> None:
30
- """Login to a provider using OAuth."""
81
+ """Login to a provider or configure API keys."""
31
82
  if provider is None:
32
83
  provider = _select_provider()
33
84
  if provider is None:
@@ -99,8 +150,27 @@ def login_command(
99
150
  log((f"Login failed: {e}", "red"))
100
151
  raise typer.Exit(1) from None
101
152
  case _:
102
- log((f"Error: Unknown provider '{provider}'. Supported: codex, claude", "red"))
103
- raise typer.Exit(1)
153
+ from klaude_code.config.builtin_config import SUPPORTED_API_KEYS
154
+
155
+ # Match by env var (e.g., OPENAI_API_KEY) or name (e.g., openai, google)
156
+ env_var: str | None = None
157
+ provider_lower = provider.lower()
158
+ provider_upper = provider.upper()
159
+ for key_info in SUPPORTED_API_KEYS:
160
+ name_lower = key_info.name.lower()
161
+ # Exact match or starts with (for "google" -> "google gemini")
162
+ if key_info.env_var == provider_upper or name_lower == provider_lower:
163
+ env_var = key_info.env_var
164
+ break
165
+ if name_lower.startswith(provider_lower) or provider_lower in name_lower.split():
166
+ env_var = key_info.env_var
167
+ break
168
+
169
+ if env_var:
170
+ _configure_api_key(env_var)
171
+ else:
172
+ log((f"Error: Unknown provider '{provider}'", "red"))
173
+ raise typer.Exit(1)
104
174
 
105
175
 
106
176
  def logout_command(
@@ -139,5 +209,14 @@ def logout_command(
139
209
 
140
210
  def register_auth_commands(app: typer.Typer) -> None:
141
211
  """Register auth commands to the given Typer app."""
142
- app.command("login")(login_command)
143
- app.command("logout")(logout_command)
212
+ auth_app = typer.Typer(help="Login/logout", invoke_without_command=True)
213
+
214
+ @auth_app.callback()
215
+ def auth_callback(ctx: typer.Context) -> None: # pyright: ignore[reportUnusedFunction]
216
+ """Authentication commands for managing provider logins."""
217
+ if ctx.invoked_subcommand is None:
218
+ typer.echo(ctx.get_help())
219
+
220
+ auth_app.command("login")(login_command)
221
+ auth_app.command("logout")(logout_command)
222
+ app.add_typer(auth_app, name="auth")
@@ -11,9 +11,9 @@ from klaude_code.log import log
11
11
 
12
12
 
13
13
  def list_models(
14
- show_all: bool = typer.Option(False, "--all", "-a", help="Show all providers including unavailable ones"),
14
+ show_all: bool = typer.Option(False, "--all", "-a", help="Include unavailable providers"),
15
15
  ) -> None:
16
- """List all models and providers configuration"""
16
+ """List available models"""
17
17
  from klaude_code.cli.list_model import display_models_and_providers
18
18
  from klaude_code.tui.terminal.color import is_light_terminal_background
19
19
 
@@ -31,7 +31,7 @@ def list_models(
31
31
 
32
32
 
33
33
  def edit_config() -> None:
34
- """Open the configuration file in $EDITOR or default system editor"""
34
+ """Edit config file"""
35
35
  editor = os.environ.get("EDITOR")
36
36
 
37
37
  # If no EDITOR is set, prioritize TextEdit on macOS
@@ -89,5 +89,5 @@ def edit_config() -> None:
89
89
  def register_config_commands(app: typer.Typer) -> None:
90
90
  """Register config commands to the given Typer app."""
91
91
  app.command("list")(list_models)
92
- app.command("config")(edit_config)
93
- app.command("conf", hidden=True)(edit_config)
92
+ app.command("conf")(edit_config)
93
+ app.command("config", hidden=True)(edit_config)