kolega-code 0.2.0__tar.gz → 0.3.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 (220) hide show
  1. {kolega_code-0.2.0 → kolega_code-0.3.0}/.env.example +2 -0
  2. {kolega_code-0.2.0 → kolega_code-0.3.0}/PKG-INFO +6 -2
  3. {kolega_code-0.2.0 → kolega_code-0.3.0}/README.md +4 -1
  4. {kolega_code-0.2.0 → kolega_code-0.3.0}/RELEASING.md +2 -2
  5. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/cli/doctor.md +3 -0
  6. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/cli/overview.md +3 -1
  7. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/configuration/environment-variables.md +8 -2
  8. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/configuration/providers-and-models.mdx +20 -0
  9. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/getting-started/installation.mdx +9 -2
  10. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/tui/sessions-and-resume.md +1 -1
  11. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/tui/slash-commands.md +2 -0
  12. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/__init__.py +1 -1
  13. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/__init__.py +1 -1
  14. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_thinking_effort.py +44 -0
  15. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/app.py +47 -2
  16. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/config.py +4 -0
  17. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/main.py +33 -3
  18. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/messages.py +4 -0
  19. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/provider_registry.py +9 -0
  20. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/slash_commands.py +2 -0
  21. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_app.py +67 -2
  22. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_main.py +88 -9
  23. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_slash_commands.py +2 -0
  24. kolega_code-0.3.0/kolega_code/cli/tests/test_updater.py +87 -0
  25. kolega_code-0.3.0/kolega_code/cli/updater.py +102 -0
  26. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/config.py +6 -0
  27. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/client.py +4 -0
  28. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/instrumented_client.py +3 -3
  29. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/anthropic.py +1 -1
  30. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/specs.py +45 -0
  31. {kolega_code-0.2.0 → kolega_code-0.3.0}/pyproject.toml +2 -1
  32. {kolega_code-0.2.0 → kolega_code-0.3.0}/scripts/install-kolega-code.sh +1 -1
  33. {kolega_code-0.2.0 → kolega_code-0.3.0}/uv.lock +55 -53
  34. {kolega_code-0.2.0 → kolega_code-0.3.0}/.github/workflows/ci.yml +0 -0
  35. {kolega_code-0.2.0 → kolega_code-0.3.0}/.github/workflows/docs.yml +0 -0
  36. {kolega_code-0.2.0 → kolega_code-0.3.0}/.github/workflows/release.yml +0 -0
  37. {kolega_code-0.2.0 → kolega_code-0.3.0}/.gitignore +0 -0
  38. {kolega_code-0.2.0 → kolega_code-0.3.0}/CONTRIBUTING.md +0 -0
  39. {kolega_code-0.2.0 → kolega_code-0.3.0}/LICENSE +0 -0
  40. {kolega_code-0.2.0 → kolega_code-0.3.0}/SECURITY.md +0 -0
  41. {kolega_code-0.2.0 → kolega_code-0.3.0}/conftest.py +0 -0
  42. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/.gitignore +0 -0
  43. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/README.md +0 -0
  44. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/astro.config.mjs +0 -0
  45. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/package-lock.json +0 -0
  46. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/package.json +0 -0
  47. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/public/favicon.svg +0 -0
  48. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/assets/kolega-dark.svg +0 -0
  49. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/assets/kolega-light.svg +0 -0
  50. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/cli/ask.md +0 -0
  51. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/cli/sessions.md +0 -0
  52. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/concepts/agents.md +0 -0
  53. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/concepts/how-it-works.md +0 -0
  54. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/concepts/tools.md +0 -0
  55. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/configuration/settings-and-api-keys.mdx +0 -0
  56. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/getting-started/introduction.md +0 -0
  57. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/getting-started/quick-start.mdx +0 -0
  58. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/index.mdx +0 -0
  59. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/skills.mdx +0 -0
  60. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/tui/composer.md +0 -0
  61. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/tui/interface.md +0 -0
  62. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content/docs/tui/modes.md +0 -0
  63. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/content.config.ts +0 -0
  64. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/src/styles/brand.css +0 -0
  65. {kolega_code-0.2.0 → kolega_code-0.3.0}/docs/tsconfig.json +0 -0
  66. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/baseagent.py +0 -0
  67. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/browseragent.py +0 -0
  68. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/coder.py +0 -0
  69. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/common.py +0 -0
  70. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/compression.py +0 -0
  71. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/context.py +0 -0
  72. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/conversation.py +0 -0
  73. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/generalagent.py +0 -0
  74. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/investigationagent.py +0 -0
  75. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/planningagent.py +0 -0
  76. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_provider.py +0 -0
  77. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/agents/browser.j2 +0 -0
  78. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/agents/coder_cli_mode.j2 +0 -0
  79. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/agents/general.j2 +0 -0
  80. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/agents/investigation.j2 +0 -0
  81. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/common/frontend_guidance.md +0 -0
  82. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/common/kolega_md_instructions.md +0 -0
  83. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/environment_variables/workspace_env_vars.md +0 -0
  84. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/template_guidance/expo-template.md +0 -0
  85. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/template_guidance/html-website-template.md +0 -0
  86. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/template_guidance/mern-stack-template.md +0 -0
  87. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompt_templates/template_guidance/react-vite-shadcdn-template.md +0 -0
  88. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/prompts.py +0 -0
  89. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/__init__.py +0 -0
  90. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/__init__.py +0 -0
  91. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_anthropic_token_counting.py +0 -0
  92. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_billing_openai_cache.py +0 -0
  93. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_client.py +0 -0
  94. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_dashscope_mapping.py +0 -0
  95. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_error_boundary.py +0 -0
  96. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_exceptions.py +0 -0
  97. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_google_thought_signature.py +0 -0
  98. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_google_tool_signature_live.py +0 -0
  99. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_instrumented_client.py +0 -0
  100. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_instrumented_client_integration.py +0 -0
  101. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_langfuse_normalization.py +0 -0
  102. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_live_providers.py +0 -0
  103. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_model_specs.py +0 -0
  104. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_openai_cached_tokens.py +0 -0
  105. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_openai_cached_tokens_stream.py +0 -0
  106. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_openai_message_conversion.py +0 -0
  107. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_openai_token_counting.py +0 -0
  108. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/llm/test_tool_execution_ids.py +0 -0
  109. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/__init__.py +0 -0
  110. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_browser.py +0 -0
  111. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_browser_parity.py +0 -0
  112. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_file_system.py +0 -0
  113. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_sandbox_terminal_input.py +0 -0
  114. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_terminal.py +0 -0
  115. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_terminal_command_tracking.py +0 -0
  116. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/services/test_terminal_state_serializer.py +0 -0
  117. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_agent_tools_inventory.py +0 -0
  118. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_base_agent.py +0 -0
  119. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_coder_attachments.py +0 -0
  120. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_coder_prompt_extensions.py +0 -0
  121. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_commands.py +0 -0
  122. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_duplicate_tool_results.py +0 -0
  123. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_empty_message_handling.py +0 -0
  124. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_general_agent.py +0 -0
  125. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_html.py +0 -0
  126. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_parallel_tool_calls.py +0 -0
  127. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_planning_agent.py +0 -0
  128. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_prompt_provider.py +0 -0
  129. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_tool_registry.py +0 -0
  130. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/test_tools.py +0 -0
  131. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/__init__.py +0 -0
  132. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_agent_tool.py +0 -0
  133. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_base_tool.py +0 -0
  134. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_browser_tool.py +0 -0
  135. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_build_tool.py +0 -0
  136. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_create_file_tool.py +0 -0
  137. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_glob_tool.py +0 -0
  138. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_glob_tool_sandbox_parity.py +0 -0
  139. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_list_directory_tool.py +0 -0
  140. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_read_file_tool.py +0 -0
  141. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_replace_entire_file_tool.py +0 -0
  142. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_replace_lines_tool.py +0 -0
  143. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_search_and_replace_tool.py +0 -0
  144. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_search_codebase_tool.py +0 -0
  145. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_terminal_tool.py +0 -0
  146. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_think_hard_integration.py +0 -0
  147. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_think_hard_streaming.py +0 -0
  148. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tests/tool_backend/test_web_fetch_tool.py +0 -0
  149. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/agent_tool.py +0 -0
  150. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/apply_patch_tool.py +0 -0
  151. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/base_tool.py +0 -0
  152. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/browser_tool.py +0 -0
  153. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/build_tool.py +0 -0
  154. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/create_file_tool.py +0 -0
  155. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/glob_tool.py +0 -0
  156. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/list_directory_tool.py +0 -0
  157. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/memory_tool.py +0 -0
  158. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/read_file_tool.py +0 -0
  159. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/replace_entire_file_tool.py +0 -0
  160. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/replace_lines_tool.py +0 -0
  161. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/search_and_replace_tool.py +0 -0
  162. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/search_codebase_tool.py +0 -0
  163. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/streaming_tool.py +0 -0
  164. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/terminal_tool.py +0 -0
  165. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/think_hard_tool.py +0 -0
  166. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tool_backend/web_fetch_tool.py +0 -0
  167. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/tools.py +0 -0
  168. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/agent/utils/commands.py +0 -0
  169. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/__init__.py +0 -0
  170. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/connection.py +0 -0
  171. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/file_index.py +0 -0
  172. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/mentions.py +0 -0
  173. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/session_store.py +0 -0
  174. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/settings.py +0 -0
  175. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/skills.py +0 -0
  176. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/__init__.py +0 -0
  177. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_cli_config.py +0 -0
  178. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_connection.py +0 -0
  179. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_file_index.py +0 -0
  180. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_mentions.py +0 -0
  181. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_session_store.py +0 -0
  182. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_settings.py +0 -0
  183. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/tests/test_skills.py +0 -0
  184. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/cli/theme.py +0 -0
  185. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/events.py +0 -0
  186. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/exceptions.py +0 -0
  187. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/models.py +0 -0
  188. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/__init__.py +0 -0
  189. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/base.py +0 -0
  190. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/google.py +0 -0
  191. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/models.py +0 -0
  192. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/providers/openai.py +0 -0
  193. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/ratelimit.py +0 -0
  194. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/llm/tool_execution_ids.py +0 -0
  195. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/models/__init__.py +0 -0
  196. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/models/sandbox_terminal_state.py +0 -0
  197. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/runtime.py +0 -0
  198. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/README.md +0 -0
  199. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/__init__.py +0 -0
  200. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/async_filesystem.py +0 -0
  201. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/base.py +0 -0
  202. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/browser.py +0 -0
  203. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/event_loop.py +0 -0
  204. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/filesystem.py +0 -0
  205. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/local.py +0 -0
  206. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/serializer.py +0 -0
  207. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/terminal.py +0 -0
  208. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/sandbox/utils.py +0 -0
  209. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/services/base.py +0 -0
  210. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/services/browser.py +0 -0
  211. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/services/file_system.py +0 -0
  212. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/services/html.py +0 -0
  213. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/services/terminal.py +0 -0
  214. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/__init__.py +0 -0
  215. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/core.py +0 -0
  216. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/definitions.py +0 -0
  217. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/registry.py +0 -0
  218. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/tests/__init__.py +0 -0
  219. {kolega_code-0.2.0 → kolega_code-0.3.0}/kolega_code/tools/tests/test_definitions.py +0 -0
  220. {kolega_code-0.2.0 → kolega_code-0.3.0}/run_tests.sh +0 -0
