shotgun-sh 0.2.1.dev2__tar.gz → 0.2.1.dev3__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.

Potentially problematic release.


This version of shotgun-sh might be problematic. Click here for more details.

Files changed (148) hide show
  1. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/PKG-INFO +1 -1
  2. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/pyproject.toml +1 -1
  3. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/config/manager.py +2 -2
  4. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/config/provider.py +2 -2
  5. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/config.py +16 -4
  6. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat.py +2 -8
  7. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat_screen/command_providers.py +95 -10
  8. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat_screen/history.py +3 -1
  9. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/model_picker.py +51 -14
  10. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/provider_config.py +16 -5
  11. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/utils/env_utils.py +12 -0
  12. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/.gitignore +0 -0
  13. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/LICENSE +0 -0
  14. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/README.md +0 -0
  15. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/hatch_build.py +0 -0
  16. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/__init__.py +0 -0
  17. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/__init__.py +0 -0
  18. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/agent_manager.py +0 -0
  19. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/common.py +0 -0
  20. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/config/__init__.py +0 -0
  21. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/config/constants.py +0 -0
  22. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/config/models.py +0 -0
  23. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/conversation_history.py +0 -0
  24. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/conversation_manager.py +0 -0
  25. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/export.py +0 -0
  26. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/__init__.py +0 -0
  27. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/compaction.py +0 -0
  28. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/constants.py +0 -0
  29. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/context_extraction.py +0 -0
  30. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/history_building.py +0 -0
  31. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/history_processors.py +0 -0
  32. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/message_utils.py +0 -0
  33. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/__init__.py +0 -0
  34. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/anthropic.py +0 -0
  35. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/base.py +0 -0
  36. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/openai.py +0 -0
  37. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/sentencepiece_counter.py +0 -0
  38. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/tokenizer_cache.py +0 -0
  39. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_counting/utils.py +0 -0
  40. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/history/token_estimation.py +0 -0
  41. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/llm.py +0 -0
  42. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/messages.py +0 -0
  43. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/models.py +0 -0
  44. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/plan.py +0 -0
  45. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/research.py +0 -0
  46. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/specify.py +0 -0
  47. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tasks.py +0 -0
  48. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/__init__.py +0 -0
  49. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
  50. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
  51. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
  52. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
  53. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/models.py +0 -0
  54. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
  55. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
  56. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/file_management.py +0 -0
  57. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/user_interaction.py +0 -0
  58. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
  59. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
  60. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
  61. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/web_search/openai.py +0 -0
  62. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/tools/web_search/utils.py +0 -0
  63. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/agents/usage_manager.py +0 -0
  64. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/build_constants.py +0 -0
  65. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/__init__.py +0 -0
  66. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/codebase/__init__.py +0 -0
  67. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/codebase/commands.py +0 -0
  68. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/codebase/models.py +0 -0
  69. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/export.py +0 -0
  70. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/feedback.py +0 -0
  71. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/models.py +0 -0
  72. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/plan.py +0 -0
  73. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/research.py +0 -0
  74. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/specify.py +0 -0
  75. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/tasks.py +0 -0
  76. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/update.py +0 -0
  77. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/cli/utils.py +0 -0
  78. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/__init__.py +0 -0
  79. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/__init__.py +0 -0
  80. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/change_detector.py +0 -0
  81. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/code_retrieval.py +0 -0
  82. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/cypher_models.py +0 -0
  83. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/ingestor.py +0 -0
  84. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/language_config.py +0 -0
  85. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/manager.py +0 -0
  86. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/nl_query.py +0 -0
  87. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/core/parser_loader.py +0 -0
  88. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/models.py +0 -0
  89. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/codebase/service.py +0 -0
  90. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/llm_proxy/__init__.py +0 -0
  91. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/llm_proxy/clients.py +0 -0
  92. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/llm_proxy/constants.py +0 -0
  93. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/logging_config.py +0 -0
  94. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/main.py +0 -0
  95. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/posthog_telemetry.py +0 -0
  96. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/__init__.py +0 -0
  97. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/__init__.py +0 -0
  98. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/export.j2 +0 -0
  99. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
  100. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
  101. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
  102. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
  103. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/plan.j2 +0 -0
  104. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/research.j2 +0 -0
  105. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/specify.j2 +0 -0
  106. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
  107. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
  108. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/agents/tasks.j2 +0 -0
  109. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/__init__.py +0 -0
  110. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
  111. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
  112. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
  113. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
  114. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
  115. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
  116. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/history/__init__.py +0 -0
  117. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
  118. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/history/summarization.j2 +0 -0
  119. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/prompts/loader.py +0 -0
  120. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/py.typed +0 -0
  121. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sdk/__init__.py +0 -0
  122. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sdk/codebase.py +0 -0
  123. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sdk/exceptions.py +0 -0
  124. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sdk/models.py +0 -0
  125. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sdk/services.py +0 -0
  126. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/sentry_telemetry.py +0 -0
  127. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/telemetry.py +0 -0
  128. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/__init__.py +0 -0
  129. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/app.py +0 -0
  130. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/commands/__init__.py +0 -0
  131. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/components/prompt_input.py +0 -0
  132. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/components/spinner.py +0 -0
  133. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/components/splash.py +0 -0
  134. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/components/vertical_tail.py +0 -0
  135. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/filtered_codebase_service.py +0 -0
  136. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat.tcss +0 -0
  137. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
  138. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/chat_screen/hint_message.py +0 -0
  139. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/directory_setup.py +0 -0
  140. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/feedback.py +0 -0
  141. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/screens/splash.py +0 -0
  142. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/styles.tcss +0 -0
  143. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/utils/__init__.py +0 -0
  144. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/tui/utils/mode_progress.py +0 -0
  145. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/utils/__init__.py +0 -0
  146. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/utils/file_system_utils.py +0 -0
  147. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/utils/source_detection.py +0 -0
  148. {shotgun_sh-0.2.1.dev2 → shotgun_sh-0.2.1.dev3}/src/shotgun/utils/update_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.2.1.dev2
