shotgun-sh 0.2.1.dev4__tar.gz → 0.2.1.dev6__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 (154) hide show
  1. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/PKG-INFO +1 -1
  2. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/pyproject.toml +1 -1
  3. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/config/constants.py +2 -1
  4. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/config/manager.py +68 -13
  5. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/config/models.py +11 -2
  6. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/config.py +6 -6
  7. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/feedback.py +4 -2
  8. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/ingestor.py +47 -8
  9. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/manager.py +7 -3
  10. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/posthog_telemetry.py +10 -8
  11. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sentry_telemetry.py +3 -3
  12. shotgun_sh-0.2.1.dev6/src/shotgun/shotgun_web/__init__.py +19 -0
  13. shotgun_sh-0.2.1.dev6/src/shotgun/shotgun_web/client.py +138 -0
  14. shotgun_sh-0.2.1.dev6/src/shotgun/shotgun_web/constants.py +17 -0
  15. shotgun_sh-0.2.1.dev6/src/shotgun/shotgun_web/models.py +47 -0
  16. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/telemetry.py +7 -4
  17. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/app.py +21 -7
  18. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/feedback.py +2 -2
  19. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/provider_config.py +61 -2
  20. shotgun_sh-0.2.1.dev6/src/shotgun/tui/screens/shotgun_auth.py +295 -0
  21. shotgun_sh-0.2.1.dev6/src/shotgun/tui/screens/welcome.py +176 -0
  22. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/.gitignore +0 -0
  23. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/LICENSE +0 -0
  24. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/README.md +0 -0
  25. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/hatch_build.py +0 -0
  26. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/__init__.py +0 -0
  27. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/__init__.py +0 -0
  28. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/agent_manager.py +0 -0
  29. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/common.py +0 -0
  30. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/config/__init__.py +0 -0
  31. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/config/provider.py +0 -0
  32. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/conversation_history.py +0 -0
  33. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/conversation_manager.py +0 -0
  34. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/export.py +0 -0
  35. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/__init__.py +0 -0
  36. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/compaction.py +0 -0
  37. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/constants.py +0 -0
  38. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/context_extraction.py +0 -0
  39. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/history_building.py +0 -0
  40. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/history_processors.py +0 -0
  41. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/message_utils.py +0 -0
  42. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/__init__.py +0 -0
  43. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/anthropic.py +0 -0
  44. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/base.py +0 -0
  45. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/openai.py +0 -0
  46. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/sentencepiece_counter.py +0 -0
  47. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/tokenizer_cache.py +0 -0
  48. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_counting/utils.py +0 -0
  49. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/history/token_estimation.py +0 -0
  50. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/llm.py +0 -0
  51. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/messages.py +0 -0
  52. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/models.py +0 -0
  53. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/plan.py +0 -0
  54. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/research.py +0 -0
  55. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/specify.py +0 -0
  56. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tasks.py +0 -0
  57. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/__init__.py +0 -0
  58. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
  59. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
  60. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
  61. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
  62. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/models.py +0 -0
  63. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
  64. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
  65. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/file_management.py +0 -0
  66. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/user_interaction.py +0 -0
  67. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
  68. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
  69. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
  70. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/web_search/openai.py +0 -0
  71. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/tools/web_search/utils.py +0 -0
  72. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/agents/usage_manager.py +0 -0
  73. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/build_constants.py +0 -0
  74. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/__init__.py +0 -0
  75. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/codebase/__init__.py +0 -0
  76. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/codebase/commands.py +0 -0
  77. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/codebase/models.py +0 -0
  78. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/export.py +0 -0
  79. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/models.py +0 -0
  80. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/plan.py +0 -0
  81. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/research.py +0 -0
  82. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/specify.py +0 -0
  83. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/tasks.py +0 -0
  84. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/update.py +0 -0
  85. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/cli/utils.py +0 -0
  86. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/__init__.py +0 -0
  87. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/__init__.py +0 -0
  88. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/change_detector.py +0 -0
  89. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/code_retrieval.py +0 -0
  90. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/cypher_models.py +0 -0
  91. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/language_config.py +0 -0
  92. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/nl_query.py +0 -0
  93. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/core/parser_loader.py +0 -0
  94. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/models.py +0 -0
  95. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/codebase/service.py +0 -0
  96. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/llm_proxy/__init__.py +0 -0
  97. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/llm_proxy/clients.py +0 -0
  98. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/llm_proxy/constants.py +0 -0
  99. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/logging_config.py +0 -0
  100. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/main.py +0 -0
  101. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/__init__.py +0 -0
  102. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/__init__.py +0 -0
  103. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/export.j2 +0 -0
  104. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
  105. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
  106. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
  107. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
  108. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/plan.j2 +0 -0
  109. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/research.j2 +0 -0
  110. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/specify.j2 +0 -0
  111. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
  112. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
  113. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/agents/tasks.j2 +0 -0
  114. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/__init__.py +0 -0
  115. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
  116. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
  117. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
  118. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
  119. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
  120. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
  121. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/history/__init__.py +0 -0
  122. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
  123. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/history/summarization.j2 +0 -0
  124. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/prompts/loader.py +0 -0
  125. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/py.typed +0 -0
  126. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sdk/__init__.py +0 -0
  127. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sdk/codebase.py +0 -0
  128. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sdk/exceptions.py +0 -0
  129. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sdk/models.py +0 -0
  130. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/sdk/services.py +0 -0
  131. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/__init__.py +0 -0
  132. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/commands/__init__.py +0 -0
  133. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/components/prompt_input.py +0 -0
  134. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/components/spinner.py +0 -0
  135. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/components/splash.py +0 -0
  136. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/components/vertical_tail.py +0 -0
  137. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/filtered_codebase_service.py +0 -0
  138. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat.py +0 -0
  139. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat.tcss +0 -0
  140. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
  141. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat_screen/command_providers.py +0 -0
  142. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat_screen/hint_message.py +0 -0
  143. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/chat_screen/history.py +0 -0
  144. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/directory_setup.py +0 -0
  145. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/model_picker.py +0 -0
  146. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/screens/splash.py +0 -0
  147. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/styles.tcss +0 -0
  148. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/utils/__init__.py +0 -0
  149. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/tui/utils/mode_progress.py +0 -0
  150. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/utils/__init__.py +0 -0
  151. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/utils/env_utils.py +0 -0
  152. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/utils/file_system_utils.py +0 -0
  153. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/src/shotgun/utils/source_detection.py +0 -0
  154. {shotgun_sh-0.2.1.dev4 → shotgun_sh-0.2.1.dev6}/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.dev4