@@ -6,6 +6,8 @@ OPENAI_API_KEY=
6
6
  GOOGLE_API_KEY=
7
7
  MOONSHOT_API_KEY=
8
8
  DEEPSEEK_API_KEY=
9
+ ZAI_API_KEY=
10
+ KIMI_CODING_API_KEY=
9
11
 
10
12
  KOLEGA_CODE_THINKING_EFFORT=
11
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kolega-code
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Local-first AI coding agent for the terminal
5
5
  Project-URL: Homepage, https://kolega-ai.github.io/kolega-code/
6
6
  Project-URL: Documentation, https://kolega-ai.github.io/kolega-code/
@@ -49,6 +49,7 @@ Requires-Dist: jinja2==3.1.6
49
49
  Requires-Dist: langfuse==3.14.5
50
50
  Requires-Dist: nest-asyncio==1.6.0
51
51
  Requires-Dist: openai==1.109.1
52
+ Requires-Dist: packaging==25.0
52
53
  Requires-Dist: pathspec==1.1.1
53
54
  Requires-Dist: playwright==1.59.0
54
55
  Requires-Dist: psutil==7.2.2
@@ -96,10 +97,13 @@ kolega-code --version
96
97
  Upgrade or uninstall:
97
98
 
98
99
  ```bash
99
- uv tool upgrade kolega-code
100
+ kolega-code update
100
101
  uv tool uninstall kolega-code
101
102
  ```
102
103
 
104
+ Running the installer again also updates an existing install to the latest
105
+ released version.
106
+
103
107
  Run the Textual UI and open the Settings tab to pick any provider and model from the catalog, choose the model's thinking effort, and save your API key:
104
108
 
105
109
  ```bash
@@ -28,10 +28,13 @@ kolega-code --version
28
28
  Upgrade or uninstall:
29
29
 
30
30
  ```bash
31
- uv tool upgrade kolega-code
31
+ kolega-code update
32
32
  uv tool uninstall kolega-code
33
33
  ```
34
34
 
35
+ Running the installer again also updates an existing install to the latest
36
+ released version.
37
+
35
38
  Run the Textual UI and open the Settings tab to pick any provider and model from the catalog, choose the model's thinking effort, and save your API key:
36
39
 
37
40
  ```bash
@@ -29,8 +29,8 @@ the organization request.
29
29
  4. Create and push a matching tag:
30
30
 
31
31
  ```bash
32
- git tag v0.2.0
33
- git push origin v0.2.0
32
+ git tag v0.3.0
33
+ git push origin v0.3.0
34
34
  ```
35
35
 
36
36
  5. Approve the `pypi` environment deployment in GitHub Actions.
@@ -33,6 +33,8 @@ you can validate a specific provider/model combination before using it.
33
33
  itself is never printed).
34
34
  - **Configuration** — whether a valid `AgentConfig` can be built. If valid, it
35
35
  prints the resolved **long**, **fast**, and **thinking** models.
36
+ - **Update** — whether the installed CLI is current or a newer PyPI release is
37
+ available.
36
38
 
37
39
  ## Example output
38
40
 
@@ -40,6 +42,7 @@ you can validate a specific provider/model combination before using it.
40
42
  Project: /Users/you/code/my-app
41
43
  State dir: /Users/you/Library/Application Support/kolega-code
42
44
  Textual installed: True
45
+ Update: Kolega Code is up to date (0.3.0).
43
46
  Stored active model: moonshot/kimi-k2.7-code
44
47
  Stored thinking effort: auto
45
48
  Stored API key: present in local settings
@@ -6,7 +6,7 @@ description: Invocation forms, global options, and the command surface of kolega
6
6
  The `kolega-code` command has two shapes:
7
7
 
8
8
  - **No subcommand** → launches the interactive [Terminal UI](../../tui/interface/).
9
- - **A subcommand** (`ask`, `sessions`, `doctor`) → runs a specific non-interactive
9
+ - **A subcommand** (`ask`, `sessions`, `doctor`, `update`) → runs a specific non-interactive
10
10
  task.
11
11
 
12
12
  ```bash
@@ -14,6 +14,7 @@ kolega-code [PROJECT_PATH] [options] # interactive TUI
14
14
  kolega-code ask "<prompt>" [options] # one-shot prompt
15
15
  kolega-code sessions <list|delete|export> [options]
16
16
  kolega-code doctor [options]
17
+ kolega-code update
17
18
  ```
18
19
 
19
20
  ## Commands
@@ -24,6 +25,7 @@ kolega-code doctor [options]
24
25
  | [`ask`](../ask/) | Run a single prompt and print the answer |
25
26
  | [`sessions`](../sessions/) | List, delete, or export saved sessions |
26
27
  | [`doctor`](../doctor/) | Check local configuration and API-key status |
28
+ | `update` | Update Kolega Code to the latest released version |
27
29
 
28
30
  ## Launching the TUI
29
31
 
@@ -44,8 +44,14 @@ provider or model.
44
44
  | `DASHSCOPE_API_KEY` | DashScope (Alibaba) |