3
+ Version: 0.2.1.dev3
4
4
  Summary: AI-powered research, planning, and task management CLI tool
5
5
  Project-URL: Homepage, https://shotgun.sh/
6
6
  Project-URL: Repository, https://github.com/shotgun-sh/shotgun
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shotgun-sh"
3
- version = "0.2.1.dev2"
3
+ version = "0.2.1.dev3"
4
4
  description = "AI-powered research, planning, and task management CLI tool"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -109,7 +109,7 @@ class ConfigManager:
109
109
  # Find default model for this provider
110
110
  provider_models = {
111
111
  ProviderType.OPENAI: ModelName.GPT_5,
112
- ProviderType.ANTHROPIC: ModelName.CLAUDE_OPUS_4_1,
112
+ ProviderType.ANTHROPIC: ModelName.CLAUDE_SONNET_4_5,
113
113
  ProviderType.GOOGLE: ModelName.GEMINI_2_5_PRO,
114
114
  }
115
115
 
@@ -210,7 +210,7 @@ class ConfigManager:
210
210
 
211
211
  provider_models = {
212
212
  ProviderType.OPENAI: ModelName.GPT_5,
213
- ProviderType.ANTHROPIC: ModelName.CLAUDE_OPUS_4_1,
213
+ ProviderType.ANTHROPIC: ModelName.CLAUDE_SONNET_4_5,
214
214
  ProviderType.GOOGLE: ModelName.GEMINI_2_5_PRO,
215
215
  }
216
216
  if provider_enum in provider_models:
@@ -219,8 +219,8 @@ def get_provider_model(
219
219
  if not api_key:
220
220
  raise ValueError("Anthropic API key not configured. Set via config.")
221
221
 
222
- # Use requested model or default to claude-opus-4-1
223
- model_name = requested_model if requested_model else ModelName.CLAUDE_OPUS_4_1
222
+ # Use requested model or default to claude-sonnet-4-5
223
+ model_name = requested_model if requested_model else ModelName.CLAUDE_SONNET_4_5
224
224
  if model_name not in MODEL_SPECS:
225
225
  raise ValueError(f"Model '{model_name.value}' not found")
226
226
  spec = MODEL_SPECS[model_name]
@@ -9,6 +9,7 @@ from rich.table import Table
9
9
 
10
10
  from shotgun.agents.config import ProviderType, get_config_manager
11
11
  from shotgun.logging_config import get_logger
12
+ from shotgun.utils.env_utils import is_shotgun_account_enabled
12
13
 
13
14
  logger = get_logger(__name__)
14
15
  console = Console()
@@ -162,12 +163,17 @@ def _show_full_config(config: Any) -> None:
162
163
  table.add_row("", "") # Separator
163
164
 
164
165
  # Provider configurations
165
- for provider_name, provider_config in [
166
+ providers_to_show = [
166
167
  ("OpenAI", config.openai),
167
168
  ("Anthropic", config.anthropic),
168
169
  ("Google", config.google),
169
- ("Shotgun Account", config.shotgun),
170
- ]:
170
+ ]
171
+
172
+ # Only show Shotgun Account if feature flag is enabled
173
+ if is_shotgun_account_enabled():
174
+ providers_to_show.append(("Shotgun Account", config.shotgun))
175
+
176
+ for provider_name, provider_config in providers_to_show:
171
177
  table.add_row(f"[bold]{provider_name}[/bold]", "")
172
178
 
173
179
  # API Key
@@ -207,7 +213,13 @@ def _show_provider_config(provider: ProviderType, config: Any) -> None:
207
213
 
208
214
  def _mask_secrets(data: dict[str, Any]) -> None:
209
215
  """Mask secrets in configuration data."""
210
- for provider in ["openai", "anthropic", "google", "shotgun"]:
216
+ providers = ["openai", "anthropic", "google"]
217
+
218
+ # Only mask shotgun if feature flag is enabled
219
+ if is_shotgun_account_enabled():
220
+ providers.append("shotgun")
221
+
222
+ for provider in providers:
211
223
  if provider in data and isinstance(data[provider], dict):
212
224
  if "api_key" in data[provider] and data[provider]["api_key"]:
213
225
  data[provider]["api_key"] = _mask_value(data[provider]["api_key"])
@@ -54,11 +54,8 @@ from ..components.prompt_input import PromptInput
54
54
  from ..components.spinner import Spinner
55
55
  from ..utils.mode_progress import PlaceholderHints
56
56
  from .chat_screen.command_providers import (
57
- AgentModeProvider,
58
- CodebaseCommandProvider,
59
57
  DeleteCodebasePaletteProvider,
60
- ProviderSetupProvider,
61
- UsageProvider,
58
+ UnifiedCommandProvider,
62
59
  )
63
60
 
64
61
  logger = logging.getLogger(__name__)
@@ -233,10 +230,7 @@ class ChatScreen(Screen[None]):
233
230
  ]
234
231
 
235
232
  COMMANDS = {
236
- AgentModeProvider,
237
- ProviderSetupProvider,
238
- CodebaseCommandProvider,
239
- UsageProvider,
233
+ UnifiedCommandProvider,
240
234
  }
241
235
 
242
236
  value = reactive("")
@@ -191,30 +191,30 @@ class CodebaseCommandProvider(Provider):
191
191
  return cast(ChatScreen, self.screen)
192
192
 
193
193
  async def discover(self) -> AsyncGenerator[DiscoveryHit, None]:
194
- yield DiscoveryHit(
195
- "Codebase: Index Codebase",
196
- self.chat_screen.index_codebase_command,
197
- help="Index a repository into the codebase graph",
198
- )
199
194
  yield DiscoveryHit(
200
195
  "Codebase: Delete Codebase Index",
201
196
  self.chat_screen.delete_codebase_command,
202
197
  help="Delete an existing codebase index",
203
198
  )
199
+ yield DiscoveryHit(
200
+ "Codebase: Index Codebase",
201
+ self.chat_screen.index_codebase_command,
202
+ help="Index a repository into the codebase graph",
203
+ )
204
204
 
205
205
  async def search(self, query: str) -> AsyncGenerator[Hit, None]:
206
206
  matcher = self.matcher(query)
207
207
  commands = [
208
- (
209
- "Codebase: Index Codebase",
210
- self.chat_screen.index_codebase_command,
211
- "Index a repository into the codebase graph",
212
- ),
213
208
  (
214
209
  "Codebase: Delete Codebase Index",
215
210
  self.chat_screen.delete_codebase_command,
216
211
  "Delete an existing codebase index",
217
212
  ),
213
+ (
214
+ "Codebase: Index Codebase",
215
+ self.chat_screen.index_codebase_command,
216
+ "Index a repository into the codebase graph",
217
+ ),
218
218
  ]