3
+ Version: 0.2.1.dev6
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.dev4"
3
+ version = "0.2.1.dev6"
4
4
  description = "AI-powered research, planning, and task management CLI tool"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -4,7 +4,8 @@ from enum import StrEnum, auto
4
4
 
5
5
  # Field names
6
6
  API_KEY_FIELD = "api_key"
7
- USER_ID_FIELD = "user_id"
7
+ SUPABASE_JWT_FIELD = "supabase_jwt"
8
+ SHOTGUN_INSTANCE_ID_FIELD = "shotgun_instance_id"
8
9
  CONFIG_VERSION_FIELD = "config_version"
9
10
 
10
11
 
@@ -12,6 +12,8 @@ from shotgun.utils import get_shotgun_home
12
12
 
13
13
  from .constants import (
14
14
  API_KEY_FIELD,
15
+ SHOTGUN_INSTANCE_ID_FIELD,
16
+ SUPABASE_JWT_FIELD,
15
17
  ConfigSection,
16
18
  )
17
19
  from .models import (
@@ -60,10 +62,10 @@ class ConfigManager:
60
62
 
61
63
  if not self.config_path.exists():
62
64
  logger.info(
63
- "Configuration file not found, creating new config with user_id: %s",
65
+ "Configuration file not found, creating new config at: %s",
64
66
  self.config_path,
65
67
  )
66
- # Create new config with generated user_id
68
+ # Create new config with generated shotgun_instance_id
67
69
  self._config = self.initialize()
68
70
  return self._config
69
71
 
@@ -71,6 +73,14 @@ class ConfigManager:
71
73
  with open(self.config_path, encoding="utf-8") as f:
72
74
  data = json.load(f)
73
75
 
76
+ # Migration: Rename user_id to shotgun_instance_id (config v2 -> v3)
77
+ if "user_id" in data and SHOTGUN_INSTANCE_ID_FIELD not in data:
78
+ data[SHOTGUN_INSTANCE_ID_FIELD] = data.pop("user_id")
79
+ data["config_version"] = 3
80
+ logger.info(
81
+ "Migrated config v2->v3: renamed user_id to shotgun_instance_id"
82
+ )
83
+
74
84
  # Convert plain text secrets to SecretStr objects
75
85
  self._convert_secrets_to_secretstr(data)
76
86
 
@@ -134,7 +144,7 @@ class ConfigManager:
134
144
  logger.error(
135
145
  "Failed to load configuration from %s: %s", self.config_path, e
136
146
  )
137
- logger.info("Creating new configuration with generated user_id")
147
+ logger.info("Creating new configuration with generated shotgun_instance_id")
138
148
  self._config = self.initialize()
139
149
  return self._config
140
150
 
@@ -148,9 +158,9 @@ class ConfigManager:
148
158
  if self._config:
149
159
  config = self._config
150
160
  else:
151
- # Create a new config with generated user_id
161
+ # Create a new config with generated shotgun_instance_id
152
162
  config = ShotgunConfig(
153
- user_id=str(uuid.uuid4()),
163
+ shotgun_instance_id=str(uuid.uuid4()),
154
164
  )
155
165
 
156
166
  # Ensure directory exists
@@ -276,15 +286,15 @@ class ConfigManager:
276
286
  Returns:
277
287
  Default ShotgunConfig
278
288
  """
279
- # Generate unique user ID for new config
289
+ # Generate unique shotgun instance ID for new config
280
290
  config = ShotgunConfig(
281
- user_id=str(uuid.uuid4()),
291
+ shotgun_instance_id=str(uuid.uuid4()),
282
292
  )
283
293
  self.save(config)
284
294
  logger.info(
285
- "Configuration initialized at %s with user_id: %s",
295
+ "Configuration initialized at %s with shotgun_instance_id: %s",
286
296
  self.config_path,
287
- config.user_id,
297
+ config.shotgun_instance_id,
288
298
  )
289
299
  return config
290
300
 
@@ -292,6 +302,7 @@ class ConfigManager:
292
302
  """Convert plain text secrets in data to SecretStr objects."""
293
303
  for section in ConfigSection:
294
304
  if section.value in data and isinstance(data[section.value], dict):
305
+ # Convert API key
295
306
  if (
296
307
  API_KEY_FIELD in data[section.value]
297
308
  and data[section.value][API_KEY_FIELD] is not None
@@ -299,11 +310,21 @@ class ConfigManager:
299
310
  data[section.value][API_KEY_FIELD] = SecretStr(
300
311
  data[section.value][API_KEY_FIELD]
301
312
  )
313
+ # Convert supabase JWT (shotgun section only)
314
+ if (
315
+ section == ConfigSection.SHOTGUN
316
+ and SUPABASE_JWT_FIELD in data[section.value]
317
+ and data[section.value][SUPABASE_JWT_FIELD] is not None
318
+ ):
319
+ data[section.value][SUPABASE_JWT_FIELD] = SecretStr(
320
+ data[section.value][SUPABASE_JWT_FIELD]
321
+ )
302
322
 
303
323
  def _convert_secretstr_to_plain(self, data: dict[str, Any]) -> None:
304
324
  """Convert SecretStr objects in data to plain text for JSON serialization."""
305
325
  for section in ConfigSection:
306
326
  if section.value in data and isinstance(data[section.value], dict):
327
+ # Convert API key
307
328
  if (
308
329
  API_KEY_FIELD in data[section.value]
309
330
  and data[section.value][API_KEY_FIELD] is not None
@@ -312,6 +333,18 @@ class ConfigManager:
312
333
  data[section.value][API_KEY_FIELD] = data[section.value][
313
334
  API_KEY_FIELD
314
335
  ].get_secret_value()
336
+ # Convert supabase JWT (shotgun section only)
337
+ if (
338
+ section == ConfigSection.SHOTGUN
339
+ and SUPABASE_JWT_FIELD in data[section.value]
340
+ and data[section.value][SUPABASE_JWT_FIELD] is not None
341
+ ):
342
+ if hasattr(
343
+ data[section.value][SUPABASE_JWT_FIELD], "get_secret_value"
344
+ ):
345
+ data[section.value][SUPABASE_JWT_FIELD] = data[section.value][
346
+ SUPABASE_JWT_FIELD
347
+ ].get_secret_value()
315
348
 
316
349
  def _ensure_provider_enum(self, provider: ProviderType | str) -> ProviderType:
317
350
  """Normalize provider values to ProviderType enum."""
@@ -376,14 +409,36 @@ class ConfigManager:
376
409
  provider_enum = self._ensure_provider_enum(provider)
377
410
  return (self._get_provider_config(config, provider_enum), False)
378
411
 
379
- def get_user_id(self) -> str:
380
- """Get the user ID from configuration.
412
+ def get_shotgun_instance_id(self) -> str:
413
+ """Get the shotgun instance ID from configuration.
381
414
 
382
415
  Returns:
383
- The unique user ID string
416
+ The unique shotgun instance ID string
417
+ """
418
+ config = self.load()
419
+ return config.shotgun_instance_id
420
+
421
+ def update_shotgun_account(
422
+ self, api_key: str | None = None, supabase_jwt: str | None = None
423
+ ) -> None:
424
+ """Update Shotgun Account configuration.
425
+
426
+ Args:
427
+ api_key: LiteLLM proxy API key (optional)
428
+ supabase_jwt: Supabase authentication JWT (optional)
384
429
  """
385
430
  config = self.load()
386
- return config.user_id
431
+
432
+ if api_key is not None:
433
+ config.shotgun.api_key = SecretStr(api_key) if api_key else None
434
+
435
+ if supabase_jwt is not None:
436
+ config.shotgun.supabase_jwt = (
437
+ SecretStr(supabase_jwt) if supabase_jwt else None
438
+ )
439
+
440
+ self.save(config)
441
+ logger.info("Updated Shotgun Account configuration")
387
442
 
388
443
 
389
444
  # Global singleton instance
@@ -149,6 +149,9 @@ class ShotgunAccountConfig(BaseModel):
149
149
  """Configuration for Shotgun Account (LiteLLM proxy)."""
150
150
 
151
151
  api_key: SecretStr | None = None
152
+ supabase_jwt: SecretStr | None = Field(
153
+ default=None, description="Supabase authentication JWT"
154
+ )
152
155
 
153
156
 
154
157
  class ShotgunConfig(BaseModel):
@@ -162,5 +165,11 @@ class ShotgunConfig(BaseModel):
162
165
  default=None,
163
166
  description="User-selected model",
164
167
  )