45
45
  | `MOONSHOT_API_KEY` | Moonshot |
46
46
  | `DEEPSEEK_API_KEY` | DeepSeek |
47
-
48
- The local `llama` provider needs no key.
47
+ | `ZAI_API_KEY` | Z.AI (GLM Coding Plan) |
48
+ | `KIMI_CODING_API_KEY` | Kimi Coding Plan |
49
+
50
+ The local `llama` provider needs no key. The `zai` key authenticates against Z.AI's
51
+ Anthropic-compatible endpoint (it is the key Z.AI also documents as `ANTHROPIC_AUTH_TOKEN`).
52
+ The `kimi_coding` key authenticates against the Kimi Coding Plan's separate
53
+ Anthropic-compatible endpoint (`https://api.kimi.com/coding/`), which is distinct from the
54
+ standard Moonshot API used by the `moonshot` provider.
49
55
 
50
56
  ## Model selection
51
57
 
@@ -24,8 +24,26 @@ The agent runtime recognizes these providers:
24
24
  | DashScope (Alibaba) | `dashscope` | `DASHSCOPE_API_KEY` |
25
25
  | Moonshot (Kimi) | `moonshot` | `MOONSHOT_API_KEY` |
26
26
  | DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` |
27
+ | Z.AI (GLM Coding Plan) | `zai` | `ZAI_API_KEY` |
28
+ | Kimi Coding Plan | `kimi_coding` | `KIMI_CODING_API_KEY` |
27
29
  | Llama (local) | `llama` | _none — local model_ |
28
30
 
31
+ <Aside type="tip">
32
+ **Z.AI GLM Coding Plan.** The `zai` provider targets Z.AI's Anthropic-compatible
33
+ endpoint (`https://api.z.ai/api/anthropic`) and exposes **GLM-5.2** (default) and
34
+ **GLM-5.1**. Set `ZAI_API_KEY` to your GLM Coding Plan key (the key Z.AI also
35
+ documents as `ANTHROPIC_AUTH_TOKEN`).
36
+ </Aside>
37
+
38
+ <Aside type="tip">
39
+ **Kimi Coding Plan.** The `kimi_coding` provider targets Kimi's Anthropic-compatible
40
+ coding endpoint (`https://api.kimi.com/coding/`), which is separate from the standard
41
+ Moonshot API used by the `moonshot` provider. It exposes a single stable model ID,
42
+ **`kimi-for-coding`**, that the backend auto-routes to the latest underlying model:
43
+ with thinking effort `auto` (enabled) requests route to **K2.7 Code**, and with `none`
44
+ (disabled) they route to **K2.6**. Set `KIMI_CODING_API_KEY` to your Kimi Coding Plan key.
45
+ </Aside>
46
+
29
47
  <Aside type="note">
30
48
  The **Settings tab** in the TUI currently offers a curated shortlist —
31
49
  **Moonshot (Kimi K2.7 Code and Kimi K2.6)** and **DeepSeek (DeepSeek V4 Pro)**.
@@ -96,6 +114,8 @@ models in the TUI.
96
114
  | DeepSeek `deepseek-v4-pro` | `none`, `high`, `max` | `high` |
97
115
  | Moonshot `kimi-k2.7-code` | `auto` | `auto` |
98
116
  | Moonshot `kimi-k2.6` | `auto`, `none` | `auto` |
117
+ | Z.AI `glm-5.2` | `high`, `max` | `max` |
118
+ | Z.AI `glm-5.1` | `auto`, `none` | `auto` |
99
119
  | Google `gemini-2.5-pro` | `auto`, `low`, `medium`, `high` | `medium` |
100
120
  | OpenAI reasoning models | `low`, `medium`, `high` | `medium` |
101
121
 
@@ -58,10 +58,17 @@ present. See [`doctor`](../../cli/doctor/) for details.
58
58
 
59
59
  ## Upgrade or uninstall
60
60
 
61
- If you installed with the script or `uv tool install`, manage the CLI with uv:
61
+ If you installed with the script or `uv tool install`, update the CLI with the
62
+ built-in command:
63
+
64
+ ```bash
65
+ kolega-code update
66
+ ```
67
+
68
+ Running the installer again also updates an existing install to the latest
69
+ released version. To uninstall, use uv:
62
70
 
63
71
  ```bash
64
- uv tool upgrade kolega-code
65
72
  uv tool uninstall kolega-code
66
73
  ```
67
74
 
@@ -10,7 +10,7 @@ task list. Sessions let you stop and resume work later.
10
10
  ## How sessions are created
11
11
 
12
12
  - **In the TUI**, launching `kolega-code .` starts a **fresh session by default**.
13
- Your work is saved when you quit (`Ctrl+Q` or `/quit`).
13
+ Your work is saved when you quit (`Ctrl+Q`, `/quit`, or `/exit`).
14
14
  - **With `ask`**, a session is only persisted if you pass `--save` or `--session`.
15
15
  See [`kolega-code ask`](../../cli/ask/).
16
16
 
@@ -39,7 +39,9 @@ These control the app and your session.
39
39
  | `/effort` | Choose the active model's thinking effort |
40
40
  | `/copy` | Copy the last response to the clipboard |
41
41
  | `/version` | Show the Kolega Code version |
42
+ | `/update` | Update Kolega Code to the latest version |
42
43
  | `/quit` | Save the session and exit |
44
+ | `/exit` | Save the session and exit |
43
45
 
44
46
  Run `/model` to open a selectable list of supported models for the current