219
219
  for title, callback, help_text in commands:
220
220
  score = matcher.match(title)
@@ -269,3 +269,88 @@ class DeleteCodebasePaletteProvider(Provider):
269
269
  ),
270
270
  help=graph.repo_path,
271
271
  )
272
+
273
+
274
+ class UnifiedCommandProvider(Provider):
275
+ """Unified command provider with all commands in alphabetical order."""
276
+
277
+ @property
278
+ def chat_screen(self) -> "ChatScreen":
279
+ from shotgun.tui.screens.chat import ChatScreen
280
+
281
+ return cast(ChatScreen, self.screen)
282
+
283
+ def open_provider_config(self) -> None:
284
+ """Show the provider configuration screen."""
285
+ self.chat_screen.app.push_screen("provider_config")
286
+
287
+ def open_model_picker(self) -> None:
288
+ """Show the model picker screen."""
289
+ self.chat_screen.app.push_screen("model_picker")
290
+
291
+ async def discover(self) -> AsyncGenerator[DiscoveryHit, None]:
292
+ """Provide commands in alphabetical order when palette opens."""
293
+ # Alphabetically ordered commands
294
+ yield DiscoveryHit(
295
+ "Codebase: Delete Codebase Index",
296
+ self.chat_screen.delete_codebase_command,
297
+ help="Delete an existing codebase index",
298
+ )
299
+ yield DiscoveryHit(
300
+ "Codebase: Index Codebase",
301
+ self.chat_screen.index_codebase_command,
302
+ help="Index a repository into the codebase graph",
303
+ )
304
+ yield DiscoveryHit(
305
+ "Open Provider Setup",
306
+ self.open_provider_config,
307
+ help="⚙️ Manage API keys for available providers",
308
+ )
309
+ yield DiscoveryHit(
310
+ "Select AI Model",
311
+ self.open_model_picker,
312
+ help="🤖 Choose which AI model to use",
313
+ )
314
+ yield DiscoveryHit(
315
+ "Show usage",
316
+ self.chat_screen.action_show_usage,
317
+ help="Display usage information for the current session",
318
+ )
319
+
320
+ async def search(self, query: str) -> AsyncGenerator[Hit, None]:
321
+ """Search for commands in alphabetical order."""
322
+ matcher = self.matcher(query)
323
+
324
+ # Define all commands in alphabetical order
325
+ commands = [
326
+ (
327
+ "Codebase: Delete Codebase Index",
328
+ self.chat_screen.delete_codebase_command,
329
+ "Delete an existing codebase index",
330
+ ),
331
+ (
332
+ "Codebase: Index Codebase",
333
+ self.chat_screen.index_codebase_command,
334
+ "Index a repository into the codebase graph",
335
+ ),
336
+ (
337
+ "Open Provider Setup",
338
+ self.open_provider_config,
339
+ "⚙️ Manage API keys for available providers",
340
+ ),
341
+ (
342
+ "Select AI Model",
343
+ self.open_model_picker,
344
+ "🤖 Choose which AI model to use",
345
+ ),
346
+ (
347
+ "Show usage",
348
+ self.chat_screen.action_show_usage,
349
+ "Display usage information for the current session",
350
+ ),
351
+ ]
352
+
353
+ for title, callback, help_text in commands:
354
+ score = matcher.match(title)
355
+ if score > 0:
356
+ yield Hit(score, matcher.highlight(title), callback, help=help_text)
@@ -217,7 +217,9 @@ class AgentResponseWidget(Widget):
217
217
  return ""
218
218
  for idx, part in enumerate(self.item.parts):
219
219
  if isinstance(part, TextPart):
220
- acc += f"**⏺** {part.content}\n\n"
220
+ # Only show the circle prefix if there's actual content
221
+ if part.content and part.content.strip():
222
+ acc += f"**⏺** {part.content}\n\n"
221
223
  elif isinstance(part, ToolCallPart):
222
224
  parts_str = self._format_tool_call_part(part)
223
225
  acc += parts_str + "\n\n"
@@ -35,10 +35,6 @@ class ModelPickerScreen(Screen[None]):
35
35
  layout: vertical;
36
36
  }
37
37
 
38
- ModelPicker > * {
39
- height: auto;
40
- }
41
-
42
38
  #titlebox {
43
39
  height: auto;
