shotgun-sh 0.1.0__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.

Potentially problematic release.


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

Files changed (130) hide show
  1. shotgun/__init__.py +5 -0
  2. shotgun/agents/__init__.py +1 -0
  3. shotgun/agents/agent_manager.py +651 -0
  4. shotgun/agents/common.py +549 -0
  5. shotgun/agents/config/__init__.py +13 -0
  6. shotgun/agents/config/constants.py +17 -0
  7. shotgun/agents/config/manager.py +294 -0
  8. shotgun/agents/config/models.py +185 -0
  9. shotgun/agents/config/provider.py +206 -0
  10. shotgun/agents/conversation_history.py +106 -0
  11. shotgun/agents/conversation_manager.py +105 -0
  12. shotgun/agents/export.py +96 -0
  13. shotgun/agents/history/__init__.py +5 -0
  14. shotgun/agents/history/compaction.py +85 -0
  15. shotgun/agents/history/constants.py +19 -0
  16. shotgun/agents/history/context_extraction.py +108 -0
  17. shotgun/agents/history/history_building.py +104 -0
  18. shotgun/agents/history/history_processors.py +426 -0
  19. shotgun/agents/history/message_utils.py +84 -0
  20. shotgun/agents/history/token_counting.py +429 -0
  21. shotgun/agents/history/token_estimation.py +138 -0
  22. shotgun/agents/messages.py +35 -0
  23. shotgun/agents/models.py +275 -0
  24. shotgun/agents/plan.py +98 -0
  25. shotgun/agents/research.py +108 -0
  26. shotgun/agents/specify.py +98 -0
  27. shotgun/agents/tasks.py +96 -0
  28. shotgun/agents/tools/__init__.py +34 -0
  29. shotgun/agents/tools/codebase/__init__.py +28 -0
  30. shotgun/agents/tools/codebase/codebase_shell.py +256 -0
  31. shotgun/agents/tools/codebase/directory_lister.py +141 -0
  32. shotgun/agents/tools/codebase/file_read.py +144 -0
  33. shotgun/agents/tools/codebase/models.py +252 -0
  34. shotgun/agents/tools/codebase/query_graph.py +67 -0
  35. shotgun/agents/tools/codebase/retrieve_code.py +81 -0
  36. shotgun/agents/tools/file_management.py +218 -0
  37. shotgun/agents/tools/user_interaction.py +37 -0
  38. shotgun/agents/tools/web_search/__init__.py +60 -0
  39. shotgun/agents/tools/web_search/anthropic.py +144 -0
  40. shotgun/agents/tools/web_search/gemini.py +85 -0
  41. shotgun/agents/tools/web_search/openai.py +98 -0
  42. shotgun/agents/tools/web_search/utils.py +20 -0
  43. shotgun/build_constants.py +20 -0
  44. shotgun/cli/__init__.py +1 -0
  45. shotgun/cli/codebase/__init__.py +5 -0
  46. shotgun/cli/codebase/commands.py +202 -0
  47. shotgun/cli/codebase/models.py +21 -0
  48. shotgun/cli/config.py +275 -0
  49. shotgun/cli/export.py +81 -0
  50. shotgun/cli/models.py +10 -0
  51. shotgun/cli/plan.py +73 -0
  52. shotgun/cli/research.py +85 -0
  53. shotgun/cli/specify.py +69 -0
  54. shotgun/cli/tasks.py +78 -0
  55. shotgun/cli/update.py +152 -0
  56. shotgun/cli/utils.py +25 -0
  57. shotgun/codebase/__init__.py +12 -0
  58. shotgun/codebase/core/__init__.py +46 -0
  59. shotgun/codebase/core/change_detector.py +358 -0
  60. shotgun/codebase/core/code_retrieval.py +243 -0
  61. shotgun/codebase/core/ingestor.py +1497 -0
  62. shotgun/codebase/core/language_config.py +297 -0
  63. shotgun/codebase/core/manager.py +1662 -0
  64. shotgun/codebase/core/nl_query.py +331 -0
  65. shotgun/codebase/core/parser_loader.py +128 -0
  66. shotgun/codebase/models.py +111 -0
  67. shotgun/codebase/service.py +206 -0
  68. shotgun/logging_config.py +227 -0
  69. shotgun/main.py +167 -0
  70. shotgun/posthog_telemetry.py +158 -0
  71. shotgun/prompts/__init__.py +5 -0
  72. shotgun/prompts/agents/__init__.py +1 -0
  73. shotgun/prompts/agents/export.j2 +350 -0
  74. shotgun/prompts/agents/partials/codebase_understanding.j2 +87 -0
  75. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +37 -0
  76. shotgun/prompts/agents/partials/content_formatting.j2 +65 -0
  77. shotgun/prompts/agents/partials/interactive_mode.j2 +26 -0
  78. shotgun/prompts/agents/plan.j2 +144 -0
  79. shotgun/prompts/agents/research.j2 +69 -0
  80. shotgun/prompts/agents/specify.j2 +51 -0
  81. shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +19 -0
  82. shotgun/prompts/agents/state/system_state.j2 +31 -0
  83. shotgun/prompts/agents/tasks.j2 +143 -0
  84. shotgun/prompts/codebase/__init__.py +1 -0
  85. shotgun/prompts/codebase/cypher_query_patterns.j2 +223 -0
  86. shotgun/prompts/codebase/cypher_system.j2 +28 -0
  87. shotgun/prompts/codebase/enhanced_query_context.j2 +10 -0
  88. shotgun/prompts/codebase/partials/cypher_rules.j2 +24 -0
  89. shotgun/prompts/codebase/partials/graph_schema.j2 +30 -0
  90. shotgun/prompts/codebase/partials/temporal_context.j2 +21 -0
  91. shotgun/prompts/history/__init__.py +1 -0
  92. shotgun/prompts/history/incremental_summarization.j2 +53 -0
  93. shotgun/prompts/history/summarization.j2 +46 -0
  94. shotgun/prompts/loader.py +140 -0
  95. shotgun/py.typed +0 -0
  96. shotgun/sdk/__init__.py +13 -0
  97. shotgun/sdk/codebase.py +219 -0
  98. shotgun/sdk/exceptions.py +17 -0
  99. shotgun/sdk/models.py +189 -0
  100. shotgun/sdk/services.py +23 -0
  101. shotgun/sentry_telemetry.py +87 -0
  102. shotgun/telemetry.py +93 -0
  103. shotgun/tui/__init__.py +0 -0
  104. shotgun/tui/app.py +116 -0
  105. shotgun/tui/commands/__init__.py +76 -0
  106. shotgun/tui/components/prompt_input.py +69 -0
  107. shotgun/tui/components/spinner.py +86 -0
  108. shotgun/tui/components/splash.py +25 -0
  109. shotgun/tui/components/vertical_tail.py +13 -0
  110. shotgun/tui/screens/chat.py +782 -0
  111. shotgun/tui/screens/chat.tcss +43 -0
  112. shotgun/tui/screens/chat_screen/__init__.py +0 -0
  113. shotgun/tui/screens/chat_screen/command_providers.py +219 -0
  114. shotgun/tui/screens/chat_screen/hint_message.py +40 -0
  115. shotgun/tui/screens/chat_screen/history.py +221 -0
  116. shotgun/tui/screens/directory_setup.py +113 -0
  117. shotgun/tui/screens/provider_config.py +221 -0
  118. shotgun/tui/screens/splash.py +31 -0
  119. shotgun/tui/styles.tcss +10 -0
  120. shotgun/tui/utils/__init__.py +5 -0
  121. shotgun/tui/utils/mode_progress.py +257 -0
  122. shotgun/utils/__init__.py +5 -0
  123. shotgun/utils/env_utils.py +35 -0
  124. shotgun/utils/file_system_utils.py +36 -0
  125. shotgun/utils/update_checker.py +375 -0
  126. shotgun_sh-0.1.0.dist-info/METADATA +466 -0
  127. shotgun_sh-0.1.0.dist-info/RECORD +130 -0
  128. shotgun_sh-0.1.0.dist-info/WHEEL +4 -0
  129. shotgun_sh-0.1.0.dist-info/entry_points.txt +2 -0
  130. shotgun_sh-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,223 @@
