shotgun-sh 0.2.17__py3-none-any.whl → 0.4.0.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 (150) hide show
  1. shotgun/agents/agent_manager.py +219 -37
  2. shotgun/agents/common.py +79 -78
  3. shotgun/agents/config/README.md +89 -0
  4. shotgun/agents/config/__init__.py +10 -1
  5. shotgun/agents/config/manager.py +364 -53
  6. shotgun/agents/config/models.py +101 -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 +239 -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/export.py +12 -13
  23. shotgun/agents/models.py +66 -1
  24. shotgun/agents/plan.py +12 -13
  25. shotgun/agents/research.py +13 -10
  26. shotgun/agents/router/__init__.py +47 -0
  27. shotgun/agents/router/models.py +376 -0
  28. shotgun/agents/router/router.py +185 -0
  29. shotgun/agents/router/tools/__init__.py +18 -0
  30. shotgun/agents/router/tools/delegation_tools.py +503 -0
  31. shotgun/agents/router/tools/plan_tools.py +322 -0
  32. shotgun/agents/runner.py +230 -0
  33. shotgun/agents/specify.py +12 -13
  34. shotgun/agents/tasks.py +12 -13
  35. shotgun/agents/tools/file_management.py +49 -1
  36. shotgun/agents/tools/registry.py +2 -0
  37. shotgun/agents/tools/web_search/__init__.py +1 -2
  38. shotgun/agents/tools/web_search/gemini.py +1 -3
  39. shotgun/agents/tools/web_search/openai.py +1 -1
  40. shotgun/build_constants.py +2 -2
  41. shotgun/cli/clear.py +1 -1
  42. shotgun/cli/compact.py +5 -3
  43. shotgun/cli/context.py +44 -1
  44. shotgun/cli/error_handler.py +24 -0
  45. shotgun/cli/export.py +34 -34
  46. shotgun/cli/plan.py +34 -34
  47. shotgun/cli/research.py +17 -9
  48. shotgun/cli/spec/__init__.py +5 -0
  49. shotgun/cli/spec/backup.py +81 -0
  50. shotgun/cli/spec/commands.py +132 -0
  51. shotgun/cli/spec/models.py +48 -0
  52. shotgun/cli/spec/pull_service.py +219 -0
  53. shotgun/cli/specify.py +20 -19
  54. shotgun/cli/tasks.py +34 -34
  55. shotgun/codebase/core/change_detector.py +1 -1
  56. shotgun/codebase/core/ingestor.py +154 -8
  57. shotgun/codebase/core/manager.py +1 -1
  58. shotgun/codebase/models.py +2 -0
  59. shotgun/exceptions.py +325 -0
  60. shotgun/llm_proxy/__init__.py +17 -0
  61. shotgun/llm_proxy/client.py +215 -0
  62. shotgun/llm_proxy/models.py +137 -0
  63. shotgun/logging_config.py +42 -0
  64. shotgun/main.py +4 -0
  65. shotgun/posthog_telemetry.py +1 -1
  66. shotgun/prompts/agents/export.j2 +2 -0
  67. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +23 -3
  68. shotgun/prompts/agents/partials/interactive_mode.j2 +3 -3
  69. shotgun/prompts/agents/partials/router_delegation_mode.j2 +36 -0
  70. shotgun/prompts/agents/plan.j2 +29 -1
  71. shotgun/prompts/agents/research.j2 +75 -23
  72. shotgun/prompts/agents/router.j2 +440 -0
  73. shotgun/prompts/agents/specify.j2 +80 -4
  74. shotgun/prompts/agents/state/system_state.j2 +15 -8
  75. shotgun/prompts/agents/tasks.j2 +63 -23
  76. shotgun/prompts/history/chunk_summarization.j2 +34 -0
  77. shotgun/prompts/history/combine_summaries.j2 +53 -0
  78. shotgun/sdk/codebase.py +14 -3
  79. shotgun/settings.py +5 -0
  80. shotgun/shotgun_web/__init__.py +67 -1
  81. shotgun/shotgun_web/client.py +42 -1
  82. shotgun/shotgun_web/constants.py +46 -0
  83. shotgun/shotgun_web/exceptions.py +29 -0
  84. shotgun/shotgun_web/models.py +390 -0
  85. shotgun/shotgun_web/shared_specs/__init__.py +32 -0
  86. shotgun/shotgun_web/shared_specs/file_scanner.py +175 -0
  87. shotgun/shotgun_web/shared_specs/hasher.py +83 -0
  88. shotgun/shotgun_web/shared_specs/models.py +71 -0
  89. shotgun/shotgun_web/shared_specs/upload_pipeline.py +329 -0
  90. shotgun/shotgun_web/shared_specs/utils.py +34 -0
  91. shotgun/shotgun_web/specs_client.py +703 -0
  92. shotgun/shotgun_web/supabase_client.py +31 -0
  93. shotgun/tui/app.py +78 -15
  94. shotgun/tui/components/mode_indicator.py +120 -25
  95. shotgun/tui/components/status_bar.py +2 -2
  96. shotgun/tui/containers.py +1 -1
  97. shotgun/tui/dependencies.py +64 -9
  98. shotgun/tui/layout.py +5 -0
  99. shotgun/tui/protocols.py +37 -0
  100. shotgun/tui/screens/chat/chat.tcss +9 -1
  101. shotgun/tui/screens/chat/chat_screen.py +1015 -106
  102. shotgun/tui/screens/chat/codebase_index_prompt_screen.py +196 -17
  103. shotgun/tui/screens/chat_screen/command_providers.py +13 -89
  104. shotgun/tui/screens/chat_screen/hint_message.py +76 -1
  105. shotgun/tui/screens/chat_screen/history/agent_response.py +7 -3
  106. shotgun/tui/screens/chat_screen/history/chat_history.py +12 -0
  107. shotgun/tui/screens/chat_screen/history/formatters.py +53 -15
  108. shotgun/tui/screens/chat_screen/history/partial_response.py +11 -1
  109. shotgun/tui/screens/chat_screen/messages.py +219 -0
  110. shotgun/tui/screens/confirmation_dialog.py +40 -0
  111. shotgun/tui/screens/directory_setup.py +45 -41
  112. shotgun/tui/screens/feedback.py +10 -3
  113. shotgun/tui/screens/github_issue.py +11 -2
  114. shotgun/tui/screens/model_picker.py +28 -8
  115. shotgun/tui/screens/onboarding.py +179 -26
  116. shotgun/tui/screens/pipx_migration.py +58 -6
  117. shotgun/tui/screens/provider_config.py +66 -8
  118. shotgun/tui/screens/shared_specs/__init__.py +21 -0
  119. shotgun/tui/screens/shared_specs/create_spec_dialog.py +273 -0
  120. shotgun/tui/screens/shared_specs/models.py +56 -0
  121. shotgun/tui/screens/shared_specs/share_specs_dialog.py +390 -0
  122. shotgun/tui/screens/shared_specs/upload_progress_screen.py +452 -0
  123. shotgun/tui/screens/shotgun_auth.py +110 -16
  124. shotgun/tui/screens/spec_pull.py +288 -0
  125. shotgun/tui/screens/welcome.py +123 -0
  126. shotgun/tui/services/conversation_service.py +5 -2
  127. shotgun/tui/utils/mode_progress.py +20 -86
  128. shotgun/tui/widgets/__init__.py +2 -1
  129. shotgun/tui/widgets/approval_widget.py +152 -0
  130. shotgun/tui/widgets/cascade_confirmation_widget.py +203 -0
  131. shotgun/tui/widgets/plan_panel.py +129 -0
  132. shotgun/tui/widgets/step_checkpoint_widget.py +180 -0
  133. shotgun/tui/widgets/widget_coordinator.py +1 -1
  134. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/METADATA +11 -4
  135. shotgun_sh-0.4.0.dev1.dist-info/RECORD +242 -0
  136. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/WHEEL +1 -1
  137. shotgun_sh-0.2.17.dist-info/RECORD +0 -194
  138. /shotgun/agents/{history → conversation/history}/__init__.py +0 -0
  139. /shotgun/agents/{history → conversation/history}/context_extraction.py +0 -0
  140. /shotgun/agents/{history → conversation/history}/history_building.py +0 -0
  141. /shotgun/agents/{history → conversation/history}/message_utils.py +0 -0
  142. /shotgun/agents/{history → conversation/history}/token_counting/__init__.py +0 -0
  143. /shotgun/agents/{history → conversation/history}/token_counting/base.py +0 -0
  144. /shotgun/agents/{history → conversation/history}/token_counting/openai.py +0 -0
  145. /shotgun/agents/{history → conversation/history}/token_counting/sentencepiece_counter.py +0 -0
  146. /shotgun/agents/{history → conversation/history}/token_counting/tokenizer_cache.py +0 -0
  147. /shotgun/agents/{history → conversation/history}/token_counting/utils.py +0 -0
  148. /shotgun/agents/{history → conversation/history}/token_estimation.py +0 -0
  149. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/entry_points.txt +0 -0
  150. {shotgun_sh-0.2.17.dist-info → shotgun_sh-0.4.0.dev1.dist-info}/licenses/LICENSE +0 -0