44
40
  margin: 2 0;
@@ -60,6 +56,7 @@ class ModelPickerScreen(Screen[None]):
60
56
  #model-list {
61
57
  margin: 2 0;
62
58
  height: auto;
59
+ padding: 1;
63
60
  & > * {
64
61
  padding: 1 0;
65
62
  }
@@ -70,9 +67,6 @@ class ModelPickerScreen(Screen[None]):
70
67
  #model-actions > * {
71
68
  margin-right: 2;
72
69
  }
73
- #model-list {
74
- padding: 1;
75
- }
76
70
  """
77
71
 
78
72
  BINDINGS = [
@@ -97,16 +91,21 @@ class ModelPickerScreen(Screen[None]):
97
91
  # Load current selection
98
92
  config_manager = self.config_manager
99
93
  config = config_manager.load()
100
- current_model = config.selected_model or ModelName.CLAUDE_OPUS_4_1
94
+ current_model = config.selected_model or ModelName.CLAUDE_SONNET_4_5
101
95
  self.selected_model = current_model
102
96
 
103
- # Find and highlight current selection
97
+ # Find and highlight current selection (if it's in the filtered list)
104
98
  list_view = self.query_one(ListView)
105
99
  if list_view.children:
106
- for i, model_name in enumerate(AVAILABLE_MODELS):
107
- if model_name == current_model:
108
- list_view.index = i
109
- break
100
+ for i, child in enumerate(list_view.children):
101
+ if isinstance(child, ListItem) and child.id:
102
+ model_id = child.id.removeprefix("model-")
103
+ # Find the model name
104
+ for model_name in AVAILABLE_MODELS:
105
+ if _sanitize_model_name_for_id(model_name) == model_id:
106
+ if model_name == current_model:
107
+ list_view.index = i
108
+ break
110
109
  self.refresh_model_labels()
111
110
 
112
111
  def action_done(self) -> None:
@@ -141,9 +140,12 @@ class ModelPickerScreen(Screen[None]):
141
140
  def refresh_model_labels(self) -> None:
142
141
  """Update the list view entries to reflect current selection."""
143
142
  current_model = (
144
- self.config_manager.load().selected_model or ModelName.CLAUDE_OPUS_4_1
143
+ self.config_manager.load().selected_model or ModelName.CLAUDE_SONNET_4_5
145
144
  )
145
+ # Update labels for available models only
146
146
  for model_name in AVAILABLE_MODELS:
147
+ if not self._is_model_available(model_name):
148
+ continue
147
149
  label = self.query_one(
148
150
  f"#label-{_sanitize_model_name_for_id(model_name)}", Label
149
151
  )
@@ -155,6 +157,10 @@ class ModelPickerScreen(Screen[None]):
155
157
  items: list[ListItem] = []
156
158
  current_model = self.selected_model
157
159
  for model_name in AVAILABLE_MODELS:
160
+ # Only add models that are available
161
+ if not self._is_model_available(model_name):
162
+ continue
163
+
158
164
  label = Label(
159
165
  self._model_label(model_name, is_current=model_name == current_model),
160
166
  id=f"label-{_sanitize_model_name_for_id(model_name)}",
@@ -165,6 +171,7 @@ class ModelPickerScreen(Screen[None]):
165
171
  return items
166
172
 
167
173
  def _model_from_item(self, item: ListItem | None) -> ModelName | None:
174
+ """Get ModelName from a ListItem."""
168
175
  if item is None or item.id is None:
169
176
  return None
170
177
  sanitized_id = item.id.removeprefix("model-")
@@ -174,6 +181,32 @@ class ModelPickerScreen(Screen[None]):
174
181
  return model_name
175
182
  return None
176
183
 
184
+ def _is_model_available(self, model_name: ModelName) -> bool:
185
+ """Check if a model is available based on provider key configuration.
186
+
187
+ A model is available if:
188
+ 1. Shotgun Account key is configured (provides access to all models), OR
189
+ 2. The model's provider has an API key configured (BYOK mode)
190
+
191
+ Args:
192
+ model_name: The model to check availability for
193
+
194
+ Returns:
195
+ True if the model can be used, False otherwise
196
+ """
197
+ config = self.config_manager.load()
198
+
199
+ # If Shotgun Account is configured, all models are available
200
+ if self.config_manager._provider_has_api_key(config.shotgun):
201
+ return True
202
+
203
+ # In BYOK mode, check if the model's provider has a key
204
+ if model_name not in MODEL_SPECS:
205
+ return False
206
+
207
+ spec = MODEL_SPECS[model_name]
208
+ return self.config_manager.has_provider_key(spec.provider)
209
+
177
210
  def _model_label(self, model_name: ModelName, is_current: bool) -> str:
178
211
  """Generate label for model with specs and current indicator."""
179
212
  if model_name not in MODEL_SPECS:
@@ -188,6 +221,10 @@ class ModelPickerScreen(Screen[None]):
188
221
 
189
222
  label = f"{display_name} · {input_k}K context · {output_k}K output"
190
223
 
224
+ # Add cost indicator for expensive models
225
+ if model_name == ModelName.CLAUDE_OPUS_4_1:
226
+ label += " · Expensive"
227
+
191
228
  if is_current:
192
229
  label += " · Current"
193
230
 
@@ -12,12 +12,23 @@ from textual.screen import Screen
12
12
  from textual.widgets import Button, Input, Label, ListItem, ListView, Markdown, Static
13
13
 
14
14
  from shotgun.agents.config import ConfigManager, ProviderType
15
+ from shotgun.utils.env_utils import is_shotgun_account_enabled
15
16
 
16
17
  if TYPE_CHECKING:
17
18
  from ..app import ShotgunApp
18
19
 
19
- # Provider identifiers for configuration screen (LLM providers + Shotgun Account)
20
- CONFIGURABLE_PROVIDERS = ["openai", "anthropic", "google", "shotgun"]
20
+
21
+ def get_configurable_providers() -> list[str]:
22
+ """Get list of configurable providers based on feature flags.
23
+
24
+ Returns:
25
+ List of provider identifiers that can be configured.
26
+ Includes shotgun only if SHOTGUN_ACCOUNT_ENABLED is set.
27
+ """
28
+ providers = ["openai", "anthropic", "google"]
29
+ if is_shotgun_account_enabled():
30
+ providers.append("shotgun")
31
+ return providers
21
32
 
22
33
 
23
34
  class ProviderConfigScreen(Screen[None]):
@@ -155,13 +166,13 @@ class ProviderConfigScreen(Screen[None]):
155
166
 
156
167
  def refresh_provider_status(self) -> None:
157
168
  """Update the list view entries to reflect configured providers."""
158
- for provider_id in CONFIGURABLE_PROVIDERS:
169
+ for provider_id in get_configurable_providers():
159
170
  label = self.query_one(f"#label-{provider_id}", Label)
160
171
  label.update(self._provider_label(provider_id))
161
172
 
162
173
  def _build_provider_items(self) -> list[ListItem]:
163
174
  items: list[ListItem] = []
164
- for provider_id in CONFIGURABLE_PROVIDERS:
175
+ for provider_id in get_configurable_providers():
165
176
  label = Label(self._provider_label(provider_id), id=f"label-{provider_id}")
166
177
  items.append(ListItem(label, id=f"provider-{provider_id}"))
167
178
  return items
@@ -170,7 +181,7 @@ class ProviderConfigScreen(Screen[None]):
170
181
  if item is None or item.id is None:
171
182
  return None
172
183
  provider_id = item.id.removeprefix("provider-")
173
- return provider_id if provider_id in CONFIGURABLE_PROVIDERS else None
184
+ return provider_id if provider_id in get_configurable_providers() else None
174
185
 
175
186
  def _provider_label(self, provider_id: str) -> str:
176
187
  display = self._provider_display_name(provider_id)
@@ -1,5 +1,17 @@
1
1
  """Utilities for working with environment variables."""
2
2
 
3
+ import os
4
+
5
+
6
+ def is_shotgun_account_enabled() -> bool:
7
+ """Check if Shotgun Account feature is enabled via environment variable.
8
+
9
+ Returns:
10
+ True if SHOTGUN_ACCOUNT_ENABLED is set to a truthy value,
11
+ False otherwise
12
+ """
13
+ return is_truthy(os.environ.get("SHOTGUN_ACCOUNT_ENABLED"))
14
+
3
15
 
4
16
  def is_truthy(value: str | None) -> bool:
5
17
  """Check if a string value represents true.
File without changes