klaude-code 2.21.0__tar.gz → 2.22.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 (297) hide show
  1. {klaude_code-2.21.0 → klaude_code-2.22.0}/PKG-INFO +18 -5
  2. {klaude_code-2.21.0 → klaude_code-2.22.0}/README.md +16 -3
  3. {klaude_code-2.21.0 → klaude_code-2.22.0}/pyproject.toml +2 -2
  4. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/app/auth_flow.py +7 -7
  5. {klaude_code-2.21.0/src/klaude_code/cli → klaude_code-2.22.0/src/klaude_code/app}/log_viewer.html +107 -4
  6. klaude_code-2.21.0/src/klaude_code/cli/log_server.py → klaude_code-2.22.0/src/klaude_code/app/log_viewer.py +71 -8
  7. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/copilot/oauth.py +3 -1
  8. klaude_code-2.22.0/src/klaude_code/auth/copilot/token_manager.py +64 -0
  9. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/auth_cmd.py +2 -2
  10. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/list_model.py +85 -24
  11. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/main.py +2 -2
  12. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/oauth_usage.py +8 -8
  13. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/assets/builtin_config.yaml +28 -36
  14. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/builtin_config.py +1 -0
  15. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/config.py +89 -28
  16. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/sub_agent_model_helper.py +15 -15
  17. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/thinking.py +5 -5
  18. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/agent.py +16 -2
  19. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/agent_profile.py +16 -21
  20. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/executor.py +48 -46
  21. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/manager/llm_clients.py +0 -5
  22. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/manager/llm_clients_builder.py +5 -2
  23. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/manager/sub_agent_manager.py +1 -1
  24. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/memory.py +4 -1
  25. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/prompts/base-system-prompt.md +2 -0
  26. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/prompts/system_prompt.py +11 -4
  27. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/reminders.py +0 -91
  28. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/task.py +17 -3
  29. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/__init__.py +14 -3
  30. klaude_code-2.21.0/src/klaude_code/core/tool/task_tool.md → klaude_code-2.22.0/src/klaude_code/core/tool/agent_tool.md +3 -3
  31. klaude_code-2.21.0/src/klaude_code/core/tool/task_tool.py → klaude_code-2.22.0/src/klaude_code/core/tool/agent_tool.py +19 -17
  32. klaude_code-2.22.0/src/klaude_code/core/tool/ask_user_question_tool.md +9 -0
  33. klaude_code-2.22.0/src/klaude_code/core/tool/ask_user_question_tool.py +255 -0
  34. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/context.py +15 -1
  35. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/rewind_tool.md +1 -1
  36. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/turn.py +21 -1
  37. klaude_code-2.22.0/src/klaude_code/core/user_interaction/__init__.py +3 -0
  38. klaude_code-2.22.0/src/klaude_code/core/user_interaction/manager.py +114 -0
  39. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/anthropic/client.py +3 -1
  40. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/anthropic/input.py +6 -2
  41. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/copilot/client.py +4 -2
  42. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/google/input.py +11 -3
  43. klaude_code-2.22.0/src/klaude_code/llm/image.py +323 -0
  44. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/input_common.py +7 -7
  45. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_responses/input.py +2 -2
  46. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/registry.py +1 -1
  47. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/__init__.py +1 -0
  48. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/commands.py +1 -3
  49. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/events.py +9 -1
  50. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/llm_param.py +18 -4
  51. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/message.py +3 -0
  52. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/model.py +7 -0
  53. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/op.py +14 -11
  54. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/op_handler.py +5 -5
  55. klaude_code-2.22.0/src/klaude_code/protocol/sub_agent/AGENTS.md +18 -0
  56. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/sub_agent/__init__.py +4 -4
  57. klaude_code-2.21.0/src/klaude_code/protocol/sub_agent/task.py → klaude_code-2.22.0/src/klaude_code/protocol/sub_agent/general_purpose.py +2 -2
  58. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/tools.py +2 -1
  59. klaude_code-2.22.0/src/klaude_code/protocol/user_interaction.py +50 -0
  60. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/session.py +4 -4
  61. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/SKILL.md +8 -7
  62. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/references/cli.md +16 -7
  63. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/references/gemini-api.md +15 -6
  64. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/references/prompting.md +4 -3
  65. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/references/sample-prompts.md +1 -1
  66. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/scripts/gemini_image_gen.py +118 -49
  67. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/__init__.py +9 -15
  68. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/auth_selector.py +15 -9
  69. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/compact_cmd.py +1 -1
  70. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/continue_cmd.py +1 -1
  71. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/debug_cmd.py +9 -14
  72. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/export_cmd.py +1 -1
  73. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/fork_session_cmd.py +1 -1
  74. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/model_cmd.py +1 -1
  75. klaude_code-2.21.0/src/klaude_code/tui/command/clear_cmd.py → klaude_code-2.22.0/src/klaude_code/tui/command/new_cmd.py +4 -4
  76. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/registry.py +1 -1
  77. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/status_cmd.py +61 -55
  78. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/sub_agent_model_cmd.py +1 -1
  79. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/thinking_cmd.py +1 -1
  80. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/command_output.py +56 -15
  81. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/developer.py +1 -1
  82. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/metadata.py +87 -12
  83. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/theme.py +14 -7
  84. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/tools.py +80 -20
  85. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/welcome.py +13 -4
  86. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/display.py +19 -1
  87. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/completers.py +107 -23
  88. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/images.py +0 -127
  89. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/key_bindings.py +1 -1
  90. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/prompt_toolkit.py +53 -2
  91. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/machine.py +22 -7
  92. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/renderer.py +1 -0
  93. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/runner.py +163 -49
  94. klaude_code-2.22.0/src/klaude_code/tui/terminal/ask_user_question.py +772 -0
  95. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/control.py +27 -0
  96. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/notifier.py +1 -0
  97. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/selector.py +63 -20
  98. klaude_code-2.21.0/src/klaude_code/tui/command/resume_cmd.py → klaude_code-2.22.0/src/klaude_code/tui/terminal/session_selector.py +0 -46
  99. klaude_code-2.21.0/src/klaude_code/.DS_Store +0 -0
  100. klaude_code-2.21.0/src/klaude_code/auth/copilot/token_manager.py +0 -27
  101. klaude_code-2.21.0/src/klaude_code/llm/image.py +0 -67
  102. klaude_code-2.21.0/src/klaude_code/protocol/sub_agent/AGENTS.md +0 -19
  103. klaude_code-2.21.0/src/klaude_code/skill/.DS_Store +0 -0
  104. klaude_code-2.21.0/src/klaude_code/skill/assets/.DS_Store +0 -0
  105. klaude_code-2.21.0/src/klaude_code/skill/assets/gpt-image-gen/.DS_Store +0 -0
  106. klaude_code-2.21.0/src/klaude_code/tui/command/export_online_cmd.py +0 -150
  107. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/__init__.py +0 -0
  108. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/app/__init__.py +0 -0
  109. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/app/runtime.py +0 -0
  110. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/AGENTS.md +0 -0
  111. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/__init__.py +0 -0
  112. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/base.py +0 -0
  113. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/claude/__init__.py +0 -0
  114. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/claude/exceptions.py +0 -0
  115. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/claude/oauth.py +0 -0
  116. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/claude/token_manager.py +0 -0
  117. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/codex/__init__.py +0 -0
  118. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/codex/exceptions.py +0 -0
  119. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  120. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/codex/oauth.py +0 -0
  121. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/codex/token_manager.py +0 -0
  122. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/copilot/__init__.py +0 -0
  123. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/copilot/exceptions.py +0 -0
  124. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/auth/env.py +0 -0
  125. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/__init__.py +0 -0
  126. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/config_cmd.py +0 -0
  127. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/cost_cmd.py +0 -0
  128. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/debug.py +0 -0
  129. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/cli/self_update.py +0 -0
  130. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/__init__.py +0 -0
  131. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/assets/__init__.py +0 -0
  132. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/config/model_matcher.py +0 -0
  133. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/const.py +0 -0
  134. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/__init__.py +0 -0
  135. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/bash_mode.py +0 -0
  136. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/compaction/AGENTS.md +0 -0
  137. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/compaction/__init__.py +0 -0
  138. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/compaction/compaction.py +0 -0
  139. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/compaction/overflow.py +0 -0
  140. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/compaction/prompts.py +0 -0
  141. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/loaded_skills.py +0 -0
  142. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/manager/__init__.py +0 -0
  143. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/prompts/auto-memory-prompt.md +0 -0
  144. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  145. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  146. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/rewind/__init__.py +0 -0
  147. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/rewind/manager.py +0 -0
  148. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/__init__.py +0 -0
  149. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/_utils.py +0 -0
  150. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  151. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  152. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  153. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  154. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  155. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  156. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  157. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/read_tool.py +0 -0
  158. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  159. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  160. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/offload.py +0 -0
  161. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  162. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/rewind_tool.py +0 -0
  163. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  164. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  165. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  166. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  167. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/__init__.py +0 -0
  168. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  169. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  170. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  171. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  172. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  173. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/tool_abc.py +0 -0
  174. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/tool_registry.py +0 -0
  175. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/tool_runner.py +0 -0
  176. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/__init__.py +0 -0
  177. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/external_content.py +0 -0
  178. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/ssrf.py +0 -0
  179. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/web_cache.py +0 -0
  180. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  181. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  182. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  183. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  184. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/__init__.py +0 -0
  185. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  186. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/bedrock_anthropic/__init__.py +0 -0
  187. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/bedrock_anthropic/client.py +0 -0
  188. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/claude/__init__.py +0 -0
  189. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/claude/client.py +0 -0
  190. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/client.py +0 -0
  191. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/copilot/__init__.py +0 -0
  192. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/google/__init__.py +0 -0
  193. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/google/client.py +0 -0
  194. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/google_vertex/__init__.py +0 -0
  195. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/google_vertex/client.py +0 -0
  196. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/json_stable.py +0 -0
  197. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_codex/__init__.py +0 -0
  198. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_codex/client.py +0 -0
  199. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  200. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_compatible/client.py +0 -0
  201. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  202. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
  203. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_responses/__init__.py +0 -0
  204. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openai_responses/client.py +0 -0
  205. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  206. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openrouter/client.py +0 -0
  207. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openrouter/input.py +0 -0
  208. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
  209. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/partial_message.py +0 -0
  210. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/stream_parts.py +0 -0
  211. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/llm/usage.py +0 -0
  212. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/log.py +0 -0
  213. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/model_id.py +0 -0
  214. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  215. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/__init__.py +0 -0
  216. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/codec.py +0 -0
  217. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/export.py +0 -0
  218. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/selector.py +0 -0
  219. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/store.py +0 -0
  220. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/session/templates/export_session.html +0 -0
  221. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/__init__.py +0 -0
  222. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  223. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/executing-plans/SKILL.md +0 -0
  224. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/frontend-design/SKILL.md +0 -0
  225. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/LICENSE.txt +0 -0
  226. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/SKILL.md +0 -0
  227. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/references/cli.md +0 -0
  228. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/references/codex-network.md +0 -0
  229. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/references/image-api.md +0 -0
  230. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/references/prompting.md +0 -0
  231. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/references/sample-prompts.md +0 -0
  232. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/gpt-image-gen/scripts/image_gen.py +0 -0
  233. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/nano-banana-image-gen/references/vertex-setup.md +0 -0
  234. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/SKILL.md +0 -0
  235. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/forms.md +0 -0
  236. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/reference.md +0 -0
  237. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/check_bounding_boxes.py +0 -0
  238. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/check_fillable_fields.py +0 -0
  239. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/convert_pdf_to_images.py +0 -0
  240. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/create_validation_image.py +0 -0
  241. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/extract_form_field_info.py +0 -0
  242. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/extract_form_structure.py +0 -0
  243. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/fill_fillable_fields.py +0 -0
  244. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/pdf/scripts/fill_pdf_form_with_annotations.py +0 -0
  245. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/render-mermaid/.gitignore +0 -0
  246. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/render-mermaid/SKILL.md +0 -0
  247. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/render-mermaid/bun.lock +0 -0
  248. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/render-mermaid/package.json +0 -0
  249. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/render-mermaid/scripts/render_mermaid.js +0 -0
  250. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/session-logs/SKILL.md +0 -0
  251. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  252. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/web-search/SKILL.md +0 -0
  253. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/assets/writing-plans/SKILL.md +0 -0
  254. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/loader.py +0 -0
  255. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/manager.py +0 -0
  256. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/skill/system_skills.py +0 -0
  257. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/__init__.py +0 -0
  258. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/command_abc.py +0 -0
  259. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/copy_cmd.py +0 -0
  260. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/login_cmd.py +0 -0
  261. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/logout_cmd.py +0 -0
  262. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/model_picker.py +0 -0
  263. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/prompt-init.md +0 -0
  264. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/prompt_command.py +0 -0
  265. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/command/refresh_cmd.py +0 -0
  266. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/commands.py +0 -0
  267. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/__init__.py +0 -0
  268. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/bash_syntax.py +0 -0
  269. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/common.py +0 -0
  270. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/diffs.py +0 -0
  271. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/errors.py +0 -0
  272. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/__init__.py +0 -0
  273. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/cjk_wrap.py +0 -0
  274. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/code_panel.py +0 -0
  275. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/live.py +0 -0
  276. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/markdown.py +0 -0
  277. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/quote.py +0 -0
  278. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/rich/status.py +0 -0
  279. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/sub_agent.py +0 -0
  280. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/thinking.py +0 -0
  281. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/components/user_input.py +0 -0
  282. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/AGENTS.md +0 -0
  283. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/__init__.py +0 -0
  284. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/drag_drop.py +0 -0
  285. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/input/paste.py +0 -0
  286. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/__init__.py +0 -0
  287. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/color.py +0 -0
  288. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/image.py +0 -0
  289. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/tui/terminal/progress_bar.py +0 -0
  290. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/__init__.py +0 -0
  291. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/common.py +0 -0
  292. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/core/__init__.py +0 -0
  293. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/core/display.py +0 -0
  294. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/core/input.py +0 -0
  295. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/terminal/__init__.py +0 -0
  296. {klaude_code-2.21.0 → klaude_code-2.22.0}/src/klaude_code/ui/terminal/title.py +0 -0
  297. {klaude_code-2.21.0 → klaude_code-2.22.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.21.0
3
+ Version: 2.22.0
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0,<6
@@ -9,7 +9,7 @@ Requires-Dist: diff-match-patch>=20241021
9
9
  Requires-Dist: filelock>=3.20.3
10
10
  Requires-Dist: google-genai>=1.56.0
11
11
  Requires-Dist: markdown-it-py>=4.0.0
12
- Requires-Dist: openai>=1.102.0
12
+ Requires-Dist: openai>=2.24.0
13
13
  Requires-Dist: prompt-toolkit>=3.0.52
14
14
  Requires-Dist: pydantic>=2.11.7
15
15
  Requires-Dist: python-socks>=2.8.1
@@ -29,7 +29,7 @@ Minimal code agent CLI.
29
29
  - **Keep reasoning item in context**: Interleaved thinking support
30
30
  - **Model-aware tools**: Claude Code tool set for Opus, `apply_patch` for GPT-5/Codex
31
31
  - **Reminders**: Cooldown-based todo tracking, instruction reinforcement and external file change reminder
32
- - **Sub-agents**: Task, Explore, Web
32
+ - **Sub-agents**: Task, Explore
33
33
  - **Structured sub-agent output**: Main agent defines JSON schema and get schema-compliant responses via constrained decoding
34
34
  - **Recursive `@file` mentions**: Circular dependency protection, relative path resolution
35
35
  - **External file sync**: Monitoring for external edits (linter, manual)
@@ -197,6 +197,21 @@ provider_list:
197
197
  - **Overriding**: Use the same `model_name` as a built-in model to override its parameters.
198
198
  - **Environment Variables**: Use `${VAR_NAME}` syntax for secrets.
199
199
 
200
+ ##### Sub-agent Model Configuration
201
+
202
+ `sub_agent_models` only accepts sub-agent types. Current supported keys are:
203
+
204
+ - `general-purpose` (Task sub-agent)
205
+ - `explore` (Explore sub-agent)
206
+
207
+ If a sub-agent type is not configured, it falls back to the main agent model.
208
+
209
+ ```yaml
210
+ sub_agent_models:
211
+ general-purpose: sonnet
212
+ explore: haiku
213
+ ```
214
+
200
215
  ##### Supported Protocols
201
216
 
202
217
  - `anthropic` - Anthropic Messages API
@@ -243,7 +258,6 @@ Inside the interactive session (`klaude`), use these commands to streamline your
243
258
  - `/resume` - Select and resume a previous session.
244
259
  - `/fork-session` - Fork current session to a new session ID (supports interactive fork point selection).
245
260
  - `/export` - Export last assistant message to a temp Markdown file.
246
- - `/export-online` - Export and deploy session to surge.sh as a static webpage.
247
261
  - `/debug [filters]` - Toggle debug mode and configure debug filters.
248
262
  - `/init` - Bootstrap a new project structure or module.
249
263
  - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
@@ -273,4 +287,3 @@ The main agent can spawn specialized sub-agents for specific tasks:
273
287
  |-----------|---------|
274
288
  | **Explore** | Fast codebase exploration - find files, search code, answer questions about the codebase |
275
289
  | **Task** | Handle complex multi-step tasks autonomously |
276
- | **WebAgent** | Search the web, fetch pages, and analyze content. Uses Brave LLM Context API when `BRAVE_API_KEY` is set, otherwise falls back to DuckDuckGo |
@@ -7,7 +7,7 @@ Minimal code agent CLI.
7
7
  - **Keep reasoning item in context**: Interleaved thinking support
8
8
  - **Model-aware tools**: Claude Code tool set for Opus, `apply_patch` for GPT-5/Codex
9
9
  - **Reminders**: Cooldown-based todo tracking, instruction reinforcement and external file change reminder
10
- - **Sub-agents**: Task, Explore, Web
10
+ - **Sub-agents**: Task, Explore
11
11
  - **Structured sub-agent output**: Main agent defines JSON schema and get schema-compliant responses via constrained decoding
12
12
  - **Recursive `@file` mentions**: Circular dependency protection, relative path resolution
13
13
  - **External file sync**: Monitoring for external edits (linter, manual)
@@ -175,6 +175,21 @@ provider_list:
175
175
  - **Overriding**: Use the same `model_name` as a built-in model to override its parameters.
176
176
  - **Environment Variables**: Use `${VAR_NAME}` syntax for secrets.
177
177
 
178
+ ##### Sub-agent Model Configuration
179
+
180
+ `sub_agent_models` only accepts sub-agent types. Current supported keys are:
181
+
182
+ - `general-purpose` (Task sub-agent)
183
+ - `explore` (Explore sub-agent)
184
+
185
+ If a sub-agent type is not configured, it falls back to the main agent model.
186
+
187
+ ```yaml
188
+ sub_agent_models:
189
+ general-purpose: sonnet
190
+ explore: haiku
191
+ ```
192
+
178
193
  ##### Supported Protocols
179
194
 
180
195
  - `anthropic` - Anthropic Messages API
@@ -221,7 +236,6 @@ Inside the interactive session (`klaude`), use these commands to streamline your
221
236
  - `/resume` - Select and resume a previous session.
222
237
  - `/fork-session` - Fork current session to a new session ID (supports interactive fork point selection).
223
238
  - `/export` - Export last assistant message to a temp Markdown file.
224
- - `/export-online` - Export and deploy session to surge.sh as a static webpage.
225
239
  - `/debug [filters]` - Toggle debug mode and configure debug filters.
226
240
  - `/init` - Bootstrap a new project structure or module.
227
241
  - `/dev-doc [feature]` - Generate a comprehensive execution plan for a feature.
@@ -251,4 +265,3 @@ The main agent can spawn specialized sub-agents for specific tasks:
251
265
  |-----------|---------|
252
266
  | **Explore** | Fast codebase exploration - find files, search code, answer questions about the codebase |
253
267
  | **Task** | Handle complex multi-step tasks autonomously |
254
- | **WebAgent** | Search the web, fetch pages, and analyze content. Uses Brave LLM Context API when `BRAVE_API_KEY` is set, otherwise falls back to DuckDuckGo |
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "2.21.0"
7
+ version = "2.22.0"
8
8
  description = "Minimal code agent CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -16,7 +16,7 @@ dependencies = [
16
16
  "filelock>=3.20.3",
17
17
  "google-genai>=1.56.0",
18
18
  "markdown-it-py>=4.0.0",
19
- "openai>=1.102.0",
19
+ "openai>=2.24.0",
20
20
  "prompt-toolkit>=3.0.52",
21
21
  "pydantic>=2.11.7",
22
22
  "python-socks>=2.8.1",
@@ -136,7 +136,7 @@ def execute_login(provider: str) -> None:
136
136
  except Exception as e:
137
137
  log((f"Login failed: {e}", "red"))
138
138
  raise typer.Exit(1) from None
139
- case "copilot":
139
+ case "github-copilot" | "copilot":
140
140
  from klaude_code.auth.copilot.oauth import CopilotOAuth
141
141
  from klaude_code.auth.copilot.token_manager import CopilotTokenManager
142
142
 
@@ -145,7 +145,7 @@ def execute_login(provider: str) -> None:
145
145
  if token_manager.is_logged_in():
146
146
  state = token_manager.get_state()
147
147
  if state and not state.is_expired():
148
- log(("You are already logged in to Copilot.", "green"))
148
+ log(("You are already logged in to GitHub Copilot.", "green"))
149
149
  domain = state.enterprise_domain or "github.com"
150
150
  expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
151
151
  log(f" Domain: {domain}")
@@ -232,18 +232,18 @@ def execute_logout(provider: str) -> None:
232
232
  if typer.confirm("Are you sure you want to logout from Claude?"):
233
233
  token_manager.delete()
234
234
  log(("Logged out from Claude.", "green"))
235
- case "copilot":
235
+ case "github-copilot" | "copilot":
236
236
  from klaude_code.auth.copilot.token_manager import CopilotTokenManager
237
237
 
238
238
  token_manager = CopilotTokenManager()
239
239
 
240
240
  if not token_manager.is_logged_in():
241
- log("You are not logged in to Copilot.")
241
+ log("You are not logged in to GitHub Copilot.")
242
242
  return
243
243
 
244
- if typer.confirm("Are you sure you want to logout from Copilot?"):
244
+ if typer.confirm("Are you sure you want to logout from GitHub Copilot?"):
245
245
  token_manager.delete()
246
- log(("Logged out from Copilot.", "green"))
246
+ log(("Logged out from GitHub Copilot.", "green"))
247
247
  case _:
248
- log((f"Error: Unknown provider '{provider}'. Supported: codex, claude, copilot", "red"))
248
+ log((f"Error: Unknown provider '{provider}'. Supported: codex, claude, github-copilot", "red"))
249
249
  raise typer.Exit(1)
@@ -86,6 +86,25 @@ body {
86
86
  flex: 1;
87
87
  letter-spacing: -0.01em;
88
88
  }
89
+ .nav-btn {
90
+ background: var(--bg-surface);
91
+ border: 1px solid var(--border);
92
+ color: var(--fg-secondary);
93
+ padding: 4px 10px;
94
+ border-radius: 6px;
95
+ font-size: 16px;
96
+ font-weight: 700;
97
+ font-family: var(--font-sans);
98
+ cursor: pointer;
99
+ transition: all 0.2s ease;
100
+ white-space: nowrap;
101
+ box-shadow: 0 1px 2px rgba(0,0,0,0.02);
102
+ }
103
+ .nav-btn:hover {
104
+ background: var(--bg-hover);
105
+ color: var(--fg);
106
+ border-color: var(--border-strong);
107
+ }
89
108
  #toolbar .filter-group {
90
109
  display: flex;
91
110
  gap: 6px;
@@ -379,6 +398,7 @@ body {
379
398
  <div id="container">
380
399
  <div id="left">
381
400
  <div id="toolbar">
401
+ <button class="nav-btn" id="btn-back-list" title="Back to log files">Logs</button>
382
402
  <span class="title" id="log-title">No log loaded</span>
383
403
  <input type="text" id="search-box" placeholder="Search... (/)">
384
404
  <div class="filter-group" id="filter-group"></div>
@@ -408,15 +428,76 @@ let selectedIdx = -1;
408
428
  let activeFilters = new Set();
409
429
  let searchQuery = '';
410
430
  let showRaw = false;
431
+ let viewerMode = 'files';
432
+
433
+ function setViewerMode(mode) {
434
+ viewerMode = mode;
435
+ const isLogMode = mode === 'log';
436
+ document.getElementById('btn-back-list').style.display = isLogMode ? '' : 'none';
437
+ document.getElementById('search-box').style.display = isLogMode ? '' : 'none';
438
+ document.getElementById('filter-group').style.display = isLogMode ? '' : 'none';
439
+ for (const id of ['btn-copy', 'btn-expand-all', 'btn-collapse-all', 'btn-raw']) {
440
+ document.getElementById(id).disabled = !isLogMode;
441
+ }
442
+ }
443
+
444
+ document.getElementById('btn-back-list').addEventListener('click', () => {
445
+ location.search = '';
446
+ });
447
+
448
+ async function loadLogList() {
449
+ setViewerMode('files');
450
+ const title = document.getElementById('log-title');
451
+ const list = document.getElementById('log-list');
452
+ const label = document.getElementById('right-label');
453
+ const view = document.getElementById('json-view');
454
+ title.textContent = 'Log files';
455
+ label.textContent = 'Select a log file';
456
+ view.innerHTML = '<span class="empty-hint">Choose a log file from the left list</span>';
457
+ list.innerHTML = '<div class="log-line"><span class="msg">Loading...</span></div>';
458
+
459
+ try {
460
+ const resp = await fetch('/api/logs');
461
+ if (!resp.ok) throw new Error(resp.statusText);
462
+ const files = await resp.json();
463
+ list.innerHTML = '';
464
+
465
+ if (files.length === 0) {
466
+ list.innerHTML = '<div class="log-line"><span class="msg">No log files found</span></div>';
467
+ return;
468
+ }
469
+
470
+ const frag = document.createDocumentFragment();
471
+ files.forEach((file, idx) => {
472
+ const div = document.createElement('div');
473
+ div.className = 'log-line';
474
+ const mtime = new Date(file.mtime * 1000).toLocaleString();
475
+ div.innerHTML =
476
+ '<span class="lineno">' + (idx + 1) + '</span>' +
477
+ '<span class="ts">' + esc(mtime) + '</span> ' +
478
+ '<span class="msg">' + esc(file.relative_path) + '</span> ' +
479
+ '<span class="json-inline">' + esc(formatBytes(file.size_bytes)) + '</span>';
480
+ div.addEventListener('click', () => {
481
+ location.search = '?log=' + encodeURIComponent(file.path);
482
+ });
483
+ frag.appendChild(div);
484
+ });
485
+ list.appendChild(frag);
486
+ } catch (e) {
487
+ title.textContent = 'Error: ' + e.message;
488
+ list.innerHTML = '<div class="log-line"><span class="msg">Failed to load log files</span></div>';
489
+ }
490
+ }
411
491
 
412
492
  // --- Data loading ---
413
493
  async function loadLog() {
414
494
  const params = new URLSearchParams(location.search);
415
495
  const logPath = params.get('log');
416
496
  if (!logPath) {
417
- document.getElementById('log-title').textContent = 'No log path specified';
497
+ await loadLogList();
418
498
  return;
419
499
  }
500
+ setViewerMode('log');
420
501
  document.getElementById('log-title').textContent = logPath.split('/').slice(-2).join('/');
421
502
  try {
422
503
  const resp = await fetch('/api/log?path=' + encodeURIComponent(logPath));
@@ -495,13 +576,28 @@ function toggleFilter(type, btn) {
495
576
  btn.classList.add('active');
496
577
  }
497
578
  applyFilters();
579
+
580
+ if (selectedIdx >= 0) {
581
+ const list = document.getElementById('log-list');
582
+ const selected = list.children[selectedIdx];
583
+ if (selected && !selected.classList.contains('hidden')) {
584
+ const listRect = list.getBoundingClientRect();
585
+ const rowRect = selected.getBoundingClientRect();
586
+ const fullyVisible = rowRect.top >= listRect.top && rowRect.bottom <= listRect.bottom;
587
+ if (!fullyVisible) {
588
+ selected.scrollIntoView({ block: 'center' });
589
+ }
590
+ }
591
+ }
498
592
  }
499
593
 
500
594
  function applyFilters() {
595
+ if (viewerMode !== 'log') return;
501
596
  const list = document.getElementById('log-list');
502
597
  const items = list.children;
503
598
  for (let i = 0; i < items.length; i++) {
504
599
  const entry = logLines[i];
600
+ if (!entry) continue;
505
601
  let visible = true;
506
602
  if (activeFilters.size > 0 && entry.type && !activeFilters.has(entry.type)) {
507
603
  visible = false;
@@ -776,11 +872,12 @@ document.getElementById('btn-raw').addEventListener('click', () => {
776
872
  // --- Search ---
777
873
  const searchBox = document.getElementById('search-box');
778
874
  searchBox.addEventListener('input', () => {
875
+ if (viewerMode !== 'log') return;
779
876
  searchQuery = searchBox.value.toLowerCase();
780
877
  applyFilters();
781
878
  });
782
879
  document.addEventListener('keydown', (e) => {
783
- if (e.key === '/' && document.activeElement !== searchBox) {
880
+ if (viewerMode === 'log' && e.key === '/' && document.activeElement !== searchBox) {
784
881
  e.preventDefault();
785
882
  searchBox.focus();
786
883
  }
@@ -788,16 +885,17 @@ document.addEventListener('keydown', (e) => {
788
885
  searchBox.value = '';
789
886
  searchQuery = '';
790
887
  searchBox.blur();
791
- applyFilters();
888
+ if (viewerMode === 'log') applyFilters();
792
889
  }
793
890
  // Arrow keys for navigation
794
- if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
891
+ if (viewerMode === 'log' && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
795
892
  e.preventDefault();
796
893
  navigateLine(e.key === 'ArrowDown' ? 1 : -1);
797
894
  }
798
895
  });
799
896
 
800
897
  function navigateLine(direction) {
898
+ if (viewerMode !== 'log') return;
801
899
  const list = document.getElementById('log-list');
802
900
  let next = selectedIdx + direction;
803
901
  // Skip hidden lines
@@ -952,6 +1050,11 @@ function badgeify(s) {
952
1050
  return esc(s).replace(/\[([\w.]+)\]/g, '<span class="badge">$1</span>');
953
1051
  }
954
1052
  function truncate(s, n) { return s.length <= n ? s : s.slice(0, n) + '...'; }
1053
+ function formatBytes(bytes) {
1054
+ if (bytes < 1024) return bytes + ' B';
1055
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
1056
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
1057
+ }
955
1058
 
956
1059
  // --- Init ---
957
1060
  buildFilters();
@@ -1,6 +1,7 @@
1
1
  """Minimal HTTP server for the debug log viewer."""
2
2
 
3
- import socket
3
+ import errno
4
+ import json
4
5
  import threading
5
6
  import webbrowser
6
7
  from http.server import BaseHTTPRequestHandler, HTTPServer
@@ -10,6 +11,7 @@ from urllib.parse import parse_qs, urlparse
10
11
  from klaude_code.const import DEFAULT_DEBUG_LOG_DIR
11
12
 
12
13
  _VIEWER_HTML = Path(__file__).parent / "log_viewer.html"
14
+ _DEFAULT_LOG_VIEWER_PORT = 8765
13
15
 
14
16
 
15
17
  class _LogViewerHandler(BaseHTTPRequestHandler):
@@ -27,6 +29,8 @@ class _LogViewerHandler(BaseHTTPRequestHandler):
27
29
  self._serve_log(paths[0])
28
30
  else:
29
31
  self._error(400, "missing path parameter")
32
+ elif parsed.path == "/api/logs":
33
+ self._serve_logs()
30
34
  else:
31
35
  self._error(404, "not found")
32
36
 
@@ -41,7 +45,7 @@ class _LogViewerHandler(BaseHTTPRequestHandler):
41
45
  def _serve_log(self, raw_path: str) -> None:
42
46
  log_path = Path(raw_path).resolve()
43
47
  log_dir = DEFAULT_DEBUG_LOG_DIR.resolve()
44
- if not str(log_path).startswith(str(log_dir)):
48
+ if not _is_path_within(log_path, log_dir):
45
49
  self._error(403, "access denied: path outside log directory")
46
50
  return
47
51
  if not log_path.is_file():
@@ -54,6 +58,15 @@ class _LogViewerHandler(BaseHTTPRequestHandler):
54
58
  self.end_headers()
55
59
  self.wfile.write(content)
56
60
 
61
+ def _serve_logs(self) -> None:
62
+ logs = _list_log_files(DEFAULT_DEBUG_LOG_DIR.resolve())
63
+ body = json.dumps(logs).encode()
64
+ self.send_response(200)
65
+ self.send_header("Content-Type", "application/json; charset=utf-8")
66
+ self.send_header("Content-Length", str(len(body)))
67
+ self.end_headers()
68
+ self.wfile.write(body)
69
+
57
70
  def _error(self, code: int, msg: str) -> None:
58
71
  body = msg.encode()
59
72
  self.send_response(code)
@@ -66,10 +79,61 @@ class _LogViewerHandler(BaseHTTPRequestHandler):
66
79
  pass
67
80
 
68
81
 
69
- def _find_free_port() -> int:
70
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
71
- s.bind(("127.0.0.1", 0))
72
- return s.getsockname()[1]
82
+ def _create_server_with_fallback(start_port: int) -> tuple[HTTPServer, int]:
83
+ for port in range(start_port, 65536):
84
+ try:
85
+ server = HTTPServer(("127.0.0.1", port), _LogViewerHandler)
86
+ except OSError as exc:
87
+ if exc.errno == errno.EADDRINUSE:
88
+ continue
89
+ raise
90
+ return server, port
91
+ raise RuntimeError(f"no available port from {start_port} to 65535")
92
+
93
+
94
+ def _is_path_within(path: Path, root: Path) -> bool:
95
+ try:
96
+ path.relative_to(root)
97
+ return True
98
+ except ValueError:
99
+ return False
100
+
101
+
102
+ def _list_log_files(log_dir: Path) -> list[dict[str, object]]:
103
+ if not log_dir.exists():
104
+ return []
105
+
106
+ files: list[tuple[float, dict[str, object]]] = []
107
+ seen_paths: set[Path] = set()
108
+ for path in log_dir.rglob("*.log"):
109
+ if not path.is_file():
110
+ continue
111
+
112
+ try:
113
+ stat = path.stat()
114
+ resolved = path.resolve()
115
+ relative_path = str(resolved.relative_to(log_dir))
116
+ except (OSError, ValueError):
117
+ continue
118
+
119
+ if resolved in seen_paths:
120
+ continue
121
+ seen_paths.add(resolved)
122
+
123
+ files.append(
124
+ (
125
+ stat.st_mtime,
126
+ {
127
+ "path": str(resolved),
128
+ "relative_path": relative_path,
129
+ "size_bytes": stat.st_size,
130
+ "mtime": stat.st_mtime,
131
+ },
132
+ )
133
+ )
134
+
135
+ files.sort(key=lambda item: item[0], reverse=True)
136
+ return [item[1] for item in files]
73
137
 
74
138
 
75
139
  def start_log_viewer(log_path: Path) -> str:
@@ -77,8 +141,7 @@ def start_log_viewer(log_path: Path) -> str:
77
141
 
78
142
  Returns the URL of the viewer.
79
143
  """
80
- port = _find_free_port()
81
- server = HTTPServer(("127.0.0.1", port), _LogViewerHandler)
144
+ server, port = _create_server_with_fallback(_DEFAULT_LOG_VIEWER_PORT)
82
145
  thread = threading.Thread(target=server.serve_forever, daemon=True)
83
146
  thread.start()
84
147
 
@@ -224,7 +224,9 @@ class CopilotOAuth:
224
224
  """Ensure we have a valid Copilot token and return (token, base_url)."""
225
225
  state = self.token_manager.get_state()
226
226
  if state is None:
227
- raise CopilotNotLoggedInError("Not logged in to Copilot. Run 'klaude auth login copilot' first.")
227
+ raise CopilotNotLoggedInError(
228
+ "Not logged in to GitHub Copilot. Run 'klaude auth login github-copilot' first."
229
+ )
228
230
 
229
231
  if state.is_expired():
230
232
  state = self.refresh()
@@ -0,0 +1,64 @@
1
+ """Token storage and management for GitHub Copilot authentication."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any, cast
5
+
6
+ from klaude_code.auth.base import BaseAuthState, BaseTokenManager
7
+
8
+
9
+ class CopilotAuthState(BaseAuthState):
10
+ """Stored authentication state for GitHub Copilot."""
11
+
12
+ enterprise_domain: str | None = None
13
+ copilot_base_url: str = "https://api.individual.githubcopilot.com"
14
+
15
+
16
+ class CopilotTokenManager(BaseTokenManager[CopilotAuthState]):
17
+ """Manage GitHub Copilot OAuth tokens."""
18
+
19
+ _LEGACY_STORAGE_KEY = "copilot"
20
+
21
+ def __init__(self, auth_file: Path | None = None):
22
+ super().__init__(auth_file)
23
+
24
+ @property
25
+ def storage_key(self) -> str:
26
+ return "github-copilot"
27
+
28
+ def load(self) -> CopilotAuthState | None:
29
+ state = super().load()
30
+ if state is not None:
31
+ return state
32
+
33
+ store = self._load_store()
34
+ legacy_data = store.get(self._LEGACY_STORAGE_KEY)
35
+ if not isinstance(legacy_data, dict):
36
+ return None
37
+ legacy_payload = cast(dict[str, Any], legacy_data)
38
+
39
+ try:
40
+ migrated = self._create_state(legacy_payload)
41
+ except ValueError:
42
+ return None
43
+
44
+ store[self.storage_key] = migrated.model_dump(mode="json")
45
+ store.pop(self._LEGACY_STORAGE_KEY, None)
46
+ self._save_store(store)
47
+ self._state = migrated
48
+ return migrated
49
+
50
+ def delete(self) -> None:
51
+ store = self._load_store()
52
+ store.pop(self.storage_key, None)
53
+ store.pop(self._LEGACY_STORAGE_KEY, None)
54
+
55
+ if len(store) == 0:
56
+ if self.auth_file.exists():
57
+ self.auth_file.unlink()
58
+ else:
59
+ self._save_store(store)
60
+
61
+ self._state = None
62
+
63
+ def _create_state(self, data: dict[str, Any]) -> CopilotAuthState:
64
+ return CopilotAuthState.model_validate(data)
@@ -9,7 +9,7 @@ from klaude_code.tui.command.auth_selector import select_provider
9
9
  def _build_provider_help() -> str:
10
10
  from klaude_code.config.builtin_config import SUPPORTED_API_KEYS
11
11
 
12
- names = ["codex", "claude", "copilot"] + [k.name.split()[0].lower() for k in SUPPORTED_API_KEYS]
12
+ names = ["codex", "claude", "github-copilot", "copilot"] + [k.name.split()[0].lower() for k in SUPPORTED_API_KEYS]
13
13
  return f"Provider name ({', '.join(names)})"
14
14
 
15
15
 
@@ -26,7 +26,7 @@ def login_command(
26
26
 
27
27
 
28
28
  def logout_command(
29
- provider: str | None = typer.Argument(None, help="Provider to logout (codex|claude|copilot)"),
29
+ provider: str | None = typer.Argument(None, help="Provider to logout (codex|claude|github-copilot|copilot)"),
30
30
  ) -> None:
31
31
  """Logout from a provider."""
32
32
  if provider is None: