shotgun-sh 0.1.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.

Potentially problematic release.


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

Files changed (94) hide show
  1. shotgun/__init__.py +3 -0
  2. shotgun/agents/__init__.py +1 -0
  3. shotgun/agents/agent_manager.py +196 -0
  4. shotgun/agents/common.py +295 -0
  5. shotgun/agents/config/__init__.py +13 -0
  6. shotgun/agents/config/manager.py +215 -0
  7. shotgun/agents/config/models.py +120 -0
  8. shotgun/agents/config/provider.py +91 -0
  9. shotgun/agents/history/__init__.py +5 -0
  10. shotgun/agents/history/history_processors.py +213 -0
  11. shotgun/agents/models.py +94 -0
  12. shotgun/agents/plan.py +119 -0
  13. shotgun/agents/research.py +131 -0
  14. shotgun/agents/tasks.py +122 -0
  15. shotgun/agents/tools/__init__.py +26 -0
  16. shotgun/agents/tools/codebase/__init__.py +28 -0
  17. shotgun/agents/tools/codebase/codebase_shell.py +256 -0
  18. shotgun/agents/tools/codebase/directory_lister.py +141 -0
  19. shotgun/agents/tools/codebase/file_read.py +144 -0
  20. shotgun/agents/tools/codebase/models.py +252 -0
  21. shotgun/agents/tools/codebase/query_graph.py +67 -0
  22. shotgun/agents/tools/codebase/retrieve_code.py +81 -0
  23. shotgun/agents/tools/file_management.py +130 -0
  24. shotgun/agents/tools/user_interaction.py +36 -0
  25. shotgun/agents/tools/web_search.py +69 -0
  26. shotgun/cli/__init__.py +1 -0
  27. shotgun/cli/codebase/__init__.py +5 -0
  28. shotgun/cli/codebase/commands.py +202 -0
  29. shotgun/cli/codebase/models.py +21 -0
  30. shotgun/cli/config.py +261 -0
  31. shotgun/cli/models.py +10 -0
  32. shotgun/cli/plan.py +65 -0
  33. shotgun/cli/research.py +78 -0
  34. shotgun/cli/tasks.py +71 -0
  35. shotgun/cli/utils.py +25 -0
  36. shotgun/codebase/__init__.py +12 -0
  37. shotgun/codebase/core/__init__.py +46 -0
  38. shotgun/codebase/core/change_detector.py +358 -0
  39. shotgun/codebase/core/code_retrieval.py +243 -0
  40. shotgun/codebase/core/ingestor.py +1497 -0
  41. shotgun/codebase/core/language_config.py +297 -0
  42. shotgun/codebase/core/manager.py +1554 -0
  43. shotgun/codebase/core/nl_query.py +327 -0
  44. shotgun/codebase/core/parser_loader.py +152 -0
  45. shotgun/codebase/models.py +107 -0
  46. shotgun/codebase/service.py +148 -0
  47. shotgun/logging_config.py +172 -0
  48. shotgun/main.py +73 -0
  49. shotgun/prompts/__init__.py +5 -0
  50. shotgun/prompts/agents/__init__.py +1 -0
  51. shotgun/prompts/agents/partials/codebase_understanding.j2 +79 -0
  52. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +10 -0
  53. shotgun/prompts/agents/partials/interactive_mode.j2 +8 -0
  54. shotgun/prompts/agents/plan.j2 +57 -0
  55. shotgun/prompts/agents/research.j2 +38 -0
  56. shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +13 -0
  57. shotgun/prompts/agents/state/system_state.j2 +1 -0
  58. shotgun/prompts/agents/tasks.j2 +67 -0
  59. shotgun/prompts/codebase/__init__.py +1 -0
  60. shotgun/prompts/codebase/cypher_query_patterns.j2 +221 -0
  61. shotgun/prompts/codebase/cypher_system.j2 +28 -0
  62. shotgun/prompts/codebase/enhanced_query_context.j2 +10 -0
  63. shotgun/prompts/codebase/partials/cypher_rules.j2 +24 -0
  64. shotgun/prompts/codebase/partials/graph_schema.j2 +28 -0
  65. shotgun/prompts/codebase/partials/temporal_context.j2 +21 -0
  66. shotgun/prompts/history/__init__.py +1 -0
  67. shotgun/prompts/history/summarization.j2 +46 -0
  68. shotgun/prompts/loader.py +140 -0
  69. shotgun/prompts/user/research.j2 +5 -0
  70. shotgun/py.typed +0 -0
  71. shotgun/sdk/__init__.py +13 -0
  72. shotgun/sdk/codebase.py +195 -0
  73. shotgun/sdk/exceptions.py +17 -0
  74. shotgun/sdk/models.py +189 -0
  75. shotgun/sdk/services.py +23 -0
  76. shotgun/telemetry.py +68 -0
  77. shotgun/tui/__init__.py +0 -0
  78. shotgun/tui/app.py +49 -0
  79. shotgun/tui/components/prompt_input.py +69 -0
  80. shotgun/tui/components/spinner.py +86 -0
  81. shotgun/tui/components/splash.py +25 -0
  82. shotgun/tui/components/vertical_tail.py +28 -0
  83. shotgun/tui/screens/chat.py +415 -0
  84. shotgun/tui/screens/chat.tcss +28 -0
  85. shotgun/tui/screens/provider_config.py +221 -0
  86. shotgun/tui/screens/splash.py +31 -0
  87. shotgun/tui/styles.tcss +10 -0
  88. shotgun/utils/__init__.py +5 -0
  89. shotgun/utils/file_system_utils.py +31 -0
  90. shotgun_sh-0.1.0.dev1.dist-info/METADATA +318 -0
  91. shotgun_sh-0.1.0.dev1.dist-info/RECORD +94 -0
  92. shotgun_sh-0.1.0.dev1.dist-info/WHEEL +4 -0
  93. shotgun_sh-0.1.0.dev1.dist-info/entry_points.txt +3 -0
  94. shotgun_sh-0.1.0.dev1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,67 @@
