shotgun-sh 0.2.17__py3-none-any.whl → 0.3.3.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. shotgun/agents/agent_manager.py +28 -14
  2. shotgun/agents/common.py +1 -1
  3. shotgun/agents/config/README.md +89 -0
  4. shotgun/agents/config/__init__.py +10 -1
  5. shotgun/agents/config/manager.py +323 -53
  6. shotgun/agents/config/models.py +85 -21
  7. shotgun/agents/config/provider.py +51 -13
  8. shotgun/agents/config/streaming_test.py +119 -0
  9. shotgun/agents/context_analyzer/analyzer.py +6 -2
  10. shotgun/agents/conversation/__init__.py +18 -0
  11. shotgun/agents/conversation/filters.py +164 -0
  12. shotgun/agents/conversation/history/chunking.py +278 -0
  13. shotgun/agents/{history → conversation/history}/compaction.py +27 -1
  14. shotgun/agents/{history → conversation/history}/constants.py +5 -0
  15. shotgun/agents/conversation/history/file_content_deduplication.py +216 -0
  16. shotgun/agents/{history → conversation/history}/history_processors.py +267 -3
  17. shotgun/agents/{history → conversation/history}/token_counting/anthropic.py +8 -0
  18. shotgun/agents/{conversation_manager.py → conversation/manager.py} +1 -1
  19. shotgun/agents/{conversation_history.py → conversation/models.py} +8 -94
  20. shotgun/agents/error/__init__.py +11 -0
  21. shotgun/agents/error/models.py +19 -0
  22. shotgun/agents/runner.py +230 -0
  23. shotgun/agents/tools/web_search/openai.py +1 -1
  24. shotgun/build_constants.py +2 -2
  25. shotgun/cli/clear.py +1 -1
  26. shotgun/cli/compact.py +5 -3
  27. shotgun/cli/context.py +44 -1
  28. shotgun/cli/error_handler.py +24 -0
  29. shotgun/cli/export.py +34 -34
  30. shotgun/cli/plan.py +34 -34
  31. shotgun/cli/research.py +17 -9
  32. shotgun/cli/spec/__init__.py +5 -0
  33. shotgun/cli/spec/backup.py +81 -0
  34. shotgun/cli/spec/commands.py +132 -0
  35. shotgun/cli/spec/models.py +48 -0
  36. shotgun/cli/spec/pull_service.py +219 -0
  37. shotgun/cli/specify.py +20 -19
  38. shotgun/cli/tasks.py +34 -34
  39. shotgun/codebase/core/ingestor.py +153 -7
  40. shotgun/codebase/models.py +2 -0
  41. shotgun/exceptions.py +325 -0
  42. shotgun/llm_proxy/__init__.py +17 -0
  43. shotgun/llm_proxy/client.py +215 -0
  44. shotgun/llm_proxy/models.py +137 -0
  45. shotgun/logging_config.py +42 -0
  46. shotgun/main.py +4 -0
  47. shotgun/posthog_telemetry.py +1 -1
  48. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +28 -3
  49. shotgun/prompts/agents/partials/interactive_mode.j2 +3 -3
  50. shotgun/prompts/agents/plan.j2 +16 -0
  51. shotgun/prompts/agents/research.j2 +16 -3
  52. shotgun/prompts/agents/specify.j2 +54 -1
  53. shotgun/prompts/agents/state/system_state.j2 +0 -2
  54. shotgun/prompts/agents/tasks.j2 +16 -0
  55. shotgun/prompts/history/chunk_summarization.j2 +34 -0
  56. shotgun/prompts/history/combine_summaries.j2 +53 -0
  57. shotgun/sdk/codebase.py +14 -3
  58. shotgun/settings.py +5 -0
  59. shotgun/shotgun_web/__init__.py +67 -1
  60. shotgun/shotgun_web/client.py +42 -1
  61. shotgun/shotgun_web/constants.py +46 -0
  62. shotgun/shotgun_web/exceptions.py +29 -0
  63. shotgun/shotgun_web/models.py +390 -0
  64. shotgun/shotgun_web/shared_specs/__init__.py +32 -0
  65. shotgun/shotgun_web/shared_specs/file_scanner.py +175 -0
  66. shotgun/shotgun_web/shared_specs/hasher.py +83 -0
  67. shotgun/shotgun_web/shared_specs/models.py +71 -0
  68. shotgun/shotgun_web/shared_specs/upload_pipeline.py +329 -0
  69. shotgun/shotgun_web/shared_specs/utils.py +34 -0
  70. shotgun/shotgun_web/specs_client.py +703 -0
  71. shotgun/shotgun_web/supabase_client.py +31 -0
  72. shotgun/tui/app.py +73 -9
  73. shotgun/tui/containers.py +1 -1
  74. shotgun/tui/layout.py +5 -0
  75. shotgun/tui/screens/chat/chat_screen.py +372 -95
  76. shotgun/tui/screens/chat/codebase_index_prompt_screen.py +196 -17
  77. shotgun/tui/screens/chat_screen/command_providers.py +13 -2
  78. shotgun/tui/screens/chat_screen/hint_message.py +76 -1
  79. shotgun/tui/screens/confirmation_dialog.py +40 -0
  80. shotgun/tui/screens/directory_setup.py +45 -41
  81. shotgun/tui/screens/feedback.py +10 -3
  82. shotgun/tui/screens/github_issue.py +11 -2
  83. shotgun/tui/screens/model_picker.py +28 -8
  84. shotgun/tui/screens/onboarding.py +149 -0
  85. shotgun/tui/screens/pipx_migration.py +58 -6
  86. shotgun/tui/screens/provider_config.py +66 -8
  87. shotgun/tui/screens/shared_specs/__init__.py +21 -0
  88. shotgun/tui/screens/shared_specs/create_spec_dialog.py +273 -0
  89. shotgun/tui/screens/shared_specs/models.py +56 -0
  90. shotgun/tui/screens/shared_specs/share_specs_dialog.py +390 -0
  91. shotgun/tui/screens/shared_specs/upload_progress_screen.py +452 -0
  92. shotgun/tui/screens/shotgun_auth.py +110 -16
  93. shotgun/tui/screens/spec_pull.py +288 -0
  94. shotgun/tui/screens/welcome.py +123 -0
  95. shotgun/tui/services/conversation_service.py +5 -2
  96. shotgun/tui/widgets/widget_coordinator.py +1 -1
  97. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.3.3.dev1.dist-info}/METADATA +9 -2
  98. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.3.3.dev1.dist-info}/RECORD +112 -77
  99. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.3.3.dev1.dist-info}/WHEEL +1 -1
  100. /shotgun/agents/{history → conversation/history}/__init__.py +0 -0
  101. /shotgun/agents/{history → conversation/history}/context_extraction.py +0 -0
  102. /shotgun/agents/{history → conversation/history}/history_building.py +0 -0
  103. /shotgun/agents/{history → conversation/history}/message_utils.py +0 -0
  104. /shotgun/agents/{history → conversation/history}/token_counting/__init__.py +0 -0
  105. /shotgun/agents/{history → conversation/history}/token_counting/base.py +0 -0
  106. /shotgun/agents/{history → conversation/history}/token_counting/openai.py +0 -0
  107. /shotgun/agents/{history → conversation/history}/token_counting/sentencepiece_counter.py +0 -0
  108. /shotgun/agents/{history → conversation/history}/token_counting/tokenizer_cache.py +0 -0
  109. /shotgun/agents/{history → conversation/history}/token_counting/utils.py +0 -0
  110. /shotgun/agents/{history → conversation/history}/token_estimation.py +0 -0
  111. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.3.3.dev1.dist-info}/entry_points.txt +0 -0
  112. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.3.3.dev1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,34 @@