165
- user_id: str = Field(description="Unique anonymous user identifier")
166
- config_version: int = Field(default=2, description="Configuration schema version")
168
+ shotgun_instance_id: str = Field(
169
+ description="Unique shotgun instance identifier (also used for anonymous telemetry)",
170
+ )
171
+ config_version: int = Field(default=3, description="Configuration schema version")
172
+ shown_welcome_screen: bool = Field(
173
+ default=False,
174
+ description="Whether the welcome screen has been shown to the user",
175
+ )
@@ -233,14 +233,14 @@ def _mask_value(value: str) -> str:
233
233
 
234
234
 
235
235
  @app.command()
236
- def get_user_id() -> None:
237
- """Get the anonymous user ID from configuration."""
236
+ def get_shotgun_instance_id() -> None:
237
+ """Get the anonymous shotgun instance ID from configuration."""
238
238
  config_manager = get_config_manager()
239
239
 
240
240
  try:
241
- user_id = config_manager.get_user_id()
242
- console.print(f"[green]User ID:[/green] {user_id}")
241
+ shotgun_instance_id = config_manager.get_shotgun_instance_id()
242
+ console.print(f"[green]Shotgun Instance ID:[/green] {shotgun_instance_id}")
243
243
  except Exception as e:
244
- logger.error(f"Error getting user ID: {e}")
245
- console.print(f"❌ Failed to get user ID: {str(e)}", style="red")
244
+ logger.error(f"Error getting shotgun instance ID: {e}")
245
+ console.print(f"❌ Failed to get shotgun instance ID: {str(e)}", style="red")
246
246
  raise typer.Exit(1) from e