45
47
  provider. You can also switch directly with `/model <name>`.
@@ -148,4 +148,4 @@ __all__ = [
148
148
  "parse_git_status_output",
149
149
  ]
150
150
 
151
- __version__ = "0.2.0"
151
+ __version__ = "0.3.0"
@@ -39,4 +39,4 @@ __all__ = [
39
39
  "ToolExtension",
40
40
  ]
41
41
 
42
- __version__ = "0.2.0"
42
+ __version__ = "0.3.0"
@@ -17,6 +17,12 @@ def test_model_specs_expose_provider_specific_thinking_efforts() -> None:
17
17
  assert default_thinking_effort("deepseek", "deepseek-v4-pro") == "high"
18
18
  assert thinking_effort_options("google", "gemini-3.1-pro-preview") == ("low", "medium", "high")
19
19
  assert default_thinking_effort("google", "gemini-3.1-pro-preview") == "high"
20
+ assert thinking_effort_options("zai", "glm-5.2") == ("high", "max")
21
+ assert default_thinking_effort("zai", "glm-5.2") == "max"
22
+ assert thinking_effort_options("zai", "glm-5.1") == ("auto", "none")
23
+ assert default_thinking_effort("zai", "glm-5.1") == "auto"
24
+ assert thinking_effort_options("kimi_coding", "kimi-for-coding") == ("auto", "none")
25
+ assert default_thinking_effort("kimi_coding", "kimi-for-coding") == "auto"
20
26
 
21
27
 
22
28
  def test_anthropic_opus_effort_uses_adaptive_thinking_without_budget_tokens() -> None:
@@ -48,6 +54,32 @@ def test_deepseek_thinking_effort_serialization() -> None:
48
54
  assert max_params["output_config"] == {"effort": "max"}
49
55
 
50
56
 
57
+ def test_zai_glm52_thinking_effort_serialization() -> None:
58
+ provider = AnthropicProvider(api_key="test-key", provider_name="zai")
59
+
60
+ max_params = {"model": "glm-5.2"}
61
+ provider._apply_thinking_params(max_params, GenerationParams(thinking="max"))
62
+ assert max_params["thinking"] == {"type": "enabled"}
63
+ assert max_params["output_config"] == {"effort": "max"}
64
+
65
+ high_params = {"model": "glm-5.2"}
66
+ provider._apply_thinking_params(high_params, GenerationParams(thinking="high"))
67
+ assert high_params["output_config"] == {"effort": "high"}
68
+
69
+
70
+ def test_zai_glm51_thinking_toggle_serialization() -> None:
71
+ provider = AnthropicProvider(api_key="test-key", provider_name="zai")
72
+
73
+ auto_params = {"model": "glm-5.1"}
74
+ provider._apply_thinking_params(auto_params, GenerationParams(thinking="auto"))
75
+ # GLM-5.1 is a plain toggle — no output_config.effort field.
76
+ assert auto_params == {"model": "glm-5.1", "thinking": {"type": "enabled"}}
77
+
78
+ disabled_params = {"model": "glm-5.1"}
79
+ provider._apply_thinking_params(disabled_params, GenerationParams(thinking="none"))
80
+ assert disabled_params == {"model": "glm-5.1", "thinking": {"type": "disabled"}}
81
+
82
+
51
83
  def test_moonshot_kimi_thinking_toggle_serialization() -> None:
52
84
  provider = AnthropicProvider(api_key="test-key", provider_name="moonshot")
53
85
 
@@ -64,6 +96,18 @@ def test_moonshot_kimi_thinking_toggle_serialization() -> None:
64
96
  assert disabled_params == {"model": "kimi-k2.6", "thinking": {"type": "disabled"}}
65
97
 
66
98
 
99
+ def test_kimi_coding_thinking_toggle_serialization() -> None:
100
+ provider = AnthropicProvider(api_key="test-key", provider_name="kimi_coding")
101
+
102
+ enabled = {"model": "kimi-for-coding"}
103
+ provider._apply_thinking_params(enabled, GenerationParams(thinking="auto"))
104
+ assert enabled == {"model": "kimi-for-coding", "thinking": {"type": "enabled"}}
105
+
106
+ disabled = {"model": "kimi-for-coding"}
107
+ provider._apply_thinking_params(disabled, GenerationParams(thinking="none"))
108
+ assert disabled == {"model": "kimi-for-coding", "thinking": {"type": "disabled"}}
109
+
110
+
67
111
  def test_google_gemini_3_pro_uses_thinking_level() -> None:
68
112
  provider = GoogleProvider(api_key="test-key")
69
113
 
@@ -47,7 +47,6 @@ from textual.widgets import (
47
47
  )
48
48
  from textual.widgets.option_list import Option
49
49
 
50
- from kolega_code import __version__ as kolega_code_version
51
50
  from kolega_code.agent import AgentConfig, AgentEvent, CoderAgent, PlanningAgent, PromptExtension, ToolExtension
52
51
  from kolega_code.llm.exceptions import LLMError, llm_error_message
53
52
  from kolega_code.llm.models import Message, MessageHistory, TextBlock, ToolCall, ToolResult
@@ -81,6 +80,7 @@ from .slash_commands import (
81
80
  agent_command_names,
82
81
  search_commands,
83
82
  )
83
+ from .updater import check_for_update, run_self_update, update_status_message
84
84
  from .skills import (
85
85
  SkillCatalog,
86
86
  activated_skill_names,
@@ -719,6 +719,7 @@ class KolegaCodeApp(App):
719
719
  settings_store: Optional[SettingsStore] = None,
720
720
  overrides: Optional[CliConfigOverrides] = None,
721
721
  browser_visible: bool = False,
722
+ check_for_updates: bool = False,
722
723
  ) -> None:
723
724
  super().__init__()
724
725
  self.project_path = project_path
@@ -735,6 +736,7 @@ class KolegaCodeApp(App):
735
736
  self.skill_catalog: SkillCatalog = discover_skills(self.project_path)
736
737
  self.file_index = WorkspaceFileIndex(self.project_path)
737
738
  self.browser_visible = browser_visible
739
+ self.check_for_updates = check_for_updates
738
740
  self.connection_manager = CliConnectionManager()
739
741
  self.agent: Optional[CoderAgent | PlanningAgent] = None
740
742
  self.agent_worker = None
@@ -842,6 +844,8 @@ class KolegaCodeApp(App):
842
844
  self._set_effort_actions_visible(False)
843
845
  self._refresh_planning_sidebar()
844
846
  self._ensure_startup_entry()
847
+ if self.check_for_updates:
848
+ self.run_worker(self._check_for_update_on_startup(), name="kolega-update-check", group="updates")
845
849
  self._conversation.anchor()
846
850
  self.run_worker(self._consume_events(), name="kolega-events", group="events")
847
851
  if self.config is not None:
@@ -942,6 +946,14 @@ class KolegaCodeApp(App):
942
946
  except Exception:
943
947
  pass
944
948
 
949
+ async def _check_for_update_on_startup(self) -> None:
950
+ result = await asyncio.to_thread(check_for_update)
951
+ message = update_status_message(result)
952
+ if not message:
953
+ return
954
+ self._add_conversation_entry(ConversationEntry(kind="system", content=message))
955
+ self._notify_user(message)
956
+
945
957
  @property
946
958
  def _status_dashboard(self) -> Static:
947
959
  return self.query_one("#status_dashboard", Static)
@@ -1614,7 +1626,9 @@ class KolegaCodeApp(App):
1614
1626
  "/effort": self._command_effort,
1615
1627
  "/copy": self._command_copy,
1616
1628
  "/version": self._command_version,
1629
+ "/update": self._command_update,
1617
1630
  "/quit": self._command_quit,
1631
+ "/exit": self._command_quit,
1618
1632
  }
1619
1633
 
1620
1634
  async def _handle_tui_slash_command(self, stripped_text: str, composer: ChatComposer) -> bool:
@@ -1857,10 +1871,41 @@ class KolegaCodeApp(App):
1857
1871
  self._notify_user(messages.COPY_LAST_RESPONSE)
1858
1872
 
1859
1873
  async def _command_version(self, args: str) -> None:
1874
+ result = await asyncio.to_thread(check_for_update)
1875
+ lines = [messages.VERSION_INFO.format(version=result.current_version)]
1876
+ update_message = update_status_message(result, include_up_to_date=True, include_errors=True)
1877
+ if update_message:
1878
+ lines.append(update_message)
1860
1879
  self._add_conversation_entry(
1861
- ConversationEntry(kind="system", content=messages.VERSION_INFO.format(version=kolega_code_version))
1880
+ ConversationEntry(kind="system", content="\n".join(lines))
1862
1881
  )
1863
1882
 
1883
+ async def _command_update(self, args: str) -> None:
1884
+ if self._turn_active or self.agent_worker is not None:
1885
+ self._show_composer_hint(messages.BLOCK_STOP_BEFORE_UPDATE)
1886
+ self._notify_user(messages.BLOCK_STOP_BEFORE_UPDATE, severity="warning")
1887
+ return
1888
+
1889
+ self._notify_user(messages.UPDATE_STARTED)
1890
+ result = await asyncio.to_thread(run_self_update, capture_output=True)
1891
+ severity = "information" if result.returncode == 0 else "error"
1892
+ if result.returncode == 0:
1893
+ lines = [messages.UPDATE_COMPLETED]
1894
+ else:
1895
+ lines = [messages.UPDATE_FAILED.format(code=result.returncode)]
1896
+ if result.error:
1897
+ lines.append(result.error)
1898
+
1899
+ output = "\n".join(part for part in (result.stdout.strip(), result.stderr.strip()) if part)
1900
+ if output:
1901
+ if len(output) > 4000:
1902
+ output = "[output truncated]\n" + output[-4000:]
1903
+ lines.extend(["", "Output:", "```text", output, "```"])
1904
+
1905
+ content = "\n".join(lines)
1906
+ self._add_conversation_entry(ConversationEntry(kind="system", content=content))
1907
+ self._notify_user(lines[0], severity=severity)
1908
+
1864
1909
  async def _command_quit(self, args: str) -> None:
1865
1910
  await self.action_quit()
1866
1911
 
@@ -41,6 +41,8 @@ API_KEY_ENV = {
41
41
  ModelProvider.DASHSCOPE: "DASHSCOPE_API_KEY",
42
42
  ModelProvider.MOONSHOT: "MOONSHOT_API_KEY",
43
43
  ModelProvider.DEEPSEEK: "DEEPSEEK_API_KEY",
44
+ ModelProvider.ZAI: "ZAI_API_KEY",
45
+ ModelProvider.KIMI_CODING: "KIMI_CODING_API_KEY",
44
46
  }
45
47
 
46
48
 