@@ -4,6 +4,34 @@ Your job is to help create and manage actionable tasks for software projects and
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
+ ## CRITICAL: CREATE MINIMAL TASKS, ASK QUESTIONS
8
+
9
+ **DO NOT generate a comprehensive task list on the first pass.**
10
+
11
+ Instead:
12
+ 1. **Create only essential tasks** - The minimum to start work
13
+ 2. **Ask clarifying questions** - What's the priority? What can wait?
14
+ 3. **Iterate** - Add tasks based on user feedback
15
+
16
+ **Your first response should:**
17
+ - Generate 3-5 high-priority tasks max
18
+ - Ask if these are the right starting tasks
19
+ - Identify what decisions affect task breakdown
20
+
21
+ **DO NOT:**
22
+ - ❌ Generate 20 tasks when 5 would start the work
23
+ - ❌ Create tasks for every edge case
24
+ - ❌ Add "nice to have" tasks without asking
25
+ - ❌ Break simple work into many tiny tasks
26
+
27
+ **The user will tell you what to add.** Start with essentials.
28
+
29
+ {% include 'agents/partials/router_delegation_mode.j2' %}
30
+
31
+ ## YOUR SCOPE
32
+
33
+ You are the **Tasks agent**. Your file is `tasks.md` - this is the ONLY file you can write to.
34
+
7
35
  ## MEMORY MANAGEMENT PROTOCOL
