shotgun-sh 0.1.0.dev16__py3-none-any.whl → 0.1.0.dev18__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.

@@ -17,17 +17,23 @@ from pydantic_ai.agent import AgentRunResult
17
17
  from pydantic_ai.messages import (
18
18
  AgentStreamEvent,
19
19
  FinalResultEvent,
20
+ FunctionToolCallEvent,
21
+ FunctionToolResultEvent,
20
22
  ModelMessage,
21
23
  ModelRequest,
22
24
  ModelResponse,
23
25
  ModelResponsePart,
24
26
  PartDeltaEvent,
25
27
  PartStartEvent,
28
+ SystemPromptPart,
29
+ ToolCallPart,
26
30
  ToolCallPartDelta,
27
31
  )
28
32
  from textual.message import Message
29
33
  from textual.widget import Widget
30
34
 
35
+ from shotgun.agents.common import add_system_prompt_message
36
+
31
37
  from .history.compaction import apply_persistent_compaction
32
38
  from .models import AgentDeps, AgentRuntimeOptions, FileOperation
33
39
  from .plan import create_plan_agent
@@ -264,11 +270,6 @@ class AgentManager(Widget):
264
270
  self.ui_message_history.append(ModelRequest.user_text_prompt(prompt))
265
271
  self._post_messages_updated()
266
272
 
267
- # Ensure system prompt is added to message history before running agent
268
- from pydantic_ai.messages import SystemPromptPart
269
-
270
- from shotgun.agents.common import add_system_prompt_message
271
-
272
273
  # Start with persistent message history
273
274
  message_history = self.message_history
274
275
 
@@ -389,19 +390,33 @@ class AgentManager(Widget):
389
390
  state.latest_partial = partial_message
390
391
  self._post_partial_message(partial_message, False)
391
392
 
393
+ elif isinstance(event, FunctionToolCallEvent):
394
+ existing_call_idx = next(
395
+ (
396
+ i
397
+ for i, part in enumerate(partial_parts)
398
+ if isinstance(part, ToolCallPart)
399
+ and part.tool_call_id == event.part.tool_call_id
400
+ ),
401
+ None,
402
+ )
403
+ if existing_call_idx is not None:
404
+ partial_parts[existing_call_idx] = event.part
405
+ else:
406
+ partial_parts.append(event.part)
407
+ partial_message = self._build_partial_response(partial_parts)
408
+ if partial_message is not None:
409
+ state.latest_partial = partial_message
410
+ self._post_partial_message(partial_message, False)
411
+ elif isinstance(event, FunctionToolResultEvent):
412
+ self.ui_message_history.append(ModelRequest(parts=[event.result]))
413
+ self._post_messages_updated() ## this is what the user responded with
392
414
  elif isinstance(event, FinalResultEvent):
393
415
  final_message = (
394
416
  state.latest_partial
395
417
  or self._build_partial_response(partial_parts)
396
418
  )
397
- self._post_partial_message(final_message, True)
398
- state.latest_partial = None
399
- state.final_sent = True
400
- partial_parts.clear()
401
- self._stream_state = None
402
- break
403
-
404
- # Ignore other AgentStreamEvent variants (e.g. tool call notifications) for partial UI updates.
419
+ self._post_partial_message(final_message, False)
405
420
 
406
421
  except Exception: # pragma: no cover - defensive logging