@@ -255,6 +257,8 @@ def build_agent_config(
255
257
  dashscope_api_key=_api_key_for_provider(ModelProvider.DASHSCOPE, loaded_env, settings),
256
258
  moonshot_api_key=_api_key_for_provider(ModelProvider.MOONSHOT, loaded_env, settings),
257
259
  deepseek_api_key=_api_key_for_provider(ModelProvider.DEEPSEEK, loaded_env, settings),
260
+ zai_api_key=_api_key_for_provider(ModelProvider.ZAI, loaded_env, settings),
261
+ kimi_coding_api_key=_api_key_for_provider(ModelProvider.KIMI_CODING, loaded_env, settings),
258
262
  environment=overrides.environment or loaded_env.get("KOLEGA_CODE_ENVIRONMENT", "development"),
259
263
  long_context_config=_model_config(long_provider, long_model, thinking_effort=active_thinking_effort),
260
264
  fast_config=_model_config(fast_provider, fast_model),
@@ -10,7 +10,6 @@ import sys
10
10
  from pathlib import Path
11
11
  from typing import Iterable, Optional
12
12
 
13
- from kolega_code import __version__
14
13
  from kolega_code.agent import CoderAgent
15
14
  from kolega_code.llm.exceptions import LLMBillingError, billing_error_message
16
15
  from kolega_code.llm.models import TextBlock
@@ -37,8 +36,9 @@ from .skills import (
37
36
  build_skill_tool_extension,
38
37
  discover_skills,
39
38
  )
39
+ from .updater import check_for_update, run_self_update, update_status_message
40
40
 
41
- SUBCOMMANDS = {"ask", "sessions", "doctor"}
41
+ SUBCOMMANDS = {"ask", "sessions", "doctor", "update"}
42
42
  RESUME_LATEST = "__latest__"
43
43
  CLI_AGENT_MODE = AgentMode.CLI.value
44
44
 
@@ -46,12 +46,16 @@ CLI_AGENT_MODE = AgentMode.CLI.value
46
46
  def main(argv: Optional[Iterable[str]] = None) -> int:
47
47
  args = parse_args(list(argv) if argv is not None else sys.argv[1:])
48
48
  try:
49
+ if getattr(args, "version", False):
50
+ return _run_version()
49
51
  if args.command == "ask":
50
52
  return asyncio.run(_run_ask(args))
51
53
  if args.command == "sessions":
52
54
  return _run_sessions(args)
53
55
  if args.command == "doctor":
54
56
  return _run_doctor(args)
57
+ if args.command == "update":
58
+ return _run_update()
55
59
  return _run_tui(args)
56
60
  except (CliConfigError, SessionStoreError, SettingsStoreError, ValueError) as exc:
57
61
  _print_styled(f"kolega-code: {exc}", style="error", stderr=True)
@@ -110,7 +114,7 @@ def _add_session_args(parser: argparse.ArgumentParser, session_help: str = "Sess
110
114
  def _build_tui_parser() -> argparse.ArgumentParser:
111
115
  parser = argparse.ArgumentParser(prog="kolega-code", description="Run the Kolega Code Textual CLI.")
112
116
  parser.set_defaults(command="tui")
113
- parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
117
+ parser.add_argument("--version", action="store_true", help="Show the Kolega Code version.")
114
118
  parser.add_argument("project_path", nargs="?", default=".", type=Path, help="Project directory to work in.")
115
119
  parser.add_argument("--mode", choices=[mode.value for mode in AgentMode], default=CLI_AGENT_MODE, help=argparse.SUPPRESS)
116
120
  parser.add_argument("--new", action="store_true", help="Start a new session. This is now the default.")
@@ -159,6 +163,8 @@ def _build_subcommand_parser() -> argparse.ArgumentParser:
159
163
  doctor.add_argument("--state-dir", type=Path, help="Directory for CLI session state.")
160
164
  _add_common_model_args(doctor)
161
165
 
166
+ subparsers.add_parser("update", help="Update Kolega Code to the latest version.")
167
+
162
168
  return parser
163
169
 
164
170
 
@@ -260,6 +266,26 @@ def _resolve_tui_session(
260
266
  return store.create(project_path, CLI_AGENT_MODE, summary)
261
267
 
262
268
 
269
+ def _run_version() -> int:
270
+ result = check_for_update()
271
+ print(f"kolega-code {result.current_version}")
272
+ message = update_status_message(result)
273
+ if message:
274
+ print(message)
275
+ return 0
276
+
277
+
278
+ def _run_update() -> int:
279
+ result = run_self_update()
280
+ if result.error:
281
+ _print_styled(result.error, style="error", stderr=True)
282
+ if result.returncode == 0:
283
+ print("Kolega Code update completed. Run `kolega-code --version` to confirm.")
284
+ elif not result.error:
285
+ _print_styled("Kolega Code update failed.", style="error", stderr=True)
286
+ return result.returncode
287
+
288
+
263
289
  def _run_tui(args: argparse.Namespace) -> int:
264
290
  if importlib.util.find_spec("textual") is None:
265
291
  print("Textual is not installed. Reinstall the CLI with: uv tool install --force kolega-code", file=sys.stderr)
@@ -296,6 +322,7 @@ def _run_tui(args: argparse.Namespace) -> int:
296
322
  overrides=_overrides_from_args(args),
297
323
  session=session,
298
324
  browser_visible=args.browser_visible,
325
+ check_for_updates=True,
299
326
  )
300
327
  app.run()
301
328
  return 0
@@ -571,6 +598,9 @@ def _run_doctor(args: argparse.Namespace) -> int:
571
598
  line("State dir", store.root)
572
599
  textual_installed = importlib.util.find_spec("textual") is not None
573
600
  line("Textual installed", textual_installed, "success" if textual_installed else "warning")
601
+ update_message = update_status_message(check_for_update(), include_up_to_date=True, include_errors=True)
602
+ if update_message:
603
+ line("Update", update_message)
574
604
  if settings.active_provider and settings.active_model:
575
605
  line("Stored active model", f"{settings.active_provider}/{settings.active_model}")
576
606
  line("Stored thinking effort", settings.active_thinking_effort or "model default")
@@ -65,6 +65,9 @@ EFFORT_SWITCH_HINT = "Choose below, or switch with /effort <level>."
65
65
  COPY_LAST_RESPONSE = "Copied the last response to the clipboard."
66
66
  COPY_NOTHING = "No response to copy yet."
67
67
  VERSION_INFO = "Kolega Code version {version}."
68
+ UPDATE_STARTED = "Updating Kolega Code…"
69
+ UPDATE_COMPLETED = "Kolega Code update completed. Restart this TUI to use the updated version."
70
+ UPDATE_FAILED = "Kolega Code update failed with exit code {code}."
68
71
 
69
72
  # Blockers
70
73
  BLOCK_STOP_BEFORE_RESET = "Stop the current turn before resetting the thread."
@@ -72,6 +75,7 @@ BLOCK_STOP_BEFORE_MODE_SWITCH = "Stop the current turn before switching modes."
72
75
  BLOCK_STOP_BEFORE_SKILL = "Stop the current turn before activating a skill."
73
76
  BLOCK_STOP_BEFORE_MODEL_SWITCH = "Stop the current turn before switching models."
74
77
  BLOCK_STOP_BEFORE_EFFORT_SWITCH = "Stop the current turn before switching thinking effort."
78
+ BLOCK_STOP_BEFORE_UPDATE = "Stop the current turn before updating Kolega Code."
75
79
  BLOCK_PLAN_DECISION = "Choose Implement plan or Discuss further before sending another message."
76
80
  BLOCK_PLAN_DECISION_MODE_SWITCH = "Choose Implement plan or Discuss further before switching modes."
77
81
  BLOCK_PLAN_DECISION_SKILL = "Choose Implement plan or Discuss further before activating a skill."
@@ -24,6 +24,8 @@ from kolega_code.llm.specs import (
24
24
  PROVIDER_LABELS: dict[ModelProvider, str] = {
25
25
  ModelProvider.MOONSHOT: "Moonshot AI",
26
26
  ModelProvider.DEEPSEEK: "DeepSeek AI",
27
+ ModelProvider.ZAI: "Z.AI (GLM Coding Plan)",
28
+ ModelProvider.KIMI_CODING: "Kimi Coding Plan",
27
29
  ModelProvider.ANTHROPIC: "Anthropic",
28
30
  ModelProvider.OPENAI: "OpenAI",
29
31
  ModelProvider.GOOGLE: "Google",
@@ -40,9 +42,14 @@ MODEL_LABELS: dict[str, str] = {
40
42
  "kimi-k2.7-code": "Kimi K2.7 Code",
41
43
  "kimi-k2.7-code-highspeed": "Kimi K2.7 Code (High-Speed)",
42
44
  "kimi-k2.6": "Kimi K2.6",
45
+ # Kimi Coding Plan
46
+ "kimi-for-coding": "Kimi for Coding",
43
47
  # DeepSeek
44
48
  "deepseek-v4-pro": "DeepSeek V4 Pro",
45
49
  "deepseek-v4-flash": "DeepSeek V4 Flash",
50
+ # Z.AI (GLM Coding Plan)
51
+ "glm-5.2": "GLM-5.2",
52
+ "glm-5.1": "GLM-5.1",
46
53
  # Anthropic
47
54
  "claude-opus-4-8": "Claude Opus 4.8",
48
55
  "claude-opus-4-7": "Claude Opus 4.7",
@@ -76,6 +83,8 @@ MODEL_LABELS: dict[str, str] = {
76
83
  PROVIDER_DEFAULT_MODEL: dict[ModelProvider, str] = {
77
84
  ModelProvider.MOONSHOT: "kimi-k2.7-code",
78
85
  ModelProvider.DEEPSEEK: "deepseek-v4-pro",
86
+ ModelProvider.ZAI: "glm-5.2",
87
+ ModelProvider.KIMI_CODING: "kimi-for-coding",
79
88
  ModelProvider.ANTHROPIC: "claude-opus-4-8",
80
89
  ModelProvider.OPENAI: "gpt-5.5",
81
90
  ModelProvider.GOOGLE: "gemini-3.1-pro-preview",
@@ -46,7 +46,9 @@ TUI_COMMAND_ENTRIES: tuple[SlashCommandEntry, ...] = (
46
46
  SlashCommandEntry("effort", "Show or set the active thinking effort", CommandScope.TUI),
47
47
  SlashCommandEntry("copy", "Copy the last response to the clipboard", CommandScope.TUI),
48
48
  SlashCommandEntry("version", "Show the Kolega Code version", CommandScope.TUI),
49
+ SlashCommandEntry("update", "Update Kolega Code to the latest version", CommandScope.TUI),
49
50
  SlashCommandEntry("quit", "Save the session and exit", CommandScope.TUI),
51
+ SlashCommandEntry("exit", "Save the session and exit", CommandScope.TUI),
50
52
  )
51
53
 
52
54
  TUI_COMMAND_NAMES: frozenset[str] = frozenset(entry.token for entry in TUI_COMMAND_ENTRIES)