shotgun-sh 0.2.6.dev5__tar.gz → 0.2.7.dev1__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 (160) hide show
  1. shotgun_sh-0.2.7.dev1/PKG-INFO +125 -0
  2. shotgun_sh-0.2.7.dev1/README_PYPI.md +71 -0
  3. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/pyproject.toml +3 -2
  4. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/agent_manager.py +81 -1
  5. shotgun_sh-0.2.7.dev1/src/shotgun/agents/conversation_history.py +227 -0
  6. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/conversation_manager.py +24 -2
  7. shotgun_sh-0.2.7.dev1/src/shotgun/agents/history/context_extraction.py +195 -0
  8. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat.py +54 -13
  9. shotgun_sh-0.2.6.dev5/PKG-INFO +0 -467
  10. shotgun_sh-0.2.6.dev5/src/shotgun/agents/conversation_history.py +0 -106
  11. shotgun_sh-0.2.6.dev5/src/shotgun/agents/history/context_extraction.py +0 -108
  12. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/.gitignore +0 -0
  13. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/LICENSE +0 -0
  14. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/README.md +0 -0
  15. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/hatch_build.py +0 -0
  16. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/__init__.py +0 -0
  17. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/__init__.py +0 -0
  18. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/common.py +0 -0
  19. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/config/__init__.py +0 -0
  20. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/config/constants.py +0 -0
  21. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/config/manager.py +0 -0
  22. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/config/models.py +0 -0
  23. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/config/provider.py +0 -0
  24. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/export.py +0 -0
  25. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/__init__.py +0 -0
  26. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/compaction.py +0 -0
  27. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/constants.py +0 -0
  28. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/history_building.py +0 -0
  29. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/history_processors.py +0 -0
  30. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/message_utils.py +0 -0
  31. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/__init__.py +0 -0
  32. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/anthropic.py +0 -0
  33. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/base.py +0 -0
  34. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/openai.py +0 -0
  35. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/sentencepiece_counter.py +0 -0
  36. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/tokenizer_cache.py +0 -0
  37. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_counting/utils.py +0 -0
  38. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/history/token_estimation.py +0 -0
  39. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/llm.py +0 -0
  40. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/messages.py +0 -0
  41. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/models.py +0 -0
  42. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/plan.py +0 -0
  43. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/research.py +0 -0
  44. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/specify.py +0 -0
  45. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tasks.py +0 -0
  46. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/__init__.py +0 -0
  47. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
  48. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
  49. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
  50. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
  51. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/models.py +0 -0
  52. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
  53. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
  54. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/file_management.py +0 -0
  55. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
  56. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
  57. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
  58. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/web_search/openai.py +0 -0
  59. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/tools/web_search/utils.py +0 -0
  60. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/agents/usage_manager.py +0 -0
  61. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/api_endpoints.py +0 -0
  62. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/build_constants.py +0 -0
  63. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/__init__.py +0 -0
  64. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/codebase/__init__.py +0 -0
  65. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/codebase/commands.py +0 -0
  66. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/codebase/models.py +0 -0
  67. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/config.py +0 -0
  68. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/export.py +0 -0
  69. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/feedback.py +0 -0
  70. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/models.py +0 -0
  71. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/plan.py +0 -0
  72. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/research.py +0 -0
  73. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/specify.py +0 -0
  74. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/tasks.py +0 -0
  75. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/update.py +0 -0
  76. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/cli/utils.py +0 -0
  77. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/__init__.py +0 -0
  78. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/__init__.py +0 -0
  79. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/change_detector.py +0 -0
  80. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/code_retrieval.py +0 -0
  81. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/cypher_models.py +0 -0
  82. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/ingestor.py +0 -0
  83. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/language_config.py +0 -0
  84. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/manager.py +0 -0
  85. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/nl_query.py +0 -0
  86. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/core/parser_loader.py +0 -0
  87. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/models.py +0 -0
  88. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/codebase/service.py +0 -0
  89. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/llm_proxy/__init__.py +0 -0
  90. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/llm_proxy/clients.py +0 -0
  91. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/llm_proxy/constants.py +0 -0
  92. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/logging_config.py +0 -0
  93. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/main.py +0 -0
  94. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/posthog_telemetry.py +0 -0
  95. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/__init__.py +0 -0
  96. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/__init__.py +0 -0
  97. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/export.j2 +0 -0
  98. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
  99. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
  100. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
  101. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
  102. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/plan.j2 +0 -0
  103. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/research.j2 +0 -0
  104. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/specify.j2 +0 -0
  105. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
  106. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
  107. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/agents/tasks.j2 +0 -0
  108. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/__init__.py +0 -0
  109. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
  110. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
  111. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
  112. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
  113. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
  114. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
  115. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/history/__init__.py +0 -0
  116. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
  117. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/history/summarization.j2 +0 -0
  118. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/loader.py +0 -0
  119. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/prompts/tools/web_search.j2 +0 -0
  120. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/py.typed +0 -0
  121. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sdk/__init__.py +0 -0
  122. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sdk/codebase.py +0 -0
  123. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sdk/exceptions.py +0 -0
  124. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sdk/models.py +0 -0
  125. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sdk/services.py +0 -0
  126. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/sentry_telemetry.py +0 -0
  127. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/shotgun_web/__init__.py +0 -0
  128. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/shotgun_web/client.py +0 -0
  129. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/shotgun_web/constants.py +0 -0
  130. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/shotgun_web/models.py +0 -0
  131. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/telemetry.py +0 -0
  132. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/__init__.py +0 -0
  133. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/app.py +0 -0
  134. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/commands/__init__.py +0 -0
  135. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/components/prompt_input.py +0 -0
  136. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/components/spinner.py +0 -0
  137. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/components/splash.py +0 -0
  138. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/components/vertical_tail.py +0 -0
  139. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/filtered_codebase_service.py +0 -0
  140. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat.tcss +0 -0
  141. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
  142. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat_screen/command_providers.py +0 -0
  143. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat_screen/hint_message.py +0 -0
  144. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/chat_screen/history.py +0 -0
  145. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/directory_setup.py +0 -0
  146. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/feedback.py +0 -0
  147. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/model_picker.py +0 -0
  148. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/provider_config.py +0 -0
  149. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/shotgun_auth.py +0 -0
  150. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/splash.py +0 -0
  151. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/screens/welcome.py +0 -0
  152. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/styles.tcss +0 -0
  153. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/utils/__init__.py +0 -0
  154. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/tui/utils/mode_progress.py +0 -0
  155. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/__init__.py +0 -0
  156. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/datetime_utils.py +0 -0
  157. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/env_utils.py +0 -0
  158. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/file_system_utils.py +0 -0
  159. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/source_detection.py +0 -0
  160. {shotgun_sh-0.2.6.dev5 → shotgun_sh-0.2.7.dev1}/src/shotgun/utils/update_checker.py +0 -0
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: shotgun-sh
3
+ Version: 0.2.7.dev1
4
+ Summary: AI-powered research, planning, and task management CLI tool
5
+ Project-URL: Homepage, https://shotgun.sh/
6
+ Project-URL: Repository, https://github.com/shotgun-sh/shotgun
7
+ Project-URL: Issues, https://github.com/shotgun-sh/shotgun-alpha/issues
8
+ Project-URL: Discord, https://discord.gg/5RmY6J2N7s
9
+ Author-email: "Proofs.io" <hello@proofs.io>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent,ai,cli,llm,planning,productivity,pydantic-ai,research,task-management
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: anthropic>=0.39.0
25
+ Requires-Dist: genai-prices>=0.0.27
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: jinja2>=3.1.0
28
+ Requires-Dist: kuzu>=0.7.0
29
+ Requires-Dist: logfire[pydantic-ai]>=2.0.0
30
+ Requires-Dist: openai>=1.0.0
31
+ Requires-Dist: packaging>=23.0
32
+ Requires-Dist: posthog>=3.0.0
33
+ Requires-Dist: pydantic-ai>=0.0.14
34
+ Requires-Dist: rich>=13.0.0
35
+ Requires-Dist: sentencepiece>=0.2.0
36
+ Requires-Dist: sentry-sdk[pure-eval]>=2.0.0
37
+ Requires-Dist: textual-dev>=1.7.0
38
+ Requires-Dist: textual>=6.1.0
39
+ Requires-Dist: tiktoken>=0.7.0
40
+ Requires-Dist: tree-sitter-go>=0.23.0
41
+ Requires-Dist: tree-sitter-javascript>=0.23.0
42
+ Requires-Dist: tree-sitter-python>=0.23.0
43
+ Requires-Dist: tree-sitter-rust>=0.23.0
44
+ Requires-Dist: tree-sitter-typescript>=0.23.0
45
+ Requires-Dist: tree-sitter>=0.21.0
46
+ Requires-Dist: typer>=0.12.0
47
+ Requires-Dist: watchdog>=4.0.0
48
+ Provides-Extra: dev
49
+ Requires-Dist: commitizen>=3.13.0; extra == 'dev'
50
+ Requires-Dist: lefthook>=1.12.0; extra == 'dev'
51
+ Requires-Dist: mypy>=1.11.0; extra == 'dev'
52
+ Requires-Dist: ruff>=0.6.0; extra == 'dev'
53
+ Description-Content-Type: text/markdown
54
+
55
+ # Shotgun
56
+
57
+ **Spec-Driven Development for AI Code Generation**
58
+
59
+ Shotgun is a CLI tool that turns work with AI code-gen tools from "I want to build X" into: **research → specs → plans → tasks → implementation**. It reads your entire codebase, coordinates AI agents to do the heavy lifting, and exports clean artifacts in the agents.md format so your code-gen tools actually know what they're building.
60
+
61
+ 🌐 **Learn more at [shotgun.sh](https://shotgun.sh/)**
62
+
63
+ ## Features
64
+
65
+ ### 📊 Complete Codebase Understanding
66
+
67
+ Before writing a single line, Shotgun reads all of it. Your patterns. Your dependencies. Your technical debt. Whether you're adding features, onboarding devs, planning migrations, or refactoring - Shotgun knows what you're working with.
68
+
69
+ ### 🔄 Five Modes. One Journey. Zero Gaps.
70
+
71
+ **Research** (what exists) → **Specify** (what to build) → **Plan** (how to build) → **Tasks** (break it down) → **Export** (to any tool)
72
+
73
+ Not another chatbot. A complete workflow where each mode feeds the next.
74
+
75
+ ### ➡️ Export to agents.md
76
+
77
+ Outputs plug into many code-generation tools including Codex, Cursor, Warp, Devin, opencode, Jules, and more.
78
+
79
+ ### 📝 Specs That Don't Die in Slack
80
+
81
+ Every research finding, every architectural decision, every "here's why we didn't use that library" - captured as markdown in your repo. Version controlled. Searchable.
82
+
83
+ ## Installation
84
+
85
+ ### Using pipx (Recommended)
86
+
87
+ ```bash
88
+ pipx install shotgun-sh
89
+ ```
90
+
91
+ **Why pipx?** It installs Shotgun in an isolated environment, preventing dependency conflicts with your other Python projects.
92
+
93
+ ### Using pip
94
+
95
+ ```bash
96
+ pip install shotgun-sh
97
+ ```
98
+
99
+ ## Quick Start
100
+
101
+ ```bash
102
+ # Research your codebase or a topic
103
+ shotgun research "What is our authentication flow?"
104
+
105
+ # Generate specifications
106
+ shotgun spec "Add OAuth2 authentication"
107
+
108
+ # Create an implementation plan
109
+ shotgun plan "Build user dashboard"
110
+
111
+ # Break down into tasks
112
+ shotgun tasks "Implement payment system"
113
+
114
+ # Export to agents.md format for your code-gen tools
115
+ shotgun export
116
+ ```
117
+
118
+ ## Support
119
+
120
+ Have questions? Join our community on **[Discord](https://discord.gg/5RmY6J2N7s)**
121
+
122
+ ---
123
+
124
+ **License:** MIT
125
+ **Python:** 3.11+
@@ -0,0 +1,71 @@
1
+ # Shotgun
2
+
3
+ **Spec-Driven Development for AI Code Generation**
4
+
5
+ Shotgun is a CLI tool that turns work with AI code-gen tools from "I want to build X" into: **research → specs → plans → tasks → implementation**. It reads your entire codebase, coordinates AI agents to do the heavy lifting, and exports clean artifacts in the agents.md format so your code-gen tools actually know what they're building.
6
+
7
+ 🌐 **Learn more at [shotgun.sh](https://shotgun.sh/)**
8
+
9
+ ## Features
10
+
11
+ ### 📊 Complete Codebase Understanding
12
+
13
+ Before writing a single line, Shotgun reads all of it. Your patterns. Your dependencies. Your technical debt. Whether you're adding features, onboarding devs, planning migrations, or refactoring - Shotgun knows what you're working with.
14
+
15
+ ### 🔄 Five Modes. One Journey. Zero Gaps.
16
+
17
+ **Research** (what exists) → **Specify** (what to build) → **Plan** (how to build) → **Tasks** (break it down) → **Export** (to any tool)
18
+
19
+ Not another chatbot. A complete workflow where each mode feeds the next.
20
+
21
+ ### ➡️ Export to agents.md
22
+
23
+ Outputs plug into many code-generation tools including Codex, Cursor, Warp, Devin, opencode, Jules, and more.
24
+
25
+ ### 📝 Specs That Don't Die in Slack
26
+
27
+ Every research finding, every architectural decision, every "here's why we didn't use that library" - captured as markdown in your repo. Version controlled. Searchable.
28
+
29
+ ## Installation
30
+
31
+ ### Using pipx (Recommended)
32
+
33
+ ```bash
34
+ pipx install shotgun-sh
35
+ ```
36
+
37
+ **Why pipx?** It installs Shotgun in an isolated environment, preventing dependency conflicts with your other Python projects.
38
+
39
+ ### Using pip
40
+
41
+ ```bash
42
+ pip install shotgun-sh
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # Research your codebase or a topic
49
+ shotgun research "What is our authentication flow?"
50
+
51
+ # Generate specifications
52
+ shotgun spec "Add OAuth2 authentication"
53
+
54
+ # Create an implementation plan
55
+ shotgun plan "Build user dashboard"
56
+
57
+ # Break down into tasks
58
+ shotgun tasks "Implement payment system"
59
+
60
+ # Export to agents.md format for your code-gen tools
61
+ shotgun export
62
+ ```
63
+
64
+ ## Support
65
+
66
+ Have questions? Join our community on **[Discord](https://discord.gg/5RmY6J2N7s)**
67
+
68
+ ---
69
+
70
+ **License:** MIT
71
+ **Python:** 3.11+
@@ -1,8 +1,8 @@
1
1
  [project]
2
2
  name = "shotgun-sh"
3
- version = "0.2.6.dev5"
3
+ version = "0.2.7.dev1"
4
4
  description = "AI-powered research, planning, and task management CLI tool"
5
- readme = "README.md"
5
+ readme = "README_PYPI.md"
6
6
  license = { text = "MIT" }
7
7
  authors = [
8
8
  { name = "Proofs.io", email = "hello@proofs.io" }
@@ -76,6 +76,7 @@ packages = ["src/shotgun"]
76
76
  include = [
77
77
  "/src",
78
78
  "/README.md",
79
+ "/README_PYPI.md",
79
80
  "/LICENSE",
80
81
  "/pyproject.toml"
81
82
  ]
@@ -1,10 +1,13 @@
1
1
  """Agent manager for coordinating multiple AI agents with shared message history."""
2
2
 
3
+ import json
3
4
  import logging
4
5
  from collections.abc import AsyncIterable, Sequence
5
6
  from dataclasses import dataclass, field, is_dataclass, replace
6
7
  from typing import TYPE_CHECKING, Any, cast
7
8
 
9
+ import logfire
10
+
8
11
  if TYPE_CHECKING:
9
12
  from shotgun.agents.conversation_history import ConversationState
10
13
 
@@ -401,6 +404,24 @@ class AgentManager(Widget):
401
404
  else None,
402
405
  **kwargs,
403
406
  )
407
+ except Exception as e:
408
+ # Log the error with full stack trace to shotgun.log and Logfire
409
+ logger.exception(
410
+ "Agent execution failed",
411
+ extra={
412
+ "agent_mode": self._current_agent_type.value,
413
+ "model_name": model_name,
414
+ "error_type": type(e).__name__,
415
+ },
416
+ )
417
+ logfire.exception(
418
+ "Agent execution failed",
419
+ agent_mode=self._current_agent_type.value,
420
+ model_name=model_name,
421
+ error_type=type(e).__name__,
422
+ )
423
+ # Re-raise to let TUI handle user messaging
424
+ raise
404
425
  finally:
405
426
  self._stream_state = None
406
427
 
@@ -468,7 +489,33 @@ class AgentManager(Widget):
468
489
 
469
490
  # Apply compaction to persistent message history to prevent cascading growth
470
491
  all_messages = result.all_messages()
471
- self.message_history = await apply_persistent_compaction(all_messages, deps)
492
+ try:
493
+ logger.debug(
494
+ "Starting message history compaction",
495
+ extra={"message_count": len(all_messages)},
496
+ )
497
+ self.message_history = await apply_persistent_compaction(all_messages, deps)
498
+ logger.debug(
499
+ "Completed message history compaction",
500
+ extra={
501
+ "original_count": len(all_messages),
502
+ "compacted_count": len(self.message_history),
503
+ },
504
+ )
505
+ except Exception as e:
506
+ # If compaction fails, log full error with stack trace and use uncompacted messages
507
+ logger.error(
508
+ "Failed to compact message history - using uncompacted messages",
509
+ exc_info=True,
510
+ extra={
511
+ "error": str(e),
512
+ "message_count": len(all_messages),
513
+ "agent_mode": self._current_agent_type.value,
514
+ },
515
+ )
516
+ # Fallback: use uncompacted messages to prevent data loss
517
+ self.message_history = all_messages
518
+
472
519
  usage = result.usage()
473
520
  deps.usage_manager.add_usage(
474
521
  usage, model_name=deps.llm_model.name, provider=deps.llm_model.provider
@@ -554,6 +601,39 @@ class AgentManager(Widget):
554
601
  # Detect source from call stack
555
602
  source = detect_source()
556
603
 
604
+ # Log if tool call has incomplete args (for debugging truncated JSON)
605
+ if isinstance(event.part.args, str):
606
+ try:
607
+ json.loads(event.part.args)
608
+ except (json.JSONDecodeError, ValueError):
609
+ args_preview = (
610
+ event.part.args[:100] + "..."
611
+ if len(event.part.args) > 100
612
+ else event.part.args
613
+ )
614
+ logger.warning(
615
+ "FunctionToolCallEvent received with incomplete JSON args",
616
+ extra={
617
+ "tool_name": event.part.tool_name,
618
+ "tool_call_id": event.part.tool_call_id,
619
+ "args_preview": args_preview,
620
+ "args_length": len(event.part.args)
621
+ if event.part.args
622
+ else 0,
623
+ "agent_mode": self._current_agent_type.value,
624
+ },
625
+ )
626
+ logfire.warn(
627
+ "FunctionToolCallEvent received with incomplete JSON args",
628
+ tool_name=event.part.tool_name,
629
+ tool_call_id=event.part.tool_call_id,
630
+ args_preview=args_preview,
631
+ args_length=len(event.part.args)
632
+ if event.part.args
633
+ else 0,
634
+ agent_mode=self._current_agent_type.value,
635
+ )
636
+
557
637
  track_event(
558
638
  "tool_called",
559
639
  {
@@ -0,0 +1,227 @@
1
+ """Models and utilities for persisting TUI conversation history."""
2
+
3
+ import json
4
+ import logging
5
+ from datetime import datetime
6
+ from typing import Any, cast
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+ from pydantic_ai.messages import (
10
+ ModelMessage,
11
+ ModelMessagesTypeAdapter,
12
+ ModelResponse,
13
+ ToolCallPart,
14
+ )
15
+ from pydantic_core import to_jsonable_python
16
+
17
+ from shotgun.tui.screens.chat_screen.hint_message import HintMessage
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ SerializedMessage = dict[str, Any]
22
+
23
+
24
+ def is_tool_call_complete(tool_call: ToolCallPart) -> bool:
25
+ """Check if a tool call has valid, complete JSON arguments.
26
+
27
+ Args:
28
+ tool_call: The tool call part to validate
29
+
30
+ Returns:
31
+ True if the tool call args are valid JSON, False otherwise
32
+ """
33
+ if tool_call.args is None:
34
+ return True # No args is valid
35
+
36
+ if isinstance(tool_call.args, dict):
37
+ return True # Already parsed dict is valid
38
+
39
+ if not isinstance(tool_call.args, str):
40
+ return False
41
+
42
+ # Try to parse the JSON string
43
+ try:
44
+ json.loads(tool_call.args)
45
+ return True
46
+ except (json.JSONDecodeError, ValueError) as e:
47
+ # Log incomplete tool call detection
48
+ args_preview = (
49
+ tool_call.args[:100] + "..."
50
+ if len(tool_call.args) > 100
51
+ else tool_call.args
52
+ )
53
+ logger.info(
54
+ "Detected incomplete tool call in validation",
55
+ extra={
56
+ "tool_name": tool_call.tool_name,
57
+ "tool_call_id": tool_call.tool_call_id,
58
+ "args_preview": args_preview,
59
+ "error": str(e),
60
+ },
61
+ )
62
+ return False
63
+
64
+
65
+ def filter_incomplete_messages(messages: list[ModelMessage]) -> list[ModelMessage]:
66
+ """Filter out messages with incomplete tool calls.
67
+
68
+ Args:
69
+ messages: List of messages to filter
70
+
71
+ Returns:
72
+ List of messages with only complete tool calls
73
+ """
74
+ filtered: list[ModelMessage] = []
75
+ filtered_count = 0
76
+ filtered_tool_names: list[str] = []
77
+
78
+ for message in messages:
79
+ # Only check ModelResponse messages for tool calls
80
+ if not isinstance(message, ModelResponse):
81
+ filtered.append(message)
82
+ continue
83
+
84
+ # Check if any tool calls are incomplete
85
+ has_incomplete_tool_call = False
86
+ for part in message.parts:
87
+ if isinstance(part, ToolCallPart) and not is_tool_call_complete(part):
88
+ has_incomplete_tool_call = True
89
+ filtered_tool_names.append(part.tool_name)
90
+ break
91
+
92
+ # Only include messages without incomplete tool calls
93
+ if not has_incomplete_tool_call:
94
+ filtered.append(message)
95
+ else:
96
+ filtered_count += 1
97
+
98
+ # Log if any messages were filtered
99
+ if filtered_count > 0:
100
+ logger.info(
101
+ "Filtered incomplete messages before saving",
102
+ extra={
103
+ "filtered_count": filtered_count,
104
+ "total_messages": len(messages),
105
+ "filtered_tool_names": filtered_tool_names,
106
+ },
107
+ )
108
+
109
+ return filtered
110
+
111
+
112
+ class ConversationState(BaseModel):
113
+ """Represents the complete state of a conversation in memory."""
114
+
115
+ agent_messages: list[ModelMessage]
116
+ ui_messages: list[ModelMessage | HintMessage] = Field(default_factory=list)
117
+ agent_type: str # Will store AgentType.value
118
+
119
+ model_config = ConfigDict(arbitrary_types_allowed=True)
120
+
121
+
122
+ class ConversationHistory(BaseModel):
123
+ """Persistent conversation history for TUI sessions."""
124
+
125
+ version: int = 1
126
+ agent_history: list[SerializedMessage] = Field(
127
+ default_factory=list
128
+ ) # Stores serialized ModelMessage objects
129
+ ui_history: list[SerializedMessage] = Field(
130
+ default_factory=list
131
+ ) # Stores serialized ModelMessage and HintMessage objects
132
+ last_agent_model: str = "research"
133
+ updated_at: datetime = Field(default_factory=datetime.now)
134
+
135
+ model_config = ConfigDict(arbitrary_types_allowed=True)
136
+
137
+ def set_agent_messages(self, messages: list[ModelMessage]) -> None:
138
+ """Set agent_history from a list of ModelMessage objects.
139
+
140
+ Args:
141
+ messages: List of ModelMessage objects to serialize and store
142
+ """
143
+ # Filter out messages with incomplete tool calls to prevent corruption
144
+ filtered_messages = filter_incomplete_messages(messages)
145
+
146
+ # Serialize ModelMessage list to JSON-serializable format
147
+ self.agent_history = to_jsonable_python(
148
+ filtered_messages, fallback=lambda x: str(x), exclude_none=True
149
+ )
150
+
151
+ def set_ui_messages(self, messages: list[ModelMessage | HintMessage]) -> None:
152
+ """Set ui_history from a list of UI messages."""
153
+
154
+ # Filter out ModelMessages with incomplete tool calls (keep all HintMessages)
155
+ # We need to maintain message order, so we'll check each message individually
156
+ filtered_messages: list[ModelMessage | HintMessage] = []
157
+
158
+ for msg in messages:
159
+ if isinstance(msg, HintMessage):
160
+ # Always keep hint messages
161
+ filtered_messages.append(msg)
162
+ elif isinstance(msg, ModelResponse):
163
+ # Check if this ModelResponse has incomplete tool calls
164
+ has_incomplete = False
165
+ for part in msg.parts:
166
+ if isinstance(part, ToolCallPart) and not is_tool_call_complete(
167
+ part
168
+ ):
169
+ has_incomplete = True
170
+ break
171
+
172
+ if not has_incomplete:
173
+ filtered_messages.append(msg)
174
+ else:
175
+ # Keep all other ModelMessage types (ModelRequest, etc.)
176
+ filtered_messages.append(msg)
177
+
178
+ def _serialize_message(
179
+ message: ModelMessage | HintMessage,
180
+ ) -> Any:
181
+ if isinstance(message, HintMessage):
182
+ data = message.model_dump()
183
+ data["message_type"] = "hint"
184
+ return data
185
+ payload = to_jsonable_python(
186
+ message, fallback=lambda x: str(x), exclude_none=True
187
+ )
188
+ if isinstance(payload, dict):
189
+ payload.setdefault("message_type", "model")
190
+ return payload
191
+
192
+ self.ui_history = [_serialize_message(msg) for msg in filtered_messages]
193
+
194
+ def get_agent_messages(self) -> list[ModelMessage]:
195
+ """Get agent_history as a list of ModelMessage objects.
196
+
197
+ Returns:
198
+ List of deserialized ModelMessage objects
199
+ """
200
+ if not self.agent_history:
201
+ return []
202
+
203
+ # Deserialize from JSON format back to ModelMessage objects
204
+ return ModelMessagesTypeAdapter.validate_python(self.agent_history)
205
+
206
+ def get_ui_messages(self) -> list[ModelMessage | HintMessage]:
207
+ """Get ui_history as a list of Model or hint messages."""
208
+
209
+ if not self.ui_history:
210
+ # Fallback for older conversation files without UI history
211
+ return cast(list[ModelMessage | HintMessage], self.get_agent_messages())
212
+
213
+ messages: list[ModelMessage | HintMessage] = []
214
+ for item in self.ui_history:
215
+ message_type = item.get("message_type") if isinstance(item, dict) else None
216
+ if message_type == "hint":
217
+ messages.append(HintMessage.model_validate(item))
218
+ continue
219
+
220
+ # Backwards compatibility: data may not include the type marker
221
+ payload = item
222
+ if isinstance(payload, dict):
223
+ payload = {k: v for k, v in payload.items() if k != "message_type"}
224
+ deserialized = ModelMessagesTypeAdapter.validate_python([payload])
225
+ messages.append(deserialized[0])
226
+
227
+ return messages
@@ -1,6 +1,7 @@
1
1
  """Manager for handling conversation persistence operations."""
2
2
 
3
3
  import json
4
+ import shutil
4
5
  from pathlib import Path
5
6
 
6
7
  from shotgun.logging_config import get_logger
@@ -77,9 +78,30 @@ class ConversationManager:
77
78
  )
78
79
  return conversation
79
80
 
80
- except Exception as e:
81
+ except (json.JSONDecodeError, ValueError) as e:
82
+ # Handle corrupted JSON or validation errors
83
+ logger.error(
84
+ "Corrupted conversation file at %s: %s. Creating backup and starting fresh.",
85
+ self.conversation_path,
86
+ e,
87
+ )
88
+
89
+ # Create a backup of the corrupted file for debugging
90
+ backup_path = self.conversation_path.with_suffix(".json.backup")
91
+ try:
92
+ shutil.copy2(self.conversation_path, backup_path)
93
+ logger.info("Backed up corrupted conversation to %s", backup_path)
94
+ except Exception as backup_error: # pragma: no cover
95
+ logger.warning("Failed to backup corrupted file: %s", backup_error)
96
+
97
+ return None
98
+
99
+ except Exception as e: # pragma: no cover
100
+ # Catch-all for unexpected errors
81
101
  logger.error(
82
- "Failed to load conversation from %s: %s", self.conversation_path, e
102
+ "Unexpected error loading conversation from %s: %s",
103
+ self.conversation_path,
104
+ e,
83
105
  )
84
106
  return None
85
107