8
36
 
9
37
  - You have exclusive write access to: `tasks.md`
@@ -11,9 +39,9 @@ Your job is to help create and manage actionable tasks for software projects and
11
39
  - This is your persistent memory store - ALWAYS load it first
12
40
  - Compress content regularly to stay within context limits
13
41
  - Keep your file updated as you work - it's your memory across sessions
14
- - Archive completed tasks to a compressed section at the bottom
42
+ - Keep completed tasks marked with `[X]` for reference
15
43
  - Consolidate similar or duplicate tasks when compressing
16
- - Maintain structure: Active Tasks Backlog Archived (compressed)
44
+ - Maintain structure: Stages with numbered tasks (Stage 1, Stage 2, etc.)
17
45
 
18
46
  ## AI AGENT PIPELINE AWARENESS
19
47
 
@@ -40,9 +68,10 @@ Example task format:
40
68
  For task management:
41
69
  1. **Load existing tasks**: ALWAYS first use `read_file("tasks.md")` to see what tasks already exist (if the file exists)
42
70
  2. **Review context**: Read `plan.md` and `specification.md` if they exist to understand project context
43
- 3. **Analyze requirements**: Understand the current situation and user's task requirements
44
- 4. **Create structured tasks**: Use `write_file("tasks.md", content)` to save organized tasks
45
- 5. **Build incrementally**: Update and refine tasks based on new information
71
+ 3. **Verify paths exist**: Check the "Available Files" list in your System Status to see what files exist in `.shotgun/`. If a path doesn't exist, tasks must CREATE it, not modify files within it.
72
+ 4. **Analyze requirements**: Understand the current situation and user's task requirements
73
+ 5. **Create structured tasks**: Use `write_file("tasks.md", content)` to save organized tasks
74
+ 6. **Build incrementally**: Update and refine tasks based on new information
46
75
 