1
+ You are summarizing chunk {{ chunk_index }} of {{ total_chunks }} from a conversation that is too large to summarize at once.
2
+
3
+ Focus on preserving:
4
+ 1. ALL file paths, function names, variable names, URLs, and identifiers VERBATIM
5
+ 2. Key decisions and their rationale
6
+ 3. Tool call results (summarize large outputs, keep critical data)
7
+ 4. Important errors or issues encountered
8
+ 5. User requests and how they were addressed
9
+
10
+ <CHUNK_CONTENT>
11
+ {{ chunk_content }}
12
+ </CHUNK_CONTENT>
13
+
14
+ <OUTPUT_FORMAT>
15
+ ## Topics Covered
16
+ Brief bullet points of main topics discussed in this chunk.
17
+
18
+ ## Entities & References
19
+ - Files: [list all file paths mentioned, verbatim]
20
+ - Functions/Classes: [list all function/method/class names, verbatim]
21
+ - Variables/Keys: [configuration keys, env vars, etc., verbatim]
22
+ - Links/IDs: [any URLs, ticket IDs, etc., verbatim]
23
+
24
+ ## Actions & Results
25
+ Summarized tool calls and their outcomes. Preserve important data verbatim.
26
+
27
+ ## Important Decisions
28
+ Key decisions made and their rationale.
29
+
30
+ ## Status at Chunk End
31
+ Current active task or objective at the end of this chunk (if any), or "N/A" if this chunk completes without active work.
32
+ </OUTPUT_FORMAT>
33
+
34
+ Be concise but preserve all critical information. This summary will be combined with others to create a complete conversation summary.
@@ -0,0 +1,53 @@
1
+ You are combining {{ num_summaries }} conversation chunk summaries into a unified summary.
2
+
3
+ <CHUNK_SUMMARIES>
4
+ {% for summary in chunk_summaries %}
5
+ --- Chunk {{ loop.index }} of {{ num_summaries }} ---
6
+ {{ summary }}
7
+
8
+ {% endfor %}
9
+ </CHUNK_SUMMARIES>
10
+
11
+ Instructions:
12
+ 1. Merge overlapping information - don't repeat the same facts
13
+ 2. Preserve ALL entity references (files, functions, variables) from ALL chunks
14
+ 3. Maintain chronological timeline of actions
15
+ 4. Identify patterns and evolution across chunks
16
+ 5. The current status should reflect the LAST chunk's end state
17
+
18
+ <OUTPUT_FORMAT>
19
+ # Context
20
+
21
+ Short summary of the discussion, grouped by topics or tasks if any.
22
+ Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
23
+
24
+ # Key elements, learnings and entities
25
+
26
+ Present the important elements of context, learnings and entities from the discussion. Be very detailed.
27
+
28
+ Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
29
+
30
+ If the agent obtained information via tools, preserve it verbatim if it was short, summarize it if it was long focusing on preserving all of the most important facts and information.
31
+
32
+ If there are any links mentioned, IDs, filenames, etc. - preserve them verbatim.
33
+
34
+ # Timeline
35
+
36
+ For important tasks and content, provide
37
+ - User: asked to handle a complex task X: <summary of the task>
38
+ - Assistant: we handle it by doing A, B, C...
39
+ - Tools used and output summary
40
+
41
+ ...
42
+ - User: asked to handle a complex task Y: <summary of the task>
43
+ - Assistant: we handle it by doing A, B, C...
44
+ - Tools used and output summary
45
+
46
+ Do not hesitate to merge original messages, remove noise. We want to be as concise and brief as possible.
47
+
48
+ # Current status, task and objectives
49
+
50
+ Based on the conversation, include here the current status, task and objectives.
51
+
52
+ CRITICAL: This is not about summarizing or compacting. We are talking about the status, task and objectives currently active in the conversation to keep as much context as possible regarding the last messages.
53
+ </OUTPUT_FORMAT>
shotgun/sdk/codebase.py CHANGED
@@ -93,6 +93,19 @@ class CodebaseSDK:
93
93
  if indexed_from_cwd is None:
94
94
  indexed_from_cwd = str(Path.cwd().resolve())
95
95
 
96
+ # Track codebase indexing started event
97
+ source = detect_source()
98
+ logger.debug(
99
+ "Tracking codebase_index_started event: source=%s",
100
+ source,
101
+ )
102
+ track_event(
103
+ "codebase_index_started",
104
+ {
105
+ "source": source,
106
+ },
107
+ )
108
+
96
109
  graph = await self.service.create_graph(
97
110
  resolved_path,
98
111
  name,
@@ -101,9 +114,7 @@ class CodebaseSDK:
101
114
  )
102
115
  file_count = sum(graph.language_stats.values()) if graph.language_stats else 0
103
116
 
104
- # Track codebase indexing event
105
- # Detect if called from TUI by checking the call stack
106
- source = detect_source()
117
+ # Track codebase indexing completion event (reuse source from start event)
107
118
 
108
119
  logger.debug(
109
120
  "Tracking codebase_indexed event: file_count=%d, node_count=%d, relationship_count=%d, source=%s",
shotgun/settings.py CHANGED
@@ -108,6 +108,11 @@ class LoggingSettings(BaseSettings):
108
108
  default=True,
109
109
  description="Enable file logging output",
110
110
  )
111
+ max_log_files: int = Field(
112
+ default=10,
113
+ description="Maximum number of log files to keep (older files are deleted)",
114
+ ge=1,
115
+ )
111
116
 