1
+ # FOLLOW THESE PATTERNS TO GENERATE THE CORRECT CYPHER QUERY:
2
+
3
+ **Pattern: Finding All Classes**
4
+ ```cypher
5
+ // "Find all Python classes" or "list all classes" or "show me all classes"
6
+ MATCH (c:Class)
7
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
8
+ ORDER BY c.name
9
+ ```
10
+
11
+ **Pattern: Finding Classes with Path Information**
12
+ ```cypher
13
+ // "Find Python classes with their file paths" or "show classes and where they are defined"
14
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
15
+ RETURN c.name AS name, c.qualified_name AS qualified_name, m.path AS module_path, 'Class' AS type
16
+ ORDER BY m.path, c.name
17
+ ```
18
+
19
+ **Pattern: Finding Decorated Functions/Methods (e.g., Workflows, Tasks)**
20
+ ```cypher
21
+ // "Find all prefect flows" or "what are the workflows?" or "show me the tasks"
22
+ // Use separate MATCH clauses since Kuzu doesn't support union types
23
+ MATCH (n:Function)
24
+ WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
25
+ RETURN n.name AS name, n.qualified_name AS qualified_name, 'Function' AS type
26
+ UNION ALL
27
+ MATCH (n:Method)
28
+ WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
29
+ RETURN n.name AS name, n.qualified_name AS qualified_name, 'Method' AS type
30
+ ```
31
+
32
+ **Pattern: Finding Content by Path (Using UNION ALL for Different Types)**
33
+ ```cypher
34
+ // "what is in the 'workflows/src' directory?" or "list files in workflows"
35
+ // Use separate queries with UNION ALL to handle different node types
36
+ MATCH (n:Module)
37
+ WHERE n.path STARTS WITH 'workflows'
38
+ RETURN n.name AS name, n.path AS path, 'Module' AS type
39
+ UNION ALL
40
+ MATCH (n:File)
41
+ WHERE n.path STARTS WITH 'workflows'
42
+ RETURN n.name AS name, n.path AS path, 'File' AS type
43
+ UNION ALL
44
+ MATCH (n:Folder)
45
+ WHERE n.path STARTS WITH 'workflows'
46
+ RETURN n.name AS name, n.path AS path, 'Folder' AS type
47
+ ```
48
+
49
+ **Pattern: Keyword & Concept Search (Fallback for general terms)**
50
+ ```cypher
51
+ // "find things related to 'database'"
52
+ MATCH (n)
53
+ WHERE toLower(n.name) CONTAINS 'database' OR (n.qualified_name IS NOT NULL AND toLower(n.qualified_name) CONTAINS 'database')
54
+ ```
55
+
56
+ **Pattern: Time-based Queries (IMPORTANT: Use actual timestamps from user query)**
57
+ ```cypher
58
+ // "What functions were added in the last 2 minutes?" when current timestamp is provided
59
+ MATCH (f:Function)
60
+ WHERE f.created_at > [current_timestamp - 120] // This is current_timestamp - 120
61
+ RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
62
+ ORDER BY f.created_at DESC
63
+ ```
64
+
65
+ ```cypher
66
+ // "What classes were modified today?" when current timestamp is provided
67
+ MATCH (c:Class)
68
+ WHERE c.updated_at >= [today's start timestamp] // This is today's start
69
+ RETURN c.name AS name, c.qualified_name AS qualified_name, c.updated_at AS updated_timestamp
70
+ ORDER BY c.updated_at DESC
71
+ ```
72
+
73
+ **Pattern: Finding Files by Extension**
74
+ ```cypher
75
+ // "Find all TypeScript files" or "show me .ts files"
76
+ // IMPORTANT: File extensions are stored WITH the dot (e.g., ".ts" not "ts")
77
+ MATCH (f:File)
78
+ WHERE f.extension = '.ts'
79
+ RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
80
+ ORDER BY f.path
81
+ ```
82
+
83
+ ```cypher
84
+ // "Find JavaScript and TypeScript files"
85
+ MATCH (f:File)
86
+ WHERE f.extension IN ['.js', '.ts', '.jsx', '.tsx']
87
+ RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
88
+ ORDER BY f.path
89
+ ```
90
+
91
+ **Pattern: Finding a Specific File**
92
+ ```cypher
93
+ // "Find the main README.md"
94
+ MATCH (f:File) WHERE toLower(f.name) = 'readme.md' AND f.path = 'README.md'
95
+ RETURN f.path as path, f.name as name, 'File' as type
96
+ ```
97
+
98
+ **Pattern: Finding Classes in a Specific Directory**
99
+ ```cypher
100
+ // "Find classes in the server directory"
101
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
102
+ WHERE m.path STARTS WITH 'server/'
103
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
104
+ ```
105
+
106
+ **Pattern: Finding Modules with Most Classes**
107
+ ```cypher
108
+ // "Find modules that define the most classes"
109
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
110
+ WITH m, count(c) AS class_count
111
+ ORDER BY class_count DESC
112
+ LIMIT 10
113
+ RETURN m.name AS name, m.qualified_name AS qualified_name, m.path AS path, class_count
114
+ ```
115
+
116
+ **Pattern: Finding Classes with Method Counts**
117
+ ```cypher
118
+ // "Find classes with more than N methods" or "Show me classes that have at least X methods"
119
+ MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
120
+ WITH c, count(m) AS method_count
121
+ WHERE method_count > 10 // Replace 10 with the actual number from query
122
+ RETURN c.name AS name, c.qualified_name AS qualified_name, method_count
123
+ ORDER BY method_count DESC
124
+ ```
125
+
126
+ **Pattern: Finding Classes with Inheritance (Note: INHERITS relationships must exist)**
127
+ ```cypher
128
+ // "Find classes with children/subclasses"
129
+ // This will return NO results if no inheritance relationships exist in the graph
130
+ MATCH (child:Class)-[:INHERITS]->(parent:Class)
131
+ WITH parent, count(child) AS child_count
132
+ ORDER BY child_count DESC
133
+ LIMIT 10
134
+ RETURN parent.name AS name, parent.qualified_name AS qualified_name, child_count
135
+ ```
136
+
137
+ **Pattern: Finding Parent Classes of a Specific Class**
138
+ ```cypher
139
+ // "What are the parent classes of DeputyAgent?" or "What does DeputyAgent inherit from?"
140
+ // Use name for short class names (when user doesn't provide full path)
141
+ MATCH (child:Class)-[:INHERITS]->(parent:Class)
142
+ WHERE toLower(child.name) = 'deputyagent'
143
+ RETURN parent.name AS name, parent.qualified_name AS qualified_name
144
+ ```
145
+
146
+ **Pattern: Finding Methods of a Specific Class**
147
+ ```cypher
148
+ // "What methods does WebSocketServer have?" or "List methods in WebSocketServer class"
149
+ // When user provides just the class name without full path
150
+ MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
151
+ WHERE c.name = 'WebSocketServer'
152
+ RETURN m.name AS name, m.qualified_name AS qualified_name, 'Method' AS type
153
+ ORDER BY m.name
154
+ ```
155
+
156
+ **Pattern: Finding a Specific Entity by Full Qualified Name**
157
+ ```cypher
158
+ // "Find shotgun.server.WebSocketServer" or "Show me api.websocket.server.WebSocketServer"
159
+ // When user provides a dotted path, match against qualified_name
160
+ MATCH (c:Class)
161
+ WHERE c.qualified_name = 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer'
162
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
163
+ ```
164
+
165
+ **Pattern: Finding Recently Added/Modified Code**
166
+ ```cypher
167
+ // "Find functions added in the last 24 hours" or "What new functions were added today?"
168
+ // Note: In Kuzu, use Unix timestamps directly (seconds since epoch)
169
+ // Example: 1704067200 represents 2024-01-01 00:00:00 UTC
170
+ // For "today": use timestamp from start of current day
171
+ // For "last 24 hours": use current_timestamp - 86400
172
+ MATCH (f:Function)
173
+ WHERE f.created_at > [current_timestamp - 86400] // Replace with actual timestamp for "24 hours ago"
174
+ RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
175
+ ORDER BY f.created_at DESC
176
+ ```
177
+
178
+ **Pattern: Finding Files Modified Recently**
179
+ ```cypher
180
+ // "Find files modified today" or "Which files changed in the last hour?"
181
+ // For "last hour": use current_timestamp - 3600
182
+ // For "today": use timestamp from start of current day
183
+ MATCH (fm:FileMetadata)
184
+ WHERE fm.mtime > [current_timestamp - 3600] // Replace with actual timestamp
185
+ RETURN fm.filepath AS path, fm.mtime AS last_modified
186
+ ORDER BY fm.mtime DESC
187
+ ```
188
+
189
+ **Pattern: Queries About Deleted/Removed Entities**
190
+ ```cypher
191
+ // "What functions were deleted/removed?" or "Show me classes that no longer exist"
192
+ // Query the DeletionLog table for tracking removed entities
193
+ MATCH (d:DeletionLog)
194
+ WHERE d.entity_type = 'Function' AND d.deleted_at > [current_timestamp - 86400] // Replace with timestamp for time range
195
+ RETURN d.entity_qualified_name AS name, d.deleted_from_file AS file, d.deleted_at AS deleted_at, d.deletion_reason AS reason
196
+ ORDER BY d.deleted_at DESC
197
+ ```
198
+
199
+ **Pattern: Finding Where a Method/Function is Called**
200
+ ```cypher
201
+ // "where is WebSocketServer.start called?" or "find callers of method X"
202
+ // For partial names like 'WebSocketServer.start', use ENDS WITH pattern
203
+ MATCH (caller:Method)-[:CALLS]->(target:Method)
204
+ WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
205
+ RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Method' AS caller_type
206
+ UNION ALL
207
+ MATCH (caller:Function)-[:CALLS]->(target:Method)
208
+ WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
209
+ RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Function' AS caller_type
210
+ ```
211
+
212
+ **Pattern: Finding What a Method/Function Calls**
213
+ ```cypher
214
+ // "what does WebSocketServer.start call?" or "what methods does X invoke?"
215
+ // Use ENDS WITH for partial names, UNION ALL to handle different target types
216
+ MATCH (source:Method)-[:CALLS]->(target:Method)
217
+ WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
218
+ RETURN target.name AS name, target.qualified_name AS qualified_name, 'Method' AS target_type
219
+ UNION ALL
220
+ MATCH (source:Method)-[:CALLS]->(target:Function)
221
+ WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
222
+ RETURN target.name AS name, target.qualified_name AS qualified_name, 'Function' AS target_type
223
+ ```
@@ -0,0 +1,28 @@
1
+ You are an expert translator that converts natural language questions about code structure into precise Neo4j Cypher queries.
2
+
3
+ {% include 'codebase/partials/graph_schema.j2' %}
4
+
5
+ {% include 'codebase/partials/cypher_rules.j2' %}
6
+
7
+ **3. Query Patterns & Examples**
8
+ Your goal is to return appropriate properties for each node type. Common properties:
9
+ - All nodes have: `name`
10
+ - Nodes with paths: Module, Package, File, Folder (have `path` property)
11
+ - Code entities: Class, Function, Method (have `qualified_name` but NO `path` - get path via Module relationship)
12
+ - Always include a type indicator (either as a string literal or via CASE statement)
13
+ - Do NOT include comments (// or /*) in your queries.
14
+
15
+ **IMPORTANT: Handling Entity Names**
16
+ - `name` property: Contains only the simple/short name (e.g., 'WebSocketServer', 'start')
17
+ - `qualified_name` property: Contains the full qualified path (e.g., 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer')
18
+ - When users mention a specific class/function/method by name:
19
+ - If it looks like a short name, use: `WHERE c.name = 'WebSocketServer'`
20
+ - If it contains dots or looks like a full path, use: `WHERE c.qualified_name = 'full.path.to.Class'`
21
+ - For partial paths, use: `WHERE c.qualified_name CONTAINS 'partial.path'` or `WHERE c.qualified_name ENDS WITH '.WebSocketServer'`
22
+
23
+ {% include 'codebase/cypher_query_patterns.j2' %}
24
+
25
+ {% include 'codebase/partials/temporal_context.j2' %}
26
+
27
+ **6. Output Format**
28
+ Provide only the Cypher query.
@@ -0,0 +1,10 @@
1
+ Current datetime: {{ current_datetime }} (Unix timestamp: {{ current_timestamp }})
2
+
3
+ User query: {{ natural_language_query }}
4
+
5
+ IMPORTANT: All timestamps in the database are stored as Unix timestamps (INT64). When generating time-based queries:
6
+ - For "2 minutes ago": use {{ current_timestamp - 120 }}
7
+ - For "1 hour ago": use {{ current_timestamp - 3600 }}
8
+ - For "today": use timestamps >= {{ current_timestamp - (current_timestamp % 86400) }}
9
+ - For "yesterday": use timestamps between {{ current_timestamp - 86400 - (current_timestamp % 86400) }} and {{ current_timestamp - (current_timestamp % 86400) }}
10
+ - NEVER use placeholder values like 1704067200, always calculate based on the current timestamp: {{ current_timestamp }}
@@ -0,0 +1,24 @@
1
+ **2. Critical Cypher Query Rules**
2
+
3
+ - **ALWAYS Return Specific Properties with Aliases**: Do NOT return whole nodes (e.g., `RETURN n`). You MUST return specific properties with clear aliases (e.g., `RETURN n.name AS name`).
4
+ - **File Extensions Include Dots**: File extensions are stored WITH the leading dot (e.g., `.ts`, `.py`, `.js`). When querying for files by extension, ALWAYS include the dot: `WHERE f.extension = '.ts'` NOT `WHERE f.extension = 'ts'`.
5
+ - **Use `STARTS WITH` for Paths**: When matching paths, always use `STARTS WITH` for robustness (e.g., `WHERE n.path STARTS WITH 'workflows/src'`). Do not use `=`.
6
+ - **Use `toLower()` for Searches**: For case-insensitive searching on string properties, use `toLower()`.
7
+ - **Querying Lists**: To check if a list property (like `decorators`) contains an item, use the `ANY` or `IN` clause (e.g., `WHERE 'flow' IN n.decorators`).
8
+ - **No Union Types in Patterns**: Kuzu does NOT support union types like `(n:Function|Method)`. Use separate MATCH clauses or OPTIONAL MATCH instead.
9
+ - **Timestamps in Kuzu**: Timestamps are stored as INT64 Unix timestamps (seconds since epoch). Do NOT use `timestamp()` function. For time-based queries, use numeric comparisons with Unix timestamp values that are calculated from the current timestamp provided in the user query. NEVER use hardcoded timestamps like 1704067200.
10
+ - **No labels() Function**: Kuzu does NOT support the `labels()` function. Do not use `labels(n)` in queries. If you need to indicate the type, use a string literal like 'Class' or 'Function'.
11
+ - **CASE Statements**: Kuzu has limited support for CASE statements. AVOID using CASE WHEN in RETURN clauses. Instead, use string literals for type indication or UNION ALL for handling multiple node types.
12
+ - **UNION ALL Column Matching**: When using UNION ALL, EVERY part MUST return the EXACT SAME columns with the SAME names in the SAME order.
13
+ CORRECT usage:
14
+ ```
15
+ MATCH (f:Function) WHERE ... RETURN f.name AS name, f.qualified_name AS qname, 'Function' AS type
16
+ UNION ALL
17
+ MATCH (m:Method) WHERE ... RETURN m.name AS name, m.qualified_name AS qname, 'Method' AS type
18
+ ```
19
+ INCORRECT usage (different column counts or names):
20
+ ```
21
+ MATCH (f:Function) RETURN f.name AS name, f.qualified_name AS qname
22
+ UNION ALL
23
+ MATCH (m:Method) RETURN m.name AS name, m.qualified_name AS qname, m.path AS path // ERROR: Extra column!
24
+ ```
@@ -0,0 +1,30 @@
1
+
2
+ # Codebase Graph Schema Definition
3
+ The database contains information about a codebase, structured with the following nodes and relationships.
4
+
5
+ THE ONLY PROPERTIES THAT ARE AVAILABLE ARE THE ONES LISTED BELOW. DO NOT MAKE UP ANY OTHER PROPERTIES.
6
+ PAY ATTENTION TO THE PROPERTY TYPES.
7
+ - Project: {name: string}
8
+ - Package: {qualified_name: string, name: string, path: string}
9
+ - Folder: {path: string, name: string}
10
+ - File: {path: string, name: string, extension: string} // Note: extension includes the dot (e.g., ".ts", ".py", ".js")
11
+ - FileMetadata: {filepath: string, mtime: int64, hash: string, last_updated: int64}
12
+ - Module: {qualified_name: string, name: string, path: string, created_at: int64, updated_at: int64}
13
+ - Class: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
14
+ - Function: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
15
+ - Method: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
16
+ - ExternalPackage: {name: string, version_spec: string}
17
+ - DeletionLog: {id: string, entity_type: string, entity_qualified_name: string, deleted_from_file: string, deleted_at: int64, deletion_reason: string}
18
+
19
+ Relationships (source)-[REL_TYPE]->(target):
20
+ - (Project|Package|Folder) -[:CONTAINS_PACKAGE|CONTAINS_FOLDER|CONTAINS_FILE|CONTAINS_MODULE]-> (various)
21
+ - Module -[:DEFINES]-> (Class|Function)
22
+ - Class -[:DEFINES_METHOD]-> Method
23
+ - (Child Class) -[:INHERITS]-> (Parent Class)
24
+ - Method -[:OVERRIDES]-> Method
25
+ - Project -[:DEPENDS_ON_EXTERNAL]-> ExternalPackage
26
+ - (Function|Method) -[:CALLS]-> (Function|Method)
27
+ - FileMetadata -[:TRACKS_Module]-> Module
28
+ - FileMetadata -[:TRACKS_Class]-> Class
29
+ - FileMetadata -[:TRACKS_Function]-> Function
30
+ - FileMetadata -[:TRACKS_Method]-> Method
@@ -0,0 +1,21 @@
1
+ **4. Handling Time-based Queries**
2
+ When users ask about "today", "yesterday", "last hour", "last week", etc., convert these to Unix timestamp comparisons:
3
+ - "today" → Use a timestamp representing start of current day (e.g., WHERE f.created_at > [today's start timestamp])
4
+ - "yesterday" → Use timestamps for yesterday's range
5
+ - "last hour" → Current time minus 3600 seconds
6
+ - "last 24 hours" → Current time minus 86400 seconds
7
+ - "last week" → Current time minus 604800 seconds
8
+
9
+ Since you cannot calculate the current time, use reasonable example timestamps that would work for the query.
10
+ The actual timestamp calculation will be handled by the calling application.
11
+
12
+ **5. Handling Queries About Deleted/Removed Entities**
13
+ When users ask about "removed", "deleted", or "no longer exist" entities:
14
+ - Query the DeletionLog table which tracks all deletions
15
+ - Filter by entity_type (Function, Method, Class, Module) based on what they're asking about
16
+ - Use timestamp comparisons for time-based deletion queries
17
+ - The deletion_reason field indicates why it was deleted (e.g., "removed_from_file", "file_deleted")
18
+
19
+ Examples:
20
+ - "What functions were removed today?" → Query DeletionLog WHERE entity_type = 'Function' AND deleted_at > [today's timestamp]
21
+ - "Show deleted classes from auth module" → Query DeletionLog WHERE entity_type = 'Class' AND entity_qualified_name CONTAINS 'auth'
@@ -0,0 +1 @@
1
+ """History processing prompt templates."""
@@ -0,0 +1,53 @@
1
+ You are extending an existing conversation summary with new messages.
2
+
3
+ Your task is to merge the new information into the existing summary while maintaining the same structured format and preserving all important information.
4
+
5
+ <EXISTING_SUMMARY>
6
+ {{ existing_summary }}
7
+ </EXISTING_SUMMARY>
8
+
9
+ <NEW_MESSAGES>
10
+ {{ new_messages }}
11
+ </NEW_MESSAGES>
12
+
13
+ Instructions:
14
+ 1. Update the existing summary sections with new information from the NEW_MESSAGES
15
+ 2. Maintain the same structure and format as the existing summary
16
+ 3. Preserve all important information from both existing and new content
17
+ 4. Do not repeat information already covered in the existing summary unless it's been updated or expanded
18
+ 5. Focus on integrating new developments, decisions, or progress into the appropriate sections
19
+
20
+ <OUTPUT_FORMAT>
21
+ Provide the complete updated summary following the exact same format as the existing summary:
22
+
23
+ # Context
24
+
25
+ Updated summary of the discussion, incorporating new topics or tasks. Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
26
+
27
+ # Key elements, learnings and entities
28
+
29
+ Present the updated important elements of context, learnings and entities from the entire discussion. Be very detailed.
30
+
31
+ Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
32
+
33
+ If new tool results were obtained, preserve them verbatim if short, summarize if long focusing on preserving all important facts.
34
+
35
+ If new user messages exist, preserve them verbatim if short to medium length, summarize if long focusing on preserving all important facts.
36
+
37
+ If there are any new links, IDs, filenames, etc. - preserve them verbatim.
38
+
39
+ # Timeline
40
+
41
+ Update the timeline with new important tasks and content:
42
+ - User: asked to handle a complex task X: <summary of the task>
43
+ - Assistant: we handle it by doing A, B, C...
44
+ - Tools used and output summary
45
+
46
+ [Include any new timeline entries from the new messages]
47
+
48
+ # Current status, task and objectives
49
+
50
+ Based on the complete conversation including new messages, update the current status, task and objectives.
51
+
52
+ CRITICAL: This section should reflect the most current state based on all messages including the new ones. This is not about summarizing but about the status, task and objectives currently active in the conversation to keep as much context as possible.
53
+ </OUTPUT_FORMAT>
@@ -0,0 +1,46 @@
1
+ Summarize the following conversation. Focus on key information and maintain context.
2
+ Provide the output as specified in <OUTPUT_FORMAT>.
3
+ Remove noisy information or irrelevant messages.
4
+
5
+ <OUTPUT_FORMAT>
6
+ # Context
7
+
8
+ Short summary of the discussion, grouped by topics or tasks if any.
9
+ Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
10
+
11
+ # Key elements, learnings and entities
12
+
13
+ Present the important elements of context, learnings and entities from the discussion. Be very detailed.
14
+
15
+ Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
16
+
17
+ 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.
18
+
19
+ If the agent has acknowledged the user's request, make sure to include the summary of the work done in the output so it doesn't acknowledge the user again.
20
+
21
+ If agent listed files, code or retrieved parts of the code, preserve it verbatim unless it's very long, then summarize it. ALWAYS IN THE CONTEXT OF WHAT THE AGENT NEEDS.
22
+
23
+ Keep user's messages verbatim if they are short to medium length, summarize them if they are long focusing on preserving all of the most important facts and information.
24
+
25
+ If there are any links mentioned, IDs, filenames, etc. - preserve them verbatim.
26
+
27
+ # Timeline
28
+
29
+ For important tasks and content, provide
30
+ - User: asked to handle a complex task X: <summary of the task>
31
+ - Assistant: we handle it by doing A, B, C...
32
+ - Tools used and output summary
33
+
34
+ ...
35
+ - User: asked to handle a complex task Y: <summary of the task>
36
+ - Assistant: we handle it by doing A, B, C...
37
+ - Tools used and output summary
38
+
39
+ Do not hesitate to merge original messages, remove noise. We want to be as concise and brief as possible.
40
+
41
+ # Current status, task and objectives
42
+
43
+ Based on the conversation, include here the current status, task and objectives.
44
+
45
+ CRITICAL: This is not about summarizing or compacting. We are talking about the status, task and objectives currently active in the convertion to keep as much context as possible regarding the last messages.
46
+ </OUTPUT_FORMAT>
@@ -0,0 +1,140 @@
1
+ """Template loader utility for managing Jinja2 prompt templates."""
2
+
3
+ import time
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
9
+
10
+ from shotgun.logging_config import setup_logger
11
+
12
+ logger = setup_logger(__name__)
13
+
14
+
15
+ class PromptLoader:
16
+ """Manages loading and rendering of Jinja2 prompt templates."""
17
+
18
+ def __init__(self, templates_dir: str | Path | None = None) -> None:
19
+ """Initialize the prompt loader.
20
+
21
+ Args:
22
+ templates_dir: Directory containing templates. Defaults to prompts directory.
23
+ """
24
+ if templates_dir is None:
25
+ templates_dir = Path(__file__).parent
26
+ else:
27
+ templates_dir = Path(templates_dir)
28
+
29
+ if not templates_dir.exists():
30
+ raise ValueError(f"Templates directory does not exist: {templates_dir}")
31
+
32
+ self.templates_dir = templates_dir
33
+ self.env = Environment(
34
+ loader=FileSystemLoader(str(templates_dir)),
35
+ autoescape=select_autoescape(["j2"]),
36
+ trim_blocks=True,
37
+ lstrip_blocks=True,
38
+ )
39
+
40
+ # Add common global functions and variables
41
+ self.env.globals.update(
42
+ {
43
+ "now": datetime.now,
44
+ "timestamp": time.time,
45
+ "current_timestamp": lambda: int(time.time()),
46
+ "timestamp_minus": lambda seconds: int(time.time()) - seconds,
47
+ }
48
+ )
49
+
50
+ logger.debug("Initialized PromptLoader with templates_dir: %s", templates_dir)
51
+
52
+ def load_template(self, template_path: str) -> Template:
53
+ """Load a template from the templates directory.
54
+
55
+ Args:
56
+ template_path: Path to template relative to templates directory
57
+
58
+ Returns:
59
+ Loaded Jinja2 template
60
+ """
61
+ try:
62
+ template = self.env.get_template(template_path)
63
+ logger.debug("Loaded template: %s", template_path)
64
+ return template
65
+ except Exception as e:
66
+ logger.error("Failed to load template %s: %s", template_path, str(e))
67
+ raise
68
+
69
+ def render(self, template_path: str, **context: Any) -> str:
70
+ """Render a template with the given context.
71
+
72
+ Args:
73
+ template_path: Path to template relative to templates directory
74
+ **context: Variables to pass to the template
75
+
76
+ Returns:
77
+ Rendered template content
78
+ """
79
+ template = self.load_template(template_path)
80
+ try:
81
+ result = template.render(**context)
82
+ logger.debug(
83
+ "Rendered template %s with %d context variables",
84
+ template_path,
85
+ len(context),
86
+ )
87
+ return result
88
+ except Exception as e:
89
+ logger.error("Failed to render template %s: %s", template_path, str(e))
90
+ raise
91
+
92
+ def render_string(self, template_string: str, **context: Any) -> str:
93
+ """Render a template from a string.
94
+
95
+ Args:
96
+ template_string: Template content as string
97
+ **context: Variables to pass to the template
98
+
99
+ Returns:
100
+ Rendered template content
101
+ """
102
+ try:
103
+ template = self.env.from_string(template_string)
104
+ result = template.render(**context)
105
+ logger.debug(
106
+ "Rendered string template with %d context variables", len(context)
107
+ )
108
+ return result
109
+ except Exception as e:
110
+ logger.error("Failed to render string template: %s", str(e))
111
+ raise
112
+
113
+
114
+ # Global instance for the default templates directory
115
+ _default_loader: PromptLoader | None = None
116
+
117
+
118
+ def get_prompt_loader() -> PromptLoader:
119
+ """Get the default prompt loader instance.
120
+
121
+ Returns:
122
+ Default PromptLoader instance
123
+ """
124
+ global _default_loader
125
+ if _default_loader is None:
126
+ _default_loader = PromptLoader()
127
+ return _default_loader
128
+
129
+
130
+ def render_prompt(template_path: str, **context: Any) -> str:
131
+ """Convenience function to render a template using the default loader.
132
+
133
+ Args:
134
+ template_path: Path to template relative to templates directory
135
+ **context: Variables to pass to the template
136
+
137
+ Returns:
138
+ Rendered template content
139
+ """
140
+ return get_prompt_loader().render(template_path, **context)
shotgun/py.typed ADDED
File without changes
@@ -0,0 +1,13 @@
1
+ """Shotgun SDK - Framework-agnostic business logic for CLI and TUI."""
2
+
3
+ from .codebase import CodebaseSDK
4
+ from .exceptions import CodebaseNotFoundError, CodebaseOperationError, ShotgunSDKError
5
+ from .services import get_codebase_service
6
+
7
+ __all__ = [
8
+ "CodebaseSDK",
9
+ "ShotgunSDKError",
10
+ "CodebaseNotFoundError",
11
+ "CodebaseOperationError",
12
+ "get_codebase_service",
13
+ ]