@@ -30,7 +30,7 @@ def send_feedback(
30
30
  """Initialize Shotgun configuration."""
31
31
  config_manager = get_config_manager()
32
32
  config_manager.load()
33
- user_id = config_manager.get_user_id()
33
+ shotgun_instance_id = config_manager.get_shotgun_instance_id()
34
34
 
35
35
  if not description:
36
36
  console.print(
@@ -39,7 +39,9 @@ def send_feedback(
39
39
  )
40
40
  raise typer.Exit(1)
41
41
 
42
- feedback = Feedback(kind=kind, description=description, user_id=user_id)
42
+ feedback = Feedback(
43
+ kind=kind, description=description, shotgun_instance_id=shotgun_instance_id
44
+ )
43
45
 
44
46
  submit_feedback_survey(feedback)
45
47
 
@@ -18,15 +18,12 @@ from shotgun.logging_config import get_logger
18
18
  logger = get_logger(__name__)
19
19
 
20
20
 
21
- # Default ignore patterns
22
- IGNORE_PATTERNS = {
21
+ # Directories that should never be traversed during indexing
22
+ BASE_IGNORE_DIRECTORIES = {
23
23
  ".git",
24
24
  "venv",
25
25
  ".venv",
26
26
  "__pycache__",
27
- "node_modules",
28
- "build",
29
- "dist",
30
27
  ".eggs",
31
28
  ".pytest_cache",
32
29
  ".mypy_cache",
@@ -36,6 +33,46 @@ IGNORE_PATTERNS = {
36
33
  ".vscode",
37
34
  }
38
35
 
36
+ # Well-known build output directories to skip when determining source files
37
+ BUILD_ARTIFACT_DIRECTORIES = {
38
+ "node_modules",
39
+ ".next",
40
+ ".nuxt",
41
+ ".vite",
42
+ ".yarn",
43
+ ".svelte-kit",
44
+ ".output",
45
+ ".turbo",
46
+ ".parcel-cache",
47
+ ".vercel",
48
+ ".serverless",
49
+ "build",
50
+ "dist",
51
+ "out",
52
+ "tmp",
53
+ "coverage",
54
+ }
55
+
56
+ # Default ignore patterns combines base directories and build artifacts
57
+ IGNORE_PATTERNS = BASE_IGNORE_DIRECTORIES | BUILD_ARTIFACT_DIRECTORIES
58
+
59
+ # Directory prefixes that should always be ignored
60
+ IGNORED_DIRECTORY_PREFIXES = (".",)
61
+
62
+
63
+ def should_ignore_directory(name: str, ignore_patterns: set[str] | None = None) -> bool:
64
+ """Return True if the directory name should be ignored."""
65
+ patterns = IGNORE_PATTERNS if ignore_patterns is None else ignore_patterns
66
+ if name in patterns:
67
+ return True
68
+ return name.startswith(IGNORED_DIRECTORY_PREFIXES)
69
+
70
+
71
+ def is_path_ignored(path: Path, ignore_patterns: set[str] | None = None) -> bool:
72
+ """Return True if any part of the path should be ignored."""
73
+ patterns = IGNORE_PATTERNS if ignore_patterns is None else ignore_patterns
74
+ return any(should_ignore_directory(part, patterns) for part in path.parts)
75
+
39
76
 
40
77
  class Ingestor:
41
78
  """Handles all communication and ingestion with the Kuzu database."""
@@ -607,7 +644,9 @@ class SimpleGraphBuilder:
607
644
  """First pass: Walk directory to find packages and folders."""
608
645
  dir_count = 0
609
646
  for root_str, dirs, _ in os.walk(self.repo_path, topdown=True):
610
- dirs[:] = [d for d in dirs if d not in self.ignore_dirs]
647
+ dirs[:] = [
648
+ d for d in dirs if not should_ignore_directory(d, self.ignore_dirs)
649
+ ]
611
650
  root = Path(root_str)
612
651
  relative_root = root.relative_to(self.repo_path)
613
652
 
@@ -740,7 +779,7 @@ class SimpleGraphBuilder:
740
779
  root = Path(root_str)
741
780
 
742
781
  # Skip ignored directories
743
- if any(part in self.ignore_dirs for part in root.parts):
782
+ if is_path_ignored(root, self.ignore_dirs):
744
783
  continue
745
784
 
746
785
  for filename in files:
@@ -757,7 +796,7 @@ class SimpleGraphBuilder:
757
796
  root = Path(root_str)
758
797
 
759
798
  # Skip ignored directories
760
- if any(part in self.ignore_dirs for part in root.parts):
799
+ if is_path_ignored(root, self.ignore_dirs):
761
800
  continue
762
801
 
763
802
  for filename in files:
@@ -51,9 +51,13 @@ class CodebaseFileHandler(FileSystemEventHandler):
51
51
  self.pending_changes: list[FileChange] = []
52
52
  self._lock = anyio.Lock()
53
53
  # Import default ignore patterns from ingestor
54
- from shotgun.codebase.core.ingestor import IGNORE_PATTERNS
54
+ from shotgun.codebase.core.ingestor import (
55
+ IGNORE_PATTERNS,
56
+ should_ignore_directory,
57
+ )
55
58
 
56
59
  self.ignore_patterns = ignore_patterns or IGNORE_PATTERNS
60
+ self._should_ignore_directory = should_ignore_directory
57
61
 
58
62
  def on_any_event(self, event: FileSystemEvent) -> None:
59
63
  """Handle any file system event."""
@@ -71,7 +75,7 @@ class CodebaseFileHandler(FileSystemEventHandler):
71
75
 
72
76
  # Check if any parent directory should be ignored
73
77
  for parent in path.parents:
74
- if parent.name in self.ignore_patterns:
78
+ if self._should_ignore_directory(parent.name, self.ignore_patterns):
75
79
  logger.debug(
76
80
  f"Ignoring file in ignored directory: {parent.name} - path: {src_path_str}"
77
81
  )
@@ -106,7 +110,7 @@ class CodebaseFileHandler(FileSystemEventHandler):
106
110
  )
107
111
  dest_path = Path(dest_path_str)
108
112
  for parent in dest_path.parents:
109
- if parent.name in self.ignore_patterns:
113
+ if self._should_ignore_directory(parent.name, self.ignore_patterns):
110
114
  logger.debug(
111
115
  f"Ignoring move to ignored directory: {parent.name} - dest_path: {dest_path_str}"
112
116
  )
@@ -51,14 +51,14 @@ def setup_posthog_observability() -> bool:
51
51
  # Store the client for later use
52
52
  _posthog_client = posthog
53
53
 
54
- # Set user context with anonymous user ID from config
54
+ # Set user context with anonymous shotgun instance ID from config
55
55
  try:
56
56
  config_manager = get_config_manager()
57
- user_id = config_manager.get_user_id()
57
+ shotgun_instance_id = config_manager.get_shotgun_instance_id()
58
58
 
59
59
  # Identify the user in PostHog
60
60
  posthog.identify( # type: ignore[attr-defined]
61
- distinct_id=user_id,
61
+ distinct_id=shotgun_instance_id,
62
62
  properties={
63
63
  "version": __version__,
64
64
  "environment": environment,
@@ -69,7 +69,9 @@ def setup_posthog_observability() -> bool:
69
69
  posthog.disabled = False
70
70
  posthog.personal_api_key = None # Not needed for event tracking
71
71
 
72
- logger.debug("PostHog user identified with anonymous ID: %s", user_id)
72
+ logger.debug(
73
+ "PostHog user identified with anonymous ID: %s", shotgun_instance_id
74
+ )
73
75
  except Exception as e:
74
76
  logger.warning("Failed to set user context: %s", e)
75
77
 
@@ -99,9 +101,9 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
99
101
  return
100
102
 
101
103
  try:
102
- # Get user ID for tracking
104
+ # Get shotgun instance ID for tracking
103
105
  config_manager = get_config_manager()
104
- user_id = config_manager.get_user_id()
106
+ shotgun_instance_id = config_manager.get_shotgun_instance_id()
105
107
 
106
108
  # Add version and environment to properties
107
109
  if properties is None:
@@ -116,7 +118,7 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
116
118
 
117
119
  # Track the event using PostHog's capture method
118
120
  _posthog_client.capture(
119
- distinct_id=user_id, event=event_name, properties=properties
121
+ distinct_id=shotgun_instance_id, event=event_name, properties=properties
120
122
  )
121
123
  logger.debug("Tracked PostHog event: %s", event_name)
122
124
  except Exception as e:
@@ -146,7 +148,7 @@ class FeedbackKind(StrEnum):
146
148
  class Feedback(BaseModel):
147
149
  kind: FeedbackKind
148
150
  description: str
149
- user_id: str
151
+ shotgun_instance_id: str
150
152
 
151
153
 
152
154
  SURVEY_ID = "01999f81-9486-0000-4fa6-9632959f92f3"
@@ -59,13 +59,13 @@ def setup_sentry_observability() -> bool:
59
59
  profiles_sample_rate=0.1 if environment == "production" else 1.0,
60
60
  )
61
61
 
62
- # Set user context with anonymous user ID from config
62
+ # Set user context with anonymous shotgun instance ID from config
63
63
  try:
64
64
  from shotgun.agents.config import get_config_manager
65
65
 
66
66
  config_manager = get_config_manager()
67
- user_id = config_manager.get_user_id()
68
- sentry_sdk.set_user({"id": user_id})
67
+ shotgun_instance_id = config_manager.get_shotgun_instance_id()
68
+ sentry_sdk.set_user({"id": shotgun_instance_id})
69
69
  logger.debug("Sentry user context set with anonymous ID")
70
70
  except Exception as e:
71
71
  logger.warning("Failed to set Sentry user context: %s", e)
@@ -0,0 +1,19 @@
1
+ """Shotgun Web API client for subscription and authentication."""
2
+
3
+ from .client import ShotgunWebClient, check_token_status, create_unification_token
4
+ from .models import (
5
+ TokenCreateRequest,
6
+ TokenCreateResponse,
7
+ TokenStatus,
8
+ TokenStatusResponse,
9
+ )
10
+
11
+ __all__ = [
12
+ "ShotgunWebClient",
13
+ "create_unification_token",
14
+ "check_token_status",
15
+ "TokenCreateRequest",
16
+ "TokenCreateResponse",
17
+ "TokenStatus",
18
+ "TokenStatusResponse",
19
+ ]
@@ -0,0 +1,138 @@
1
+ """HTTP client for Shotgun Web API."""
2
+
3
+ import httpx
4
+
5
+ from shotgun.logging_config import get_logger
6
+
7
+ from .constants import (
8
+ SHOTGUN_WEB_BASE_URL,
9
+ UNIFICATION_TOKEN_CREATE_PATH,
10
+ UNIFICATION_TOKEN_STATUS_PATH,
11
+ )
12
+ from .models import (
13
+ TokenCreateRequest,
14
+ TokenCreateResponse,
15
+ TokenStatusResponse,
16
+ )
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ class ShotgunWebClient:
22
+ """HTTP client for Shotgun Web API."""
23
+
24
+ def __init__(self, base_url: str | None = None, timeout: float = 10.0):
25
+ """Initialize Shotgun Web client.
26
+
27
+ Args:
28
+ base_url: Base URL for Shotgun Web API. If None, uses SHOTGUN_WEB_BASE_URL
29
+ timeout: Request timeout in seconds
30
+ """
31
+ self.base_url = base_url or SHOTGUN_WEB_BASE_URL
32
+ self.timeout = timeout
33
+
34
+ def create_unification_token(self, shotgun_instance_id: str) -> TokenCreateResponse:
35
+ """Create a unification token for CLI authentication.
36
+
37
+ Args:
38
+ shotgun_instance_id: UUID for this shotgun instance
39
+
40
+ Returns:
41
+ Token creation response with token and auth URL
42
+
43
+ Raises:
44
+ httpx.HTTPError: If request fails
45
+ """
46
+ url = f"{self.base_url}{UNIFICATION_TOKEN_CREATE_PATH}"
47
+ request_data = TokenCreateRequest(shotgun_instance_id=shotgun_instance_id)
48
+
49
+ logger.debug("Creating unification token for instance %s", shotgun_instance_id)
50
+
51
+ try:
52
+ response = httpx.post(
53
+ url,
54
+ json=request_data.model_dump(),
55
+ timeout=self.timeout,
56
+ )
57
+ response.raise_for_status()
58
+
59
+ data = response.json()
60
+ result = TokenCreateResponse.model_validate(data)
61
+
62
+ logger.info(
63
+ "Successfully created unification token, expires in %d seconds",
64
+ result.expires_in_seconds,
65
+ )
66
+ return result
67
+
68
+ except httpx.HTTPError as e:
69
+ logger.error("Failed to create unification token: %s", e)
70
+ raise
71
+
72
+ def check_token_status(self, token: str) -> TokenStatusResponse:
73
+ """Check token status and get keys if completed.
74
+
75
+ Args:
76
+ token: Unification token to check
77
+
78
+ Returns:
79
+ Token status response with status and keys (if completed)
80
+
81
+ Raises:
82
+ httpx.HTTPStatusError: If token not found (404) or expired (410)
83
+ httpx.HTTPError: For other request failures
84
+ """
85
+ url = f"{self.base_url}{UNIFICATION_TOKEN_STATUS_PATH.format(token=token)}"
86
+
87
+ logger.debug("Checking status for token %s...", token[:8])
88
+
89
+ try:
90
+ response = httpx.get(url, timeout=self.timeout)
91
+ response.raise_for_status()
92
+
93
+ data = response.json()
94
+ result = TokenStatusResponse.model_validate(data)
95
+
96
+ logger.debug("Token status: %s", result.status)
97
+ return result
98
+
99
+ except httpx.HTTPStatusError as e:
100
+ if e.response.status_code == 404:
101
+ logger.error("Token not found: %s", token[:8])
102
+ elif e.response.status_code == 410:
103
+ logger.error("Token expired: %s", token[:8])
104
+ raise
105
+ except httpx.HTTPError as e:
106
+ logger.error("Failed to check token status: %s", e)
107
+ raise
108
+
109
+
110
+ # Convenience functions for standalone use
111
+ def create_unification_token(shotgun_instance_id: str) -> TokenCreateResponse:
112
+ """Create a unification token.
113
+
114
+ Convenience function that creates a client and calls create_unification_token.
115
+
116
+ Args:
117
+ shotgun_instance_id: UUID for this shotgun instance
118
+
119
+ Returns:
120
+ Token creation response
121
+ """
122
+ client = ShotgunWebClient()
123
+ return client.create_unification_token(shotgun_instance_id)
124
+
125
+
126
+ def check_token_status(token: str) -> TokenStatusResponse:
127
+ """Check token status.
128
+
129
+ Convenience function that creates a client and calls check_token_status.
130
+
131
+ Args:
132
+ token: Unification token to check
133
+
134
+ Returns:
135
+ Token status response
136
+ """
137
+ client = ShotgunWebClient()
138
+ return client.check_token_status(token)
@@ -0,0 +1,17 @@
1
+ """Constants for Shotgun Web API."""
2
+
3
+ import os
4
+
5
+ # Shotgun Web API base URL
6
+ # Default to production URL, can be overridden with environment variable
7
+ SHOTGUN_WEB_BASE_URL = os.environ.get(
8
+ "SHOTGUN_WEB_BASE_URL", "https://api-701197220809.us-east1.run.app"
9
+ )
10
+
11
+ # API endpoints
12
+ UNIFICATION_TOKEN_CREATE_PATH = "/api/unification/token/create" # noqa: S105
13
+ UNIFICATION_TOKEN_STATUS_PATH = "/api/unification/token/{token}/status" # noqa: S105
14
+
15
+ # Polling configuration
16
+ DEFAULT_POLL_INTERVAL_SECONDS = 3
17
+ DEFAULT_TOKEN_TIMEOUT_SECONDS = 1800 # 30 minutes