112
117
  model_config = SettingsConfigDict(
113
118
  env_prefix="SHOTGUN_",
@@ -1,14 +1,48 @@
1
- """Shotgun Web API client for subscription and authentication."""
1
+ """Shotgun Web API client for subscription, authentication, and shared specs."""
2
2
 
3
3
  from .client import ShotgunWebClient, check_token_status, create_unification_token
4
+ from .exceptions import (
5
+ ConflictError,
6
+ ForbiddenError,
7
+ NotFoundError,
8
+ PayloadTooLargeError,
9
+ RateLimitExceededError,
10
+ ShotgunWebError,
11
+ UnauthorizedError,
12
+ )
4
13
  from .models import (
14
+ # Specs models
15
+ ErrorDetail,
16
+ ErrorResponse,
17
+ FileListResponse,
18
+ FileMetadata,
19
+ FileUploadRequest,
20
+ FileUploadResponse,
21
+ PermissionCheckResponse,
22
+ PublicSpecResponse,
23
+ SpecCreateRequest,
24
+ SpecCreateResponse,
25
+ SpecFileResponse,
26
+ SpecListResponse,
27
+ SpecResponse,
28
+ SpecUpdateRequest,
29
+ SpecVersionCreateRequest,
30
+ SpecVersionResponse,
31
+ SpecVersionState,
32
+ # Token models
5
33
  TokenCreateRequest,
6
34
  TokenCreateResponse,
7
35
  TokenStatus,
8
36
  TokenStatusResponse,
37
+ VersionCloseResponse,
38
+ VersionCreateResponse,
39
+ VersionListResponse,
40
+ WorkspaceRole,
9
41
  )
42
+ from .specs_client import SpecsClient
10
43
 
11
44
  __all__ = [
45
+ # Existing exports
12
46
  "ShotgunWebClient",
13
47
  "create_unification_token",
14
48
  "check_token_status",
@@ -16,4 +50,36 @@ __all__ = [
16
50
  "TokenCreateResponse",
17
51
  "TokenStatus",
18
52
  "TokenStatusResponse",
53
+ # Specs client
54
+ "SpecsClient",
55
+ # Exceptions
56
+ "ShotgunWebError",
57
+ "UnauthorizedError",
58
+ "ForbiddenError",
59
+ "NotFoundError",
60
+ "ConflictError",
61
+ "PayloadTooLargeError",
62
+ "RateLimitExceededError",
63
+ # Specs models
64
+ "ErrorDetail",
65
+ "ErrorResponse",
66
+ "FileListResponse",
67
+ "FileMetadata",
68
+ "FileUploadRequest",
69
+ "FileUploadResponse",
70
+ "PermissionCheckResponse",
71
+ "PublicSpecResponse",
72
+ "SpecCreateRequest",
73
+ "SpecCreateResponse",
74
+ "SpecFileResponse",
75
+ "SpecListResponse",
76
+ "SpecResponse",
77
+ "SpecUpdateRequest",
78
+ "SpecVersionCreateRequest",
79
+ "SpecVersionResponse",
80
+ "SpecVersionState",
81
+ "VersionCloseResponse",
82
+ "VersionCreateResponse",
83
+ "VersionListResponse",
84
+ "WorkspaceRole",
19
85
  ]
@@ -5,11 +5,13 @@ import httpx
5
5
  from shotgun.logging_config import get_logger
6
6
 
7
7
  from .constants import (
8
+ ME_PATH,
8
9
  SHOTGUN_WEB_BASE_URL,
9
10
  UNIFICATION_TOKEN_CREATE_PATH,
10
11
  UNIFICATION_TOKEN_STATUS_PATH,
11
12
  )
12
13
  from .models import (
14
+ MeResponse,
13
15
  TokenCreateRequest,
14
16
  TokenCreateResponse,
15
17
  TokenStatusResponse,
@@ -66,7 +68,7 @@ class ShotgunWebClient:
66
68
  return result
67
69
 
68
70
  except httpx.HTTPError as e:
69
- logger.error("Failed to create unification token: %s", e)
71
+ logger.error("Failed to create unification token at %s: %s", url, e)
70
72
  raise
71
73
 
72
74
  def check_token_status(self, token: str) -> TokenStatusResponse:
@@ -106,6 +108,45 @@ class ShotgunWebClient:
106
108
  logger.error("Failed to check token status: %s", e)
107
109
  raise
108
110
 
111
+ def get_me(self, jwt: str) -> MeResponse:
112
+ """Get current user info including workspace.
113
+
114
+ Args:
115
+ jwt: Supabase JWT for authentication
116
+
117
+ Returns:
118
+ User info including workspace details
119
+
120
+ Raises:
121
+ httpx.HTTPStatusError: If authentication fails (401) or other HTTP errors
122
+ httpx.HTTPError: For other request failures
123
+ """
124
+ url = f"{self.base_url}{ME_PATH}"
125
+
126
+ logger.debug("Fetching user info from /api/me")
127
+
128
+ try:
129
+ response = httpx.get(
130
+ url,
131
+ headers={"Authorization": f"Bearer {jwt}"},
132
+ timeout=self.timeout,
133
+ )
134
+ response.raise_for_status()
135
+
136
+ data = response.json()
137
+ result = MeResponse.model_validate(data)
138
+
139
+ logger.info("Successfully fetched user info for %s", result.email)
140
+ return result
141
+
142
+ except httpx.HTTPStatusError as e:
143
+ if e.response.status_code == 401:
144
+ logger.error("Authentication failed for /api/me")
145
+ raise
146
+ except httpx.HTTPError as e:
147
+ logger.error("Failed to fetch user info: %s", e)
148
+ raise
149
+
109
150
 
110
151
  # Convenience functions for standalone use
111
152
  def create_unification_token(shotgun_instance_id: str) -> TokenCreateResponse:
@@ -6,16 +6,62 @@ from shotgun.api_endpoints import SHOTGUN_WEB_BASE_URL
6
6
  # API endpoints
7
7
  UNIFICATION_TOKEN_CREATE_PATH = "/api/unification/token/create" # noqa: S105
8
8
  UNIFICATION_TOKEN_STATUS_PATH = "/api/unification/token/{token}/status" # noqa: S105
9
+ ME_PATH = "/api/me"
9
10
 
10
11
  # Polling configuration
11
12
  DEFAULT_POLL_INTERVAL_SECONDS = 3
12
13
  DEFAULT_TOKEN_TIMEOUT_SECONDS = 1800 # 30 minutes
13
14
 
15
+ # Workspaces API endpoint
16
+ WORKSPACES_PATH = "/api/workspaces"
17
+
18
+ # Specs API endpoints
19
+ PERMISSIONS_PATH = "/api/workspaces/{workspace_id}/specs/permissions"
20
+ SPECS_BASE_PATH = "/api/workspaces/{workspace_id}/specs"
21
+ SPECS_DETAIL_PATH = "/api/workspaces/{workspace_id}/specs/{spec_id}"
22
+ VERSIONS_PATH = "/api/workspaces/{workspace_id}/specs/{spec_id}/versions"
23
+ VERSION_DETAIL_PATH = (
24
+ "/api/workspaces/{workspace_id}/specs/{spec_id}/versions/{version_id}"
25
+ )
26
+ VERSION_CLOSE_PATH = (
27
+ "/api/workspaces/{workspace_id}/specs/{spec_id}/versions/{version_id}/close"
28
+ )
29
+ VERSION_SET_LATEST_PATH = (
30
+ "/api/workspaces/{workspace_id}/specs/{spec_id}/versions/{version_id}/set-latest"
31
+ )
32
+ FILES_PATH = (
33
+ "/api/workspaces/{workspace_id}/specs/{spec_id}/versions/{version_id}/files"
34
+ )
35
+ FILE_DETAIL_PATH = "/api/workspaces/{workspace_id}/specs/{spec_id}/versions/{version_id}/files/{file_id}"
36
+ PUBLIC_SPEC_PATH = "/api/public/specs/{spec_id}"
37
+ PUBLIC_SPEC_FILES_PATH = "/api/public/specs/{spec_id}/files"
38
+ PUBLIC_FILE_PATH = "/api/public/specs/{spec_id}/files/{file_id}"
39
+
40
+ # CLI convenience endpoint (version lookup by ID only)
41
+ VERSION_BY_ID_PATH = "/api/versions/{version_id}"
42
+
14
43
  # Re-export for backward compatibility
15
44
  __all__ = [
16
45
  "SHOTGUN_WEB_BASE_URL",
17
46
  "UNIFICATION_TOKEN_CREATE_PATH",
18
47
  "UNIFICATION_TOKEN_STATUS_PATH",
48
+ "ME_PATH",
19
49
  "DEFAULT_POLL_INTERVAL_SECONDS",
20
50
  "DEFAULT_TOKEN_TIMEOUT_SECONDS",
51
+ # Workspaces endpoint
52
+ "WORKSPACES_PATH",
53
+ # Specs endpoints
54
+ "PERMISSIONS_PATH",
55
+ "SPECS_BASE_PATH",
56
+ "SPECS_DETAIL_PATH",
57
+ "VERSIONS_PATH",
58
+ "VERSION_DETAIL_PATH",
59
+ "VERSION_CLOSE_PATH",
60
+ "VERSION_SET_LATEST_PATH",
61
+ "FILES_PATH",
62
+ "FILE_DETAIL_PATH",
63
+ "PUBLIC_SPEC_PATH",
64
+ "PUBLIC_SPEC_FILES_PATH",
65
+ "PUBLIC_FILE_PATH",
66
+ "VERSION_BY_ID_PATH",
21
67
  ]
@@ -0,0 +1,29 @@
1
+ """Typed exceptions for Shotgun Web API operations."""
2
+
3
+
4
+ class ShotgunWebError(Exception):
5
+ """Base exception for Shotgun Web API operations."""
6
+
7
+
8
+ class UnauthorizedError(ShotgunWebError):
9
+ """401 - Missing or invalid authentication token."""
10
+
11
+
12
+ class ForbiddenError(ShotgunWebError):
13
+ """403 - Insufficient permissions for the requested operation."""
14
+
15
+
16
+ class NotFoundError(ShotgunWebError):
17
+ """404 - Resource not found."""
18
+
19
+
20
+ class ConflictError(ShotgunWebError):
21
+ """409 - Name conflict or duplicate path."""
22
+
23
+
24
+ class PayloadTooLargeError(ShotgunWebError):
25
+ """413 - File exceeds maximum size limit."""
26
+
27
+
28
+ class RateLimitExceededError(ShotgunWebError):
29
+ """429 - Rate limit exceeded."""