407
422
  logger.exception(
@@ -13,8 +13,9 @@ logger = get_logger(__name__)
13
13
  async def ask_user(ctx: RunContext[AgentDeps], question: str) -> str:
14
14
  """Ask the human a question and return the answer.
15
15
 
16
+
16
17
  Args:
17
- question: The question to ask the user
18
+ question: The question to ask the user with a clear CTA at the end. Needs to be is readable, clear, and easy to understand. Use Markdown formatting. Make key phrases and words stand out.
18
19
 
19
20
  Returns:
20
21
  The user's response as a string
@@ -27,6 +27,14 @@ from shotgun.logging_config import get_logger
27
27
  logger = get_logger(__name__)
28
28
 
29
29
 
30
+ class CodebaseAlreadyIndexedError(Exception):
31
+ """Raised when a codebase is already indexed."""
32
+
33
+ def __init__(self, repo_path: str):
34
+ self.repo_path = repo_path
35
+ super().__init__(f"Codebase already indexed: {repo_path}")
36
+
37
+
30
38
  class CodebaseFileHandler(FileSystemEventHandler):
31
39
  """Handles file system events for code graph updates."""
32
40
 
@@ -339,9 +347,7 @@ class CodebaseGraphManager:
339
347
 
340
348
  # Check if graph already exists
341
349
  if graph_path.exists():
342
- raise ValueError(
343
- f"Graph already exists for {repo_path}. Use update_graph() to modify it."
344
- )
350
+ raise CodebaseAlreadyIndexedError(repo_path)
345
351
 
346
352
  # Import the builder from local core module
347
353
  from shotgun.codebase.core import CodebaseIngestor
@@ -14,7 +14,6 @@ You have access to a structured artifact system for organizing your work. Use ar
14
14
  - **Organization**: `.shotgun/{agent_mode}/{artifact_id}/{section_number}-{section_slug}.md`
15
15
 
16
16
  ### Best Practices:
17
- - Always start by checking existing artifacts with `list_artifacts()`
18
17
  - Use meaningful artifact IDs that describe the work
19
18
  - Organize content into logical sections (overview, analysis, recommendations, etc.)
20
19
  - Use descriptive section titles and slugs
@@ -27,8 +26,6 @@ Use artifact templates to help you create new artifacts.
27
26
 
28
27
  MOST IMPORTANT: WHEN YOU CREATE AN ARTIFACT FROM A TEMPLATE, ALWAYS RESPECT AND FOLLOW THE "INSTRUCTIONS" AND "PROMPT" CONTAINED IN THE TEMPLATE TO THE LETTER.
29
28
 
30
- Use `list_artifact_templates(agent_mode)` to see what templates are available.
31
-
32
29
  Use `create_artifact(artifact_id, agent_mode, name, template_id)` to create a new artifact with a template.
33
30
 
34
31
  Template ID example: "research/market_research"
@@ -23,7 +23,7 @@ Use meaningful artifact IDs like: "api-design-patterns", "microservices-study",
23
23
  ## RESEARCH PRINCIPLES
24
24
 
25
25
  {% if interactive_mode -%}
26
- - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR CONFIRMATION USING ask_user().
26
+ - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL USING ask_user(). FINISH THE QUESTION WITH ASKING FOR A GO AHEAD.
27
27
  {% endif -%}
28
28
  - Build upon existing research rather than starting from scratch
29
29
  - Focus on practical, actionable information over theoretical concepts
@@ -33,6 +33,7 @@ from shotgun.agents.models import (
33
33
  UserAnswer,
34
34
  UserQuestion,
35
35
  )
36
+ from shotgun.codebase.core.manager import CodebaseAlreadyIndexedError
36
37
  from shotgun.sdk.codebase import CodebaseSDK
37
38
  from shotgun.sdk.exceptions import CodebaseNotFoundError, InvalidPathError
38
39
  from shotgun.sdk.services import get_artifact_service, get_codebase_service
@@ -248,6 +249,12 @@ class CodebaseIndexScreen(ModalScreen[CodebaseIndexSelection | None]):
248
249
  disabled=True,
249
250
  )
250
251
 
252
+ def on_mount(self) -> None:
253
+ name_input = self.query_one("#index-codebase-name", Input)
254
+ if not name_input.value and self.selected_path:
255
+ name_input.value = self.selected_path.name
256
+ self._update_confirm()
257
+
251
258
  def _update_confirm(self) -> None:
252
259
  confirm = self.query_one("#index-confirm", Button)
253
260
  name_input = self.query_one("#index-codebase-name", Input)
@@ -423,7 +430,7 @@ class ChatScreen(Screen[None]):
423
430
  question_display.display = False
424
431
 
425
432
  def action_toggle_mode(self) -> None:
426
- modes = [AgentType.RESEARCH, AgentType.PLAN, AgentType.TASKS, AgentType.SPECIFY]
433
+ modes = [AgentType.RESEARCH, AgentType.SPECIFY, AgentType.PLAN, AgentType.TASKS]
427
434
  self.mode = modes[(modes.index(self.mode) + 1) % len(modes)]
428
435
  self.agent_manager.set_agent(self.mode)
429
436
  # whoops it actually changes focus. Let's be brutal for now
@@ -475,9 +482,14 @@ class ChatScreen(Screen[None]):
475
482
  if event.is_last:
476
483
  partial_response_widget.partial_response = None
477
484
 
485
+ def _clear_partial_response(self) -> None:
486
+ partial_response_widget = self.query_one(ChatHistory)
487
+ partial_response_widget.partial_response = None
488
+
478
489
  @on(MessageHistoryUpdated)
479
490
  def handle_message_history_updated(self, event: MessageHistoryUpdated) -> None:
480
491
  """Handle message history updates from the agent manager."""
492
+ self._clear_partial_response()
481
493
  self.messages = event.messages
482
494
 
483
495
  # If there are file operations, add a message showing the modified files
@@ -611,6 +623,11 @@ class ChatScreen(Screen[None]):
611
623
  severity="information",
612
624
  timeout=8,
613
625
  )
626
+
627
+ self.mount_hint(codebase_indexed_hint(selection.name))
628
+ except CodebaseAlreadyIndexedError as exc:
629
+ self.notify(str(exc), severity="warning")
630
+ return
614
631
  except InvalidPathError as exc:
615
632
  self.notify(str(exc), severity="error")
616
633
 
@@ -619,7 +636,6 @@ class ChatScreen(Screen[None]):
619
636
  finally:
620
637
  label.update("")
621
638
  label.refresh()
622
- self.mount_hint(codebase_indexed_hint(selection.name))
623
639
 
624
640
  @work
625
641
  async def run_agent(self, message: str) -> None:
@@ -52,6 +52,12 @@ class AgentModeProvider(Provider):
52
52
  lambda: self.set_mode(AgentType.RESEARCH),
53
53
  AgentType.RESEARCH,
54
54
  ),
55
+ (
56
+ "Switch to Specify Mode",
57
+ "📝 Create detailed specifications and requirements documents",
58
+ lambda: self.set_mode(AgentType.SPECIFY),
59
+ AgentType.SPECIFY,
60
+ ),
55
61
  (
56
62
  "Switch to Plan Mode",
57
63
  "📋 Create comprehensive, actionable plans with milestones",
@@ -1,12 +1,17 @@
1
+ import json
2
+ from collections.abc import Sequence
3
+
1
4
  from pydantic_ai.messages import (
2
5
  BuiltinToolCallPart,
3
6
  BuiltinToolReturnPart,
4
7
  ModelMessage,
5
8
  ModelRequest,
9
+ ModelRequestPart,
6
10
  ModelResponse,
7
11
  TextPart,
8
12
  ThinkingPart,
9
13
  ToolCallPart,
14
+ ToolReturnPart,
10
15
  )
11
16
  from textual.app import ComposeResult
12
17
  from textual.reactive import reactive
@@ -76,27 +81,32 @@ class ChatHistory(Widget):
76
81
 
77
82
  def compose(self) -> ComposeResult:
78
83
  self.vertical_tail = VerticalTail()
79
- yield self.vertical_tail
80
- yield PartialResponseWidget(self.partial_response).data_bind(
81
- item=ChatHistory.partial_response
82
- )
84
+ with self.vertical_tail:
85
+ for item in self.items:
86
+ if isinstance(item, ModelRequest):
87
+ yield UserQuestionWidget(item)
88
+ elif isinstance(item, ModelResponse):
89
+ yield AgentResponseWidget(item)
90
+ yield PartialResponseWidget(self.partial_response).data_bind(
91
+ item=ChatHistory.partial_response
92
+ )
93
+
94
+ def watch_partial_response(self, _partial_response: ModelMessage | None) -> None:
95
+ self.call_after_refresh(self.autoscroll)
83
96
 
84
97
  def update_messages(self, messages: list[ModelMessage]) -> None:
85
98
  """Update the displayed messages without recomposing."""
86
99
  if not self.vertical_tail:
87
100
  return
88
101
 
89
- # Clear existing widgets
90
- self.vertical_tail.remove_children()
102
+ self.items = messages
103
+ self.refresh(recompose=True)
91
104
 
92
- # Add new message widgets
93
- for item in messages:
94
- if isinstance(item, ModelRequest):
95
- self.vertical_tail.mount(UserQuestionWidget(item))
96
- elif isinstance(item, ModelResponse):
97
- self.vertical_tail.mount(AgentResponseWidget(item))
105
+ self.autoscroll()
98
106
 
99
- self.items = messages
107
+ def autoscroll(self) -> None:
108
+ if self.vertical_tail:
109
+ self.vertical_tail.scroll_end(animate=False)
100
110
 
101
111
 
102
112
  class UserQuestionWidget(Widget):
@@ -114,6 +124,20 @@ class UserQuestionWidget(Widget):
114
124
  )
115
125
  yield Markdown(markdown=f"**>** {prompt}")
116
126
 
127
+ def format_prompt_parts(self, parts: Sequence[ModelRequestPart]) -> str:
128
+ acc = ""
129
+ for part in parts:
130
+ if isinstance(part, TextPart):
131
+ acc += (
132
+ f"**>** {part.content if isinstance(part.content, str) else ''}\n\n"
133
+ )
134
+ elif isinstance(part, ToolCallPart):
135
+ if part.tool_name == "ask_user" and isinstance(part.content, dict):
136
+ acc += f"**>** {part.content['answer']}\n\n"
137
+ else:
138
+ acc += "∟ finished\n\n" # let's not show anything yet
139
+ return acc
140
+
117
141
 
118
142
  class AgentResponseWidget(Widget):
119
143
  def __init__(self, item: ModelResponse | None) -> None:
@@ -131,21 +155,38 @@ class AgentResponseWidget(Widget):
131
155
  acc = ""
132
156
  if self.item is None:
133
157
  return ""
134
- for part in self.item.parts: # TextPart | ToolCallPart | BuiltinToolCallPart | BuiltinToolReturnPart | ThinkingPart
158
+ for idx, part in enumerate(self.item.parts):
135
159
  if isinstance(part, TextPart):
136
160
  acc += part.content + "\n\n"
137
161
  elif isinstance(part, ToolCallPart):
138
162
  parts_str = self._format_tool_call_part(part)
139
163
  acc += parts_str + "\n\n"
164
+ elif isinstance(part, ToolReturnPart):
165
+ acc += (
166
+ f"tool ({part.tool_name}) return: "
167
+ + self._format_tool_return_call_part(part)
168
+ + "\n\n"
169
+ )
140
170
  elif isinstance(part, BuiltinToolCallPart):
141
- acc += f"{part.tool_name}({part.args})\n\n"
171
+ acc += f"builtin tool ({part.tool_name}): {part.args}\n\n"
142
172
  elif isinstance(part, BuiltinToolReturnPart):
143
- acc += f"{part.tool_name}()\n\n"
173
+ acc += f"builtin tool ({part.tool_name}) return: {part.content}\n\n"
144
174
  elif isinstance(part, ThinkingPart):
145
- acc += f"{part.content}\n\n"
175
+ if (
176
+ idx == len(self.item.parts) - 1
177
+ ): # show the thinking part only if it's the last part
178
+ acc += (
179
+ f"thinking: {part.content}\n\n"
180
+ if part.content
181
+ else "Thinking..."
182
+ )
183
+ else:
184
+ continue
146
185
  return acc.strip()
147
186
 
148
187
  def _format_tool_call_part(self, part: ToolCallPart) -> str:
188
+ if part.tool_name == "ask_user":
189
+ return self._format_ask_user_part(part)
149
190
  if part.tool_name == "write_artifact_section":
150
191
  if isinstance(part.args, dict) and "section_title" in part.args:
151
192
  return f"{part.tool_name}({part.args['section_title']})"
@@ -155,6 +196,31 @@ class AgentResponseWidget(Widget):
155
196
  if isinstance(part.args, dict) and "name" in part.args:
156
197
  return f"{part.tool_name}({part.args['name']})"
157
198
  else:
158
- return f"{part.tool_name}()"
199
+ return f"{part.tool_name}()"
159
200
 
160
201
  return f"{part.tool_name}({part.args})"
202
+
203
+ def _format_ask_user_part(
204
+ self,
205
+ part: ToolCallPart,
206
+ ) -> str:
207
+ return "*Answer to continue*"
208
+ if isinstance(part.args, str):
209
+ try:
210
+ _args = json.loads(part.args) if part.args.strip() else {}
211
+ except json.JSONDecodeError:
212
+ _args = {}
213
+ else:
214
+ _args = part.args
215
+
216
+ if isinstance(_args, dict) and "question" in _args:
217
+ return f"{_args['question']}"
218
+ else:
219
+ return "❓ "
220
+
221
+ def _format_tool_return_call_part(self, part: ToolReturnPart) -> str:
222
+ content = part.content
223
+ if part.tool_name == "ask_user":
224
+ response = content.get("answer", "") if isinstance(content, dict) else ""
225
+ return f"**⏺** {response}"
226
+ return f"∟ {content}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.1.0.dev16
3
+ Version: 0.1.0.dev18
4
4
  Summary: AI-powered research, planning, and task management CLI tool
5
5
  Project-URL: Homepage, https://shotgun.sh/
6
6
  Project-URL: Repository, https://github.com/shotgun-sh/shotgun
@@ -7,7 +7,7 @@ shotgun/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  shotgun/sentry_telemetry.py,sha256=3r9on0GQposn9aX6Dkb9mrfaVQl_dIZzhu9BjE838AU,2854
8
8
  shotgun/telemetry.py,sha256=aBwCRFU97oiIK5K13OhT7yYCQUAVQyrvnoG-aX3k2ZE,3109
9
9
  shotgun/agents/__init__.py,sha256=8Jzv1YsDuLyNPFJyckSr_qI4ehTVeDyIMDW4omsfPGc,25
10
- shotgun/agents/agent_manager.py,sha256=VRMPfwPtgTBtzyp-JYyyitGk_ZQ8oh8hTmB2cEylyZ0,16024
10
+ shotgun/agents/agent_manager.py,sha256=N9BUoGCydfiHVxLImG4JraSO4niQJqJPcj82M0ATT6g,16828
11
11
  shotgun/agents/artifact_state.py,sha256=WkspYQe-9CvBS90PapBsX997yvJ5KWH-qtSXIWmfvp0,2121
12
12
  shotgun/agents/common.py,sha256=my-Y7VNNpDDYxDJ4hlRmTs7lIS8tBKFvR9ew7uKxcPE,11369
13
13
  shotgun/agents/models.py,sha256=6edILmN7caDAmf8x-qgl7lA42tl2b-ZsiC3da8tS3Xw,7127
@@ -32,7 +32,7 @@ shotgun/agents/history/token_estimation.py,sha256=iNqhDSqFzG0YYxGijMRzj54GALFglO
32
32
  shotgun/agents/tools/__init__.py,sha256=QaN80IqWvB5qEcjHqri1-PYvYlO74vdhcwLugoEdblo,772
33
33
  shotgun/agents/tools/artifact_management.py,sha256=f8WvCCcXb_sMK0U4Y8D1RLUhcj2rhT6CrxB3bURYxcs,17205
34
34
  shotgun/agents/tools/file_management.py,sha256=6ru6DXAl-S6DiCt2HLGTDrK2rJBJpn-t6RkSHzYbxc4,4571
35
- shotgun/agents/tools/user_interaction.py,sha256=7l0OY8EdgO-9gkKy-yOv0V0P_Uzzfk0jMU39d4XN1xM,1087
35
+ shotgun/agents/tools/user_interaction.py,sha256=b3ncEpvoD06Cz4hwsS-ppVbQajQj640iWnVfA5WBjAA,1236
36
36
  shotgun/agents/tools/codebase/__init__.py,sha256=ceAGkK006NeOYaIJBLQsw7Q46sAyCRK9PYDs8feMQVw,661
37
37
  shotgun/agents/tools/codebase/codebase_shell.py,sha256=2zEq8YXzdcYttYAfKso_JGRqXHyy3xgAuWlf0unopFg,8635
38
38
  shotgun/agents/tools/codebase/directory_lister.py,sha256=MCLGDEc0F-4J8-UrquxdJrIQYs5xzYgws65mjf7Q7X4,4724
@@ -79,17 +79,17 @@ shotgun/codebase/core/change_detector.py,sha256=kWCYLWzRzb3IGGOj71KBn7UOCOKMpINJ
79
79
  shotgun/codebase/core/code_retrieval.py,sha256=_JVyyQKHDFm3dxOOua1mw9eIIOHIVz3-I8aZtEsEj1E,7927
80
80
  shotgun/codebase/core/ingestor.py,sha256=zMjadeqDOEr2v3vhTS25Jvx0WsLPXpgwquZfbdiz57o,59810
81
81
  shotgun/codebase/core/language_config.py,sha256=vsqHyuFnumRPRBV1lMOxWKNOIiClO6FyfKQR0fGrtl4,8934
82
- shotgun/codebase/core/manager.py,sha256=5GlJKykDGvnb6nTr9w3kyCPTL4OQgmBoesnWr28wvTg,55419
82
+ shotgun/codebase/core/manager.py,sha256=GpLeyxC25HJKxh3wQxTiTkXv9NUDQdH6Mi9IdaMUmVQ,55586
83
83
  shotgun/codebase/core/nl_query.py,sha256=iV6NbsyDd1SQpT9U9BtgxcZPsNoEW3OHrkk475r_jAY,11410
84
84
  shotgun/codebase/core/parser_loader.py,sha256=LZRrDS8Sp518jIu3tQW-BxdwJ86lnsTteI478ER9Td8,4278
85
85
  shotgun/prompts/__init__.py,sha256=RswUm0HMdfm2m2YKUwUsEdRIwoczdbI7zlucoEvHYRo,132
86
86
  shotgun/prompts/loader.py,sha256=jy24-E02pCSmz2651aCT2NgHfRrHAGMYvKrD6gs0Er8,4424
87
87
  shotgun/prompts/agents/__init__.py,sha256=YRIJMbzpArojNX1BP5gfxxois334z_GQga8T-xyWMbY,39
88
88
  shotgun/prompts/agents/plan.j2,sha256=mogmrjqLx5xSXYqWdvLqcObZSfLVLQI39JpVs3Z-V84,2494
89
- shotgun/prompts/agents/research.j2,sha256=LxlASYYt45sDmZW8YLJYH8ftGWa6Jvx5aD0MGNXXVjs,3025
89
+ shotgun/prompts/agents/research.j2,sha256=cLwPdIvv1MvVaHZYLdBhON-8qk-c3kjrRTF1-7Bc-vI,3069
90
90
  shotgun/prompts/agents/specify.j2,sha256=1CC2SHsxA1Yma0gSFsq-k3VpwtEohN9nh2qeRMMRPRA,1809
91
91
  shotgun/prompts/agents/tasks.j2,sha256=OYW1zsYRJxoQF4yVMqJNgi4SNz3YmcP4sljHmmqAu4Q,3613
92
- shotgun/prompts/agents/partials/artifact_system.j2,sha256=AD1CvHDSZEmjplmDw443PeOmcXUgM5JdNLu1_mz18kM,1678
92
+ shotgun/prompts/agents/partials/artifact_system.j2,sha256=kaqkMU-t2x3M7z-4HU4KffSFug1WM5VDsin6tCkxjHg,1528
93
93
  shotgun/prompts/agents/partials/codebase_understanding.j2,sha256=AQmN04VRzGmLbxKKthMK4hkJZ9mIU1NMKIpTDOHJrPM,5051
94
94
  shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=UgEHSudzfsCcKHp-Nt6tlsel8ap93z7yevbt0r9SSSg,1663
95
95
  shotgun/prompts/agents/partials/content_formatting.j2,sha256=MG0JB7SSp8YV5akDWpbs2f9DcdREIYqLp38NnoWLeQ0,1854
@@ -123,20 +123,20 @@ shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4Ugad
123
123
  shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
124
124
  shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
125
125
  shotgun/tui/components/vertical_tail.py,sha256=kkCH0WjAh54jDvRzIaOffRZXUKn_zHFZ_ichfUpgzaE,1071
126
- shotgun/tui/screens/chat.py,sha256=x9_wdXl6Mbgwr_UfNfvWEkU-ua-Ph--9BmgrkIv-BEY,23922
126
+ shotgun/tui/screens/chat.py,sha256=2jtjRBU6r-V5frEud-NqIYLHTi0C5HX6uLAXOwYuUo8,24564
127
127
  shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
128
128
  shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
129
129
  shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
130
130
  shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw,706
131
131
  shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
- shotgun/tui/screens/chat_screen/command_providers.py,sha256=jeryNT0WGeU6-8UTdEQk0C8A_HgNGrTskBgpqMDyAQU,6952
133
- shotgun/tui/screens/chat_screen/history.py,sha256=eC8Md4wNyLv19exKLitNadyylTMmm7Rk8acd9h1QXtU,5062
132
+ shotgun/tui/screens/chat_screen/command_providers.py,sha256=4Q8jR7wN4e2q0SWHSsISZP-POyu1B9lyXgoOTKB4ZLc,7198
133
+ shotgun/tui/screens/chat_screen/history.py,sha256=0rSb512ZhkF8zzqkWfwHp-Cmu5VIqL-LzPkohwlHe4Q,7447
134
134
  shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
135
135
  shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,1057
136
136
  shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
137
137
  shotgun/utils/update_checker.py,sha256=Xf-7w3Pos3etzCoT771gJe2HLkA8_V2GrqWy7ni9UqA,11373
138
- shotgun_sh-0.1.0.dev16.dist-info/METADATA,sha256=BZyZEVZzVDYuVHHMhlc-SkciK_ocrPFpujSW9MtZINU,11271
139
- shotgun_sh-0.1.0.dev16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
140
- shotgun_sh-0.1.0.dev16.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
141
- shotgun_sh-0.1.0.dev16.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
142
- shotgun_sh-0.1.0.dev16.dist-info/RECORD,,
138
+ shotgun_sh-0.1.0.dev18.dist-info/METADATA,sha256=woXTk-ZMmEwPuNJXm-LS5ZG0DPFM8ZH39VLVWEhdvZU,11271
139
+ shotgun_sh-0.1.0.dev18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
140
+ shotgun_sh-0.1.0.dev18.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
141
+ shotgun_sh-0.1.0.dev18.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
142
+ shotgun_sh-0.1.0.dev18.dist-info/RECORD,,