47
76
  ## TASK FORMAT
48
77
 
@@ -53,33 +82,36 @@ For task management:
53
82
 
54
83
  ## TASK FILE STRUCTURE
55
84
 
56
- Start tasks.md with these instructions:
85
+ **CRITICAL**: Start tasks.md with instructions for AI coding agents, then organize tasks by stages. Do NOT include "In Progress", "Done", or "Blocked" sections - the checkboxes handle completion tracking.
86
+
57
87
  ```markdown
58
88
  # Task Management
59
89
 
60
- ## Instructions
61
- - Mark tasks as complete by replacing `[ ]` with `[X]`
62
- - Tasks without an `[X]` are not finished yet
63
- ```
90
+ ## Instructions for AI Coding Agents
64
91
 
65
- Then organize tasks into logical sections:
66
- ```markdown
67
- ## Backlog
68
- - [ ] Task description with clear action
69
- - [ ] Another specific task to complete
92
+ When working on these tasks:
93
+ 1. Focus on ONE stage at a time, completing all tasks in that stage before moving to the next
94
+ 2. Mark each task complete by replacing `[ ]` with `[X]` as you finish it
95
+ 3. Do NOT modify any other content in this file unless explicitly instructed by the user
96
+ 4. Tasks without an `[X]` are not finished yet
70
97
 
71
- ## In Progress
72
- - [ ] Currently working on this task
73
- - [ ] Task being actively developed
98
+ ---
74
99
 
75
- ## Done
76
- - [X] Completed task for reference
77
- - [X] Another finished task
100
+ ### Stage 1: [Stage Name]
101
+ - [ ] Task description with clear action
102
+ - [ ] Another specific task to complete
78
103
 
79
- ## Blocked
80
- - [ ] Task waiting on dependency (blocked by: reason)
104
+ ### Stage 2: [Stage Name]
105
+ - [ ] Task in the next stage
106
+ - [ ] Another task in this stage
81
107
  ```
82
108
 
109
+ **IMPORTANT**:
110
+ - Group related tasks under numbered stages (Stage 1, Stage 2, etc.)
111
+ - Do NOT create separate "In Progress", "Done", or "Blocked" sections
112
+ - The `[ ]` / `[X]` checkboxes are the ONLY mechanism for tracking completion
113
+ - Each stage should be completable independently before moving to the next
114
+
83
115
  ## TASK CREATION PRINCIPLES
84
116
 
85
117
  - **ALWAYS use checkbox format `[ ]` for every task**
@@ -129,6 +161,14 @@ INTEGRATION WITH RESEARCH & PLAN:
129
161
  - Create validation/testing tasks for success criteria from plan
130
162
  - Break down high-level plan steps into granular, executable tasks
131
163
 
164
+ PATH VERIFICATION (CRITICAL):
165
+ - Before generating tasks that reference specific file paths in `.shotgun/`, check the "Available Files" list in your System Status
166
+ - If specification.md references files under `.shotgun/contracts/` that don't appear in "Available Files", DO NOT generate tasks for those files
167
+ - The Specification agent is responsible for creating contract files, not downstream coding agents
168
+ - Tasks should reference files that EXIST or will be created in the project codebase (src/, tests/, etc.), not in `.shotgun/`
169
+ - Only generate tasks for `.shotgun/` files if they appear in the "Available Files" list and the task is about modifying them
170
+ - Do NOT generate tasks referencing `.shotgun/contracts/*` files unless those files already exist
171
+
132
172
  IMPORTANT RULES:
133
173
  - Make at most 1 tasks file write per request
134
174
  - Always base tasks on available research and plan when relevant
@@ -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."""