1
+ You are a task management assistant with access to research data and project plans.
2
+ {% include 'agents/partials/common_agent_system_prompt.j2' %}
3
+
4
+ Your job is to:
5
+ 1. FIRST: Load previous research from research.md using read_file("research.md") if available
6
+ 2. SECOND: Load existing plan from plan.md using read_file("plan.md") if available
7
+ 3. THIRD: Load existing tasks from tasks.md using read_file("tasks.md") if it exists
8
+ 4. ANALYZE: Understand current context and the user's task creation/update request
9
+ 5. CREATE/UPDATE: Generate or modify actionable tasks based on research and plans
10
+ 6. WRITE: Save the updated tasks to tasks.md using write_file("tasks.md", content)
11
+
12
+ TASK CREATION PRINCIPLES:
13
+ - Base tasks on available research findings and plan requirements
14
+ - Create specific, actionable tasks with clear acceptance criteria
15
+ - Include effort estimates and priority levels
16
+ - Organize tasks by categories or project phases
17
+ - Consider dependencies between tasks
18
+ - Make tasks testable and verifiable
19
+ - Align with goals and steps from the plan
20
+ - Include both development and testing/validation tasks
21
+
22
+ {% if interactive_mode %}
23
+ USER INTERACTION - ASK CLARIFYING QUESTIONS:
24
+
25
+ - ALWAYS ask clarifying questions when the request is vague or ambiguous
26
+ - Use ask_user tool to gather specific details about:
27
+ - Specific features or functionality to prioritize
28
+ - Technical constraints or preferences
29
+ - Timeline and resource constraints
30
+ - Definition of "done" for key deliverables
31
+ - Testing and quality requirements
32
+ - Team size and skill levels
33
+ - Integration requirements
34
+ - Ask follow-up questions to ensure tasks are properly scoped
35
+ - Confirm task priorities and dependencies with the user
36
+ - Better to ask 2-3 targeted questions than create generic tasks
37
+ {% else %}
38
+ NON-INTERACTIVE MODE - MAKE REASONABLE ASSUMPTIONS:
39
+
40
+ - Make reasonable assumptions based on industry best practices
41
+ - Use sensible defaults for technical constraints and timelines
42
+ - Create tasks with standard definitions of "done"
43
+ - Assume typical team sizes and skill levels
44
+ - Include common testing and quality assurance tasks
45
+ - Create tasks that follow standard project management practices
46
+ {% endif %}
47
+
48
+ INTEGRATION WITH RESEARCH & PLAN:
49
+ - Reference specific findings from research.md when creating tasks
50
+ - Align tasks with action steps outlined in plan.md
51
+ - Consider technical feasibility based on research
52
+ - Include tasks for addressing challenges identified in plan
53
+ - Create validation/testing tasks for success criteria from plan
54
+ - Break down high-level plan steps into granular, executable tasks
55
+
56
+ IMPORTANT RULES:
57
+ - Make at most 1 tasks file write per request
58
+ - Always base tasks on available research and plan when relevant
59
+ - Create specific, testable tasks rather than vague objectives
60
+ - Consider realistic timelines and team capabilities
61
+ - Include both implementation and validation/testing tasks
62
+ {% if interactive_mode %}
63
+ - When in doubt about any aspect of the requirements, ASK before proceeding
64
+ {% else %}
65
+ - When in doubt, make reasonable assumptions and proceed with best practices
66
+ {% endif %}
67
+ - Ensure tasks are properly prioritized and sequenced
@@ -0,0 +1 @@
1
+ """Codebase analysis prompt templates."""
@@ -0,0 +1,221 @@
1
+ **Pattern: Finding All Classes**
2
+ ```cypher
3
+ // "Find all Python classes" or "list all classes" or "show me all classes"
4
+ MATCH (c:Class)
5
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
6
+ ORDER BY c.name
7
+ ```
8
+
9
+ **Pattern: Finding Classes with Path Information**
10
+ ```cypher
11
+ // "Find Python classes with their file paths" or "show classes and where they are defined"
12
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
13
+ RETURN c.name AS name, c.qualified_name AS qualified_name, m.path AS module_path, 'Class' AS type
14
+ ORDER BY m.path, c.name
15
+ ```
16
+
17
+ **Pattern: Finding Decorated Functions/Methods (e.g., Workflows, Tasks)**
18
+ ```cypher
19
+ // "Find all prefect flows" or "what are the workflows?" or "show me the tasks"
20
+ // Use separate MATCH clauses since Kuzu doesn't support union types
21
+ MATCH (n:Function)
22
+ WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
23
+ RETURN n.name AS name, n.qualified_name AS qualified_name, 'Function' AS type
24
+ UNION ALL
25
+ MATCH (n:Method)
26
+ WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
27
+ RETURN n.name AS name, n.qualified_name AS qualified_name, 'Method' AS type
28
+ ```
29
+
30
+ **Pattern: Finding Content by Path (Using UNION ALL for Different Types)**
31
+ ```cypher
32
+ // "what is in the 'workflows/src' directory?" or "list files in workflows"
33
+ // Use separate queries with UNION ALL to handle different node types
34
+ MATCH (n:Module)
35
+ WHERE n.path STARTS WITH 'workflows'
36
+ RETURN n.name AS name, n.path AS path, 'Module' AS type
37
+ UNION ALL
38
+ MATCH (n:File)
39
+ WHERE n.path STARTS WITH 'workflows'
40
+ RETURN n.name AS name, n.path AS path, 'File' AS type
41
+ UNION ALL
42
+ MATCH (n:Folder)
43
+ WHERE n.path STARTS WITH 'workflows'
44
+ RETURN n.name AS name, n.path AS path, 'Folder' AS type
45
+ ```
46
+
47
+ **Pattern: Keyword & Concept Search (Fallback for general terms)**
48
+ ```cypher
49
+ // "find things related to 'database'"
50
+ MATCH (n)
51
+ WHERE toLower(n.name) CONTAINS 'database' OR (n.qualified_name IS NOT NULL AND toLower(n.qualified_name) CONTAINS 'database')
52
+ ```
53
+
54
+ **Pattern: Time-based Queries (IMPORTANT: Use actual timestamps from user query)**
55
+ ```cypher
56
+ // "What functions were added in the last 2 minutes?" when current timestamp is provided
57
+ MATCH (f:Function)
58
+ WHERE f.created_at > [current_timestamp - 120] // This is current_timestamp - 120
59
+ RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
60
+ ORDER BY f.created_at DESC
61
+ ```
62
+
63
+ ```cypher
64
+ // "What classes were modified today?" when current timestamp is provided
65
+ MATCH (c:Class)
66
+ WHERE c.updated_at >= [today's start timestamp] // This is today's start
67
+ RETURN c.name AS name, c.qualified_name AS qualified_name, c.updated_at AS updated_timestamp
68
+ ORDER BY c.updated_at DESC
69
+ ```
70
+
71
+ **Pattern: Finding Files by Extension**
72
+ ```cypher
73
+ // "Find all TypeScript files" or "show me .ts files"
74
+ // IMPORTANT: File extensions are stored WITH the dot (e.g., ".ts" not "ts")
75
+ MATCH (f:File)
76
+ WHERE f.extension = '.ts'
77
+ RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
78
+ ORDER BY f.path
79
+ ```
80
+
81
+ ```cypher
82
+ // "Find JavaScript and TypeScript files"
83
+ MATCH (f:File)
84
+ WHERE f.extension IN ['.js', '.ts', '.jsx', '.tsx']
85
+ RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
86
+ ORDER BY f.path
87
+ ```
88
+
89
+ **Pattern: Finding a Specific File**
90
+ ```cypher
91
+ // "Find the main README.md"
92
+ MATCH (f:File) WHERE toLower(f.name) = 'readme.md' AND f.path = 'README.md'
93
+ RETURN f.path as path, f.name as name, 'File' as type
94
+ ```
95
+
96
+ **Pattern: Finding Classes in a Specific Directory**
97
+ ```cypher
98
+ // "Find classes in the server directory"
99
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
100
+ WHERE m.path STARTS WITH 'server/'
101
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
102
+ ```
103
+
104
+ **Pattern: Finding Modules with Most Classes**
105
+ ```cypher
106
+ // "Find modules that define the most classes"
107
+ MATCH (m:Module)-[:DEFINES]->(c:Class)
108
+ WITH m, count(c) AS class_count
109
+ ORDER BY class_count DESC
110
+ LIMIT 10
111
+ RETURN m.name AS name, m.qualified_name AS qualified_name, m.path AS path, class_count
112
+ ```
113
+
114
+ **Pattern: Finding Classes with Method Counts**
115
+ ```cypher
116
+ // "Find classes with more than N methods" or "Show me classes that have at least X methods"
117
+ MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
118
+ WITH c, count(m) AS method_count
119
+ WHERE method_count > 10 // Replace 10 with the actual number from query
120
+ RETURN c.name AS name, c.qualified_name AS qualified_name, method_count
121
+ ORDER BY method_count DESC
122
+ ```
123
+
124
+ **Pattern: Finding Classes with Inheritance (Note: INHERITS relationships must exist)**
125
+ ```cypher
126
+ // "Find classes with children/subclasses"
127
+ // This will return NO results if no inheritance relationships exist in the graph
128
+ MATCH (child:Class)-[:INHERITS]->(parent:Class)
129
+ WITH parent, count(child) AS child_count
130
+ ORDER BY child_count DESC
131
+ LIMIT 10
132
+ RETURN parent.name AS name, parent.qualified_name AS qualified_name, child_count
133
+ ```
134
+
135
+ **Pattern: Finding Parent Classes of a Specific Class**
136
+ ```cypher
137
+ // "What are the parent classes of DeputyAgent?" or "What does DeputyAgent inherit from?"
138
+ // Use name for short class names (when user doesn't provide full path)
139
+ MATCH (child:Class)-[:INHERITS]->(parent:Class)
140
+ WHERE toLower(child.name) = 'deputyagent'
141
+ RETURN parent.name AS name, parent.qualified_name AS qualified_name
142
+ ```
143
+
144
+ **Pattern: Finding Methods of a Specific Class**
145
+ ```cypher
146
+ // "What methods does WebSocketServer have?" or "List methods in WebSocketServer class"
147
+ // When user provides just the class name without full path
148
+ MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
149
+ WHERE c.name = 'WebSocketServer'
150
+ RETURN m.name AS name, m.qualified_name AS qualified_name, 'Method' AS type
151
+ ORDER BY m.name
152
+ ```
153
+
154
+ **Pattern: Finding a Specific Entity by Full Qualified Name**
155
+ ```cypher
156
+ // "Find shotgun.server.WebSocketServer" or "Show me api.websocket.server.WebSocketServer"
157
+ // When user provides a dotted path, match against qualified_name
158
+ MATCH (c:Class)
159
+ WHERE c.qualified_name = 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer'
160
+ RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
161
+ ```
162
+
163
+ **Pattern: Finding Recently Added/Modified Code**
164
+ ```cypher
165
+ // "Find functions added in the last 24 hours" or "What new functions were added today?"
166
+ // Note: In Kuzu, use Unix timestamps directly (seconds since epoch)
167
+ // Example: 1704067200 represents 2024-01-01 00:00:00 UTC
168
+ // For "today": use timestamp from start of current day
169
+ // For "last 24 hours": use current_timestamp - 86400
170
+ MATCH (f:Function)
171
+ WHERE f.created_at > [current_timestamp - 86400] // Replace with actual timestamp for "24 hours ago"
172
+ RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
173
+ ORDER BY f.created_at DESC
174
+ ```
175
+
176
+ **Pattern: Finding Files Modified Recently**
177
+ ```cypher
178
+ // "Find files modified today" or "Which files changed in the last hour?"
179
+ // For "last hour": use current_timestamp - 3600
180
+ // For "today": use timestamp from start of current day
181
+ MATCH (fm:FileMetadata)
182
+ WHERE fm.mtime > [current_timestamp - 3600] // Replace with actual timestamp
183
+ RETURN fm.filepath AS path, fm.mtime AS last_modified
184
+ ORDER BY fm.mtime DESC
185
+ ```
186
+
187
+ **Pattern: Queries About Deleted/Removed Entities**
188
+ ```cypher
189
+ // "What functions were deleted/removed?" or "Show me classes that no longer exist"
190
+ // Query the DeletionLog table for tracking removed entities
191
+ MATCH (d:DeletionLog)
192
+ WHERE d.entity_type = 'Function' AND d.deleted_at > [current_timestamp - 86400] // Replace with timestamp for time range
193
+ RETURN d.entity_qualified_name AS name, d.deleted_from_file AS file, d.deleted_at AS deleted_at, d.deletion_reason AS reason
194
+ ORDER BY d.deleted_at DESC
195
+ ```
196
+
197
+ **Pattern: Finding Where a Method/Function is Called**
198
+ ```cypher
199
+ // "where is WebSocketServer.start called?" or "find callers of method X"
200
+ // For partial names like 'WebSocketServer.start', use ENDS WITH pattern
201
+ MATCH (caller:Method)-[:CALLS]->(target:Method)
202
+ WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
203
+ RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Method' AS caller_type
204
+ UNION ALL
205
+ MATCH (caller:Function)-[:CALLS]->(target:Method)
206
+ WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
207
+ RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Function' AS caller_type
208
+ ```
209
+
210
+ **Pattern: Finding What a Method/Function Calls**
211
+ ```cypher
212
+ // "what does WebSocketServer.start call?" or "what methods does X invoke?"
213
+ // Use ENDS WITH for partial names, UNION ALL to handle different target types
214
+ MATCH (source:Method)-[:CALLS]->(target:Method)
215
+ WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
216
+ RETURN target.name AS name, target.qualified_name AS qualified_name, 'Method' AS target_type
217
+ UNION ALL
218
+ MATCH (source:Method)-[:CALLS]->(target:Function)
219
+ WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
220
+ RETURN target.name AS name, target.qualified_name AS qualified_name, 'Function' AS target_type
221
+ ```
@@ -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,28 @@
1
+ **1. Graph Schema Definition**
2
+ The database contains information about a codebase, structured with the following nodes and relationships.
3
+
4
+ Node Labels and Their Key Properties:
5
+ - Project: {name: string}
6
+ - Package: {qualified_name: string, name: string, path: string}
7
+ - Folder: {path: string, name: string}
8
+ - File: {path: string, name: string, extension: string} // Note: extension includes the dot (e.g., ".ts", ".py", ".js")
9
+ - FileMetadata: {filepath: string, mtime: int64, hash: string, last_updated: int64}
10
+ - Module: {qualified_name: string, name: string, path: string, created_at: int64, updated_at: int64}
11
+ - Class: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
12
+ - Function: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
13
+ - Method: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
14
+ - ExternalPackage: {name: string, version_spec: string}
15
+ - DeletionLog: {id: string, entity_type: string, entity_qualified_name: string, deleted_from_file: string, deleted_at: int64, deletion_reason: string}
16
+
17
+ Relationships (source)-[REL_TYPE]->(target):
18
+ - (Project|Package|Folder) -[:CONTAINS_PACKAGE|CONTAINS_FOLDER|CONTAINS_FILE|CONTAINS_MODULE]-> (various)
19
+ - Module -[:DEFINES]-> (Class|Function)
20
+ - Class -[:DEFINES_METHOD]-> Method
21
+ - (Child Class) -[:INHERITS]-> (Parent Class)
22
+ - Method -[:OVERRIDES]-> Method
23
+ - Project -[:DEPENDS_ON_EXTERNAL]-> ExternalPackage
24
+ - (Function|Method) -[:CALLS]-> (Function|Method)
25
+ - FileMetadata -[:TRACKS_Module]-> Module
26
+ - FileMetadata -[:TRACKS_Class]-> Class
27
+ - FileMetadata -[:TRACKS_Function]-> Function
28
+ - 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,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)
@@ -0,0 +1,5 @@
1
+ Research the USER_QUERY thoroughly and provide comprehensive findings:
2
+
3
+ <USER_QUERY>
4
+ {{ user_query }}
5
+ </USER_QUERY>
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
+ ]