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

@@ -37,6 +37,7 @@ from textual.widget import Widget
37
37
 
38
38
  from shotgun.agents.common import add_system_prompt_message, add_system_status_message
39
39
  from shotgun.agents.models import AgentType, FileOperation
40
+ from shotgun.tui.screens.chat_screen.hint_message import HintMessage
40
41
 
41
42
  from .export import create_export_agent
42
43
  from .history.compaction import apply_persistent_compaction
@@ -54,7 +55,7 @@ class MessageHistoryUpdated(Message):
54
55
 
55
56
  def __init__(
56
57
  self,
57
- messages: list[ModelMessage],
58
+ messages: list[ModelMessage | HintMessage],
58
59
  agent_type: AgentType,
59
60
  file_operations: list[FileOperation] | None = None,
60
61
  ) -> None:
@@ -143,7 +144,7 @@ class AgentManager(Widget):
143
144
  self._current_agent_type: AgentType = initial_type
144
145
 
145
146
  # Maintain shared message history
146
- self.ui_message_history: list[ModelMessage] = []
147
+ self.ui_message_history: list[ModelMessage | HintMessage] = []
147
148
  self.message_history: list[ModelMessage] = []
148
149
  self.recently_change_files: list[FileOperation] = []
149
150
  self._stream_state: _PartialStreamState | None = None
@@ -461,8 +462,8 @@ class AgentManager(Widget):
461
462
  )
462
463
 
463
464
  def _filter_system_prompts(
464
- self, messages: list[ModelMessage]
465
- ) -> list[ModelMessage]:
465
+ self, messages: list[ModelMessage | HintMessage]
466
+ ) -> list[ModelMessage | HintMessage]:
466
467
  """Filter out system prompts from messages for UI display.
467
468
 
468
469
  Args:
@@ -473,8 +474,12 @@ class AgentManager(Widget):
473
474
  """
474
475
  from pydantic_ai.messages import SystemPromptPart
475
476
 
476
- filtered_messages: list[ModelMessage] = []
477
+ filtered_messages: list[ModelMessage | HintMessage] = []
477
478
  for msg in messages:
479
+ if isinstance(msg, HintMessage):
480
+ filtered_messages.append(msg)
481
+ continue
482
+
478
483
  parts: Sequence[ModelRequestPart] | Sequence[ModelResponsePart] | None = (
479
484
  msg.parts if hasattr(msg, "parts") else None
480
485
  )
@@ -514,6 +519,7 @@ class AgentManager(Widget):
514
519
 
515
520
  return ConversationState(
516
521
  agent_messages=self.message_history.copy(),
522
+ ui_messages=self.ui_message_history.copy(),
517
523
  agent_type=self._current_agent_type.value,
518
524
  )
519
525
 
@@ -524,10 +530,16 @@ class AgentManager(Widget):
524
530
  state: ConversationState object to restore
525
531
  """
526
532
  # Restore message history for agents (includes system prompts)
527
- self.message_history = state.agent_messages.copy()
533
+ non_hint_messages = [
534
+ msg for msg in state.agent_messages if not isinstance(msg, HintMessage)
535
+ ]
536
+ self.message_history = non_hint_messages
528
537
 
529
- # Filter out system prompts for UI display
530
- self.ui_message_history = self._filter_system_prompts(state.agent_messages)
538
+ # Filter out system prompts for UI display while keeping hints
539
+ ui_source = state.ui_messages or cast(
540
+ list[ModelMessage | HintMessage], state.agent_messages
541
+ )
542
+ self.ui_message_history = self._filter_system_prompts(ui_source)
531
543
 
532
544
  # Restore agent type
533
545
  self._current_agent_type = AgentType(state.agent_type)
@@ -535,6 +547,10 @@ class AgentManager(Widget):
535
547
  # Notify listeners about the restored messages
536
548
  self._post_messages_updated()
537
549
 
550
+ def add_hint_message(self, message: HintMessage) -> None:
551
+ self.ui_message_history.append(message)
552
+ self._post_messages_updated()
553
+
538
554
 
539
555
  # Re-export AgentType for backward compatibility
540
556
  __all__ = [
shotgun/agents/common.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  from collections.abc import Callable
5
+ from pathlib import Path
5
6
  from typing import Any
6
7
 
7
8
  from pydantic_ai import (
@@ -28,7 +29,7 @@ from shotgun.utils.file_system_utils import get_shotgun_base_path
28
29
 
29
30
  from .history import token_limit_compactor
30
31
  from .history.compaction import apply_persistent_compaction
31
- from .models import AgentDeps, AgentRuntimeOptions
32
+ from .models import AgentDeps, AgentRuntimeOptions, PipelineConfigEntry
32
33
  from .tools import (
33
34
  append_file,
34
35
  ask_user,
@@ -197,33 +198,24 @@ def create_base_agent(
197
198
  return agent, deps
198
199
 
199
200
 
200
- def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
201
- """Extract table of contents from agent's markdown file.
201
+ def _extract_file_toc_content(
202
+ file_path: Path, max_depth: int | None = None, max_chars: int = 500
203
+ ) -> str | None:
204
+ """Extract TOC from a single file with depth and character limits.
202
205
 
203
206
  Args:
204
- agent_mode: The agent mode to extract TOC for
207
+ file_path: Path to the markdown file
208
+ max_depth: Maximum heading depth (1=#, 2=##, None=all)
209
+ max_chars: Maximum characters for the TOC
205
210
 
206
211
  Returns:
207
- Formatted TOC string (up to 2000 chars) or None if not applicable
212
+ Formatted TOC string or None if file doesn't exist
208
213
  """
209
- # Skip for EXPORT mode or no mode
210
- if (
211
- not agent_mode
212
- or agent_mode == AgentType.EXPORT
213
- or agent_mode not in AGENT_DIRECTORIES
214
- ):
215
- return None
216
-
217
- base_path = get_shotgun_base_path()
218
- md_file = AGENT_DIRECTORIES[agent_mode]
219
- md_path = base_path / md_file
220
-
221
- # Check if the markdown file exists
222
- if not md_path.exists():
214
+ if not file_path.exists():
223
215
  return None
224
216
 
225
217
  try:
226
- content = md_path.read_text(encoding="utf-8")
218
+ content = file_path.read_text(encoding="utf-8")
227
219
  lines = content.split("\n")
228
220
 
229
221
  # Extract headings
@@ -239,6 +231,10 @@ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
239
231
  else:
240
232
  break
241
233
 
234
+ # Skip if exceeds max_depth
235
+ if max_depth and level > max_depth:
236
+ continue
237
+
242
238
  # Get the heading text (remove the # symbols and clean up)
243
239
  heading_text = stripped[level:].strip()
244
240
  if heading_text:
@@ -246,21 +242,110 @@ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
246
242
  indent = " " * (level - 1)
247
243
  toc_lines.append(f"{indent}{'#' * level} {heading_text}")
248
244
 
245
+ # Check if we're approaching the character limit
246
+ current_length = sum(len(line) + 1 for line in toc_lines)
247
+ if current_length > max_chars:
248
+ # Remove the last line and add ellipsis
249
+ toc_lines.pop()
250
+ if toc_lines:
251
+ toc_lines.append(" ...")
252
+ break
253
+
249
254
  if not toc_lines:
250
255
  return None
251
256
 
252
- # Join and truncate to 2000 characters
253
- toc = "\n".join(toc_lines)
254
- if len(toc) > 2000:
255
- toc = toc[:1997] + "..."
256
-
257
- return toc
257
+ return "\n".join(toc_lines)
258
258
 
259
259
  except Exception as e:
260
- logger.debug(f"Failed to extract TOC from {md_file}: {e}")
260
+ logger.debug(f"Failed to extract TOC from {file_path}: {e}")
261
261
  return None
262
262
 
263
263
 
264
+ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
265
+ """Extract TOCs from current and prior agents' files in the pipeline.
266
+
267
+ Shows full TOC of agent's own file and high-level summaries of prior agents'
268
+ files to maintain context awareness while keeping context window tight.
269
+
270
+ Args:
271
+ agent_mode: The agent mode to extract TOC for
272
+
273
+ Returns:
274
+ Formatted multi-file TOC string or None if not applicable
275
+ """
276
+ # Skip if no mode
277
+ if not agent_mode:
278
+ return None
279
+
280
+ # Define pipeline order and dependencies
281
+ pipeline_config: dict[AgentType, PipelineConfigEntry] = {
282
+ AgentType.RESEARCH: PipelineConfigEntry(
283
+ own_file="research.md",
284
+ prior_files=[], # First in pipeline
285
+ ),
286
+ AgentType.SPECIFY: PipelineConfigEntry(
287
+ own_file="specification.md",
288
+ prior_files=["research.md"],
289
+ ),
290
+ AgentType.PLAN: PipelineConfigEntry(
291
+ own_file="plan.md",
292
+ prior_files=["research.md", "specification.md"],
293
+ ),
294
+ AgentType.TASKS: PipelineConfigEntry(
295
+ own_file="tasks.md",
296
+ prior_files=["research.md", "specification.md", "plan.md"],
297
+ ),
298
+ AgentType.EXPORT: PipelineConfigEntry(
299
+ own_file=None, # Export uses directory
300
+ prior_files=["research.md", "specification.md", "plan.md", "tasks.md"],
301
+ ),
302
+ }
303
+
304
+ # Get configuration for current agent
305
+ if agent_mode not in pipeline_config:
306
+ return None
307
+
308
+ config = pipeline_config[agent_mode]
309
+ base_path = get_shotgun_base_path()
310
+ toc_sections: list[str] = []
311
+
312
+ # Extract TOCs from prior files (high-level only)
313
+ for prior_file in config.prior_files:
314
+ file_path = base_path / prior_file
315
+ # Only show # and ## headings from prior files, max 500 chars each
316
+ prior_toc = _extract_file_toc_content(file_path, max_depth=2, max_chars=500)
317
+ if prior_toc:
318
+ # Add section header
319
+ file_label = prior_file.replace(".md", "").replace("_", " ").title()
320
+ toc_sections.append(
321
+ f"=== Prior Context: {file_label} (summary) ===\n{prior_toc}"
322
+ )
323
+
324
+ # Extract TOC from own file (full detail)
325
+ if config.own_file:
326
+ own_path = base_path / config.own_file
327
+ own_toc = _extract_file_toc_content(own_path, max_depth=None, max_chars=2000)
328
+ if own_toc:
329
+ file_label = config.own_file.replace(".md", "").replace("_", " ").title()
330
+ # Put own file TOC at the beginning
331
+ toc_sections.insert(
332
+ 0, f"=== Your Current Document: {file_label} ===\n{own_toc}"
333
+ )
334
+
335
+ # Combine all sections
336
+ if not toc_sections:
337
+ return None
338
+
339
+ combined_toc = "\n\n".join(toc_sections)
340
+
341
+ # Final truncation if needed (should rarely happen with our limits)
342
+ max_total = 3500 # Conservative total limit
343
+ if len(combined_toc) > max_total:
344
+ combined_toc = combined_toc[: max_total - 3] + "..."
345
+
346
+ return combined_toc
347
+
348
+
264
349
  def get_agent_existing_files(agent_mode: AgentType | None = None) -> list[str]:
265
350
  """Get list of existing files for the given agent mode.
266
351
 
@@ -1,7 +1,7 @@
1
1
  """Models and utilities for persisting TUI conversation history."""
2
2
 
3
3
  from datetime import datetime
4
- from typing import Any
4
+ from typing import Any, cast
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict, Field
7
7
  from pydantic_ai.messages import (
@@ -10,11 +10,16 @@ from pydantic_ai.messages import (
10
10
  )
11
11
  from pydantic_core import to_jsonable_python
12
12
 
13
+ from shotgun.tui.screens.chat_screen.hint_message import HintMessage
14
+
15
+ SerializedMessage = dict[str, Any]
16
+
13
17
 
14
18
  class ConversationState(BaseModel):
15
19
  """Represents the complete state of a conversation in memory."""
16
20
 
17
21
  agent_messages: list[ModelMessage]
22
+ ui_messages: list[ModelMessage | HintMessage] = Field(default_factory=list)
18
23
  agent_type: str # Will store AgentType.value
19
24
 
20
25
  model_config = ConfigDict(arbitrary_types_allowed=True)
@@ -24,9 +29,12 @@ class ConversationHistory(BaseModel):
24
29
  """Persistent conversation history for TUI sessions."""
25
30
 
26
31
  version: int = 1
27
- agent_history: list[dict[str, Any]] = Field(
32
+ agent_history: list[SerializedMessage] = Field(
33
+ default_factory=list
34
+ ) # Stores serialized ModelMessage objects
35
+ ui_history: list[SerializedMessage] = Field(
28
36
  default_factory=list
29
- ) # Will store serialized ModelMessage objects
37
+ ) # Stores serialized ModelMessage and HintMessage objects
30
38
  last_agent_model: str = "research"
31
39
  updated_at: datetime = Field(default_factory=datetime.now)
32
40
 
@@ -43,6 +51,25 @@ class ConversationHistory(BaseModel):
43
51
  messages, fallback=lambda x: str(x), exclude_none=True
44
52
  )
45
53
 
54
+ def set_ui_messages(self, messages: list[ModelMessage | HintMessage]) -> None:
55
+ """Set ui_history from a list of UI messages."""
56
+
57
+ def _serialize_message(
58
+ message: ModelMessage | HintMessage,
59
+ ) -> Any:
60
+ if isinstance(message, HintMessage):
61
+ data = message.model_dump()
62
+ data["message_type"] = "hint"
63
+ return data
64
+ payload = to_jsonable_python(
65
+ message, fallback=lambda x: str(x), exclude_none=True
66
+ )
67
+ if isinstance(payload, dict):
68
+ payload.setdefault("message_type", "model")
69
+ return payload
70
+
71
+ self.ui_history = [_serialize_message(msg) for msg in messages]
72
+
46
73
  def get_agent_messages(self) -> list[ModelMessage]:
47
74
  """Get agent_history as a list of ModelMessage objects.
48
75
 
@@ -54,3 +81,26 @@ class ConversationHistory(BaseModel):
54
81
 
55
82
  # Deserialize from JSON format back to ModelMessage objects
56
83
  return ModelMessagesTypeAdapter.validate_python(self.agent_history)
84
+
85
+ def get_ui_messages(self) -> list[ModelMessage | HintMessage]:
86
+ """Get ui_history as a list of Model or hint messages."""
87
+
88
+ if not self.ui_history:
89
+ # Fallback for older conversation files without UI history
90
+ return cast(list[ModelMessage | HintMessage], self.get_agent_messages())
91
+
92
+ messages: list[ModelMessage | HintMessage] = []
93
+ for item in self.ui_history:
94
+ message_type = item.get("message_type") if isinstance(item, dict) else None
95
+ if message_type == "hint":
96
+ messages.append(HintMessage.model_validate(item))
97
+ continue
98
+
99
+ # Backwards compatibility: data may not include the type marker
100
+ payload = item
101
+ if isinstance(payload, dict):
102
+ payload = {k: v for k, v in payload.items() if k != "message_type"}
103
+ deserialized = ModelMessagesTypeAdapter.validate_python([payload])
104
+ messages.append(deserialized[0])
105
+
106
+ return messages
shotgun/agents/models.py CHANGED
@@ -27,6 +27,23 @@ class AgentType(StrEnum):
27
27
  EXPORT = "export"
28
28
 
29
29
 
30
+ class PipelineConfigEntry(BaseModel):
31
+ """Configuration for each agent in the pipeline.
32
+
33
+ This model defines what files an agent can write to and what
34
+ files from prior agents it should read for context.
35
+ """
36
+
37
+ own_file: str | None = Field(
38
+ default=None,
39
+ description="The file this agent writes to (None for export agent)",
40
+ )
41
+ prior_files: list[str] = Field(
42
+ default_factory=list,
43
+ description="Files from prior agents in pipeline to read for context",
44
+ )
45
+
46
+
30
47
  class UserAnswer(BaseModel):
31
48
  """A answer from the user."""
32
49
 
@@ -26,14 +26,31 @@ Your job is to help export project documentation and findings to various formats
26
26
 
27
27
  ## EXPORT WORKFLOW
28
28
 
29
- For export tasks:
30
- 1. **Check existing files**: Read `research.md`, `plan.md`, `tasks.md`, and `specification.md` to see what content is available
31
- 2. **Understand the export requirements**: Understand what the user wants to export, assuming that's everything - but always confirm. Priority: Tasks, Plan, Specify, Research.
32
- 3. **Analyze export requirements**: Understand the requested format, destination, and scope
33
- 4. **Read source content**: Read the content of all the relevant files
34
- 5. **Transform and format**: Convert content to the requested format
35
- 6. **Create export files**: Use write_file with path like "exports/filename.ext" to save in exports folder
36
- 7. **Validate output**: Ensure the export meets requirements and is properly formatted using read_file()
29
+ For AGENTS.md exports:
30
+ 1. **MANDATORY: Read ALL pipeline files**:
31
+ - `tasks.md` - Extract actionable tasks with inputs/outputs
32
+ - `specification.md` - Get primary objective and constraints
33
+ - `plan.md` - Convert stages to success criteria
34
+ - `research.md` - Extract codebase context and open questions
35
+ 2. **Map content to template sections**:
36
+ - Primary Objective: From specification.md's main goal
37
+ - Tasks: From tasks.md, formatted as action items
38
+ - Research Needed: Unresolved questions from research.md
39
+ - Codebase Context: Technical findings from research.md
40
+ - Success Criteria: Plan.md stages as measurable outcomes
41
+ - Important Notes: Critical constraints from all files
42
+ - References: Documentation links from research.md
43
+ 3. **Transform content**: Convert to action-oriented language for AI agents
44
+ 4. **Create export**: Save as `exports/AGENTS.md` or `exports/AGENTS_[timestamp].md`
45
+ 5. **Validate**: Ensure every section has actionable content
46
+
47
+ For other export tasks:
48
+ 1. **Check existing files**: Read relevant source files
49
+ 2. **Understand requirements**: Determine format and scope
50
+ 3. **Read source content**: Load all necessary information
51
+ 4. **Transform and format**: Convert to requested format
52
+ 5. **Create export files**: Save in exports/ folder
53
+ 6. **Validate output**: Verify proper formatting
37
54
 
38
55
  ## SUPPORTED EXPORT FORMATS
39
56
 
@@ -41,18 +58,109 @@ For export tasks:
41
58
  - **Markdown (.md)**: Nicely formatted Markdown file with everything the user wants to export
42
59
  - **Multiple files**: Can create multiple export files in the exports/ folder as needed
43
60
 
44
- ### AGENTS.md
45
-
46
- Your task: generate an **AGENTS.md** file (in Markdown) for a project based on the provided documentation, specification files, and any context I supply.
47
-
48
- **Instructions / constraints**:
49
- - Use clear headings (e.g. "Architecture & Structure", "Setup / Prerequisites", "Build & Test", "Coding Conventions", etc.).
50
- - For sections with commands, wrap them in backticks so they can be executed directly.
51
- - Provide enough detail so that an AI coding agent can understand how to build, test, validate, deploy, and work with the project, without needing to hunt in scattered docs.
52
- - Link or refer to deeper docs (README, design docs) rather than duplicating large content.
53
- - If the project is a monorepo or modular, mention whether nested AGENTS.md may override parts.
54
- - Do **not** include large prose — focus on actionable instructions and bullet lists.
55
- - Assume the agent must obey programmatic checks listed in the file after generating code.
61
+ ### AGENTS.md - Primary Export Format for AI Agents
62
+
63
+ **CRITICAL**: The AGENTS.md file is THE primary deliverable for AI coding agents. It MUST follow this exact template:
64
+
65
+ ```markdown
66
+ # [Project Name] Implementation Guide for AI Agents
67
+
68
+ ## Primary Objective
69
+ [1-2 sentences describing WHAT needs to be built, not HOW]
70
+
71
+ ## Tasks
72
+
73
+ ### Task 1: [Action-oriented title]
74
+ **Input**: [What files/data this task needs]
75
+ **Output**: [What files/code this task produces]
76
+ **Constraints**: [Security, performance, or architectural requirements]
77
+
78
+ ### Task 2: [Next action]
79
+ [Continue pattern...]
80
+
81
+ ## Research Needed
82
+ - [ ] [Specific technical question to investigate]
83
+ - [ ] [API endpoint to understand]
84
+ - [ ] [Integration pattern to review]
85
+
86
+ ## Codebase Context
87
+ - **Language**: [Primary language and version]
88
+ - **Key Files**: [Critical files to read first]
89
+ - **Patterns**: [Design patterns used in codebase]
90
+ - **Dependencies**: [Important libraries/frameworks]
91
+
92
+ ## Success Criteria
93
+ - [ ] [Measurable outcome 1]
94
+ - [ ] [Measurable outcome 2]
95
+ - [ ] [Tests pass / Coverage meets X%]
96
+
97
+ ## Important Notes
98
+ - [Critical constraint or requirement]
99
+ - [Security consideration]
100
+ - [Performance requirement]
101
+
102
+ ## References
103
+ - [Link to API documentation]
104
+ - [Link to architecture diagrams]
105
+ - [Link to test requirements]
106
+ ```
107
+
108
+ **Export Requirements**:
109
+ - Extract Primary Objective from specification.md
110
+ - Map tasks from tasks.md into action-oriented Task sections
111
+ - Pull research questions from research.md that are still relevant
112
+ - Include codebase context from research findings
113
+ - Convert plan stages into Success Criteria
114
+ - Add implementation constraints from specifications
115
+ - Format ALL content for immediate AI agent execution
116
+ - NO educational content, NO "learn X" instructions
117
+ - Every section must be actionable by Claude Code
118
+
119
+ **Example of GOOD AGENTS.md Content**:
120
+ ```markdown
121
+ # E-commerce API Implementation Guide for AI Agents
122
+
123
+ ## Primary Objective
124
+ Build a REST API for product catalog management with authentication, supporting CRUD operations and search functionality.
125
+
126
+ ## Tasks
127
+
128
+ ### Task 1: Implement Database Models
129
+ **Input**: requirements.md, existing database schema
130
+ **Output**: models/product.py, models/user.py, migrations/
131
+ **Constraints**: Use SQLAlchemy ORM, maintain backward compatibility
132
+
133
+ ### Task 2: Create Authentication Endpoints
134
+ **Input**: models/user.py, auth requirements
135
+ **Output**: api/auth.py, middleware/auth.py
136
+ **Constraints**: JWT tokens, 15-minute expiry, refresh token support
137
+
138
+ ## Research Needed
139
+ - [ ] Check if existing auth middleware supports JWT refresh tokens
140
+ - [ ] Verify PostgreSQL full-text search capabilities for product search
141
+ - [ ] Review rate limiting implementation in current middleware
142
+
143
+ ## Codebase Context
144
+ - **Language**: Python 3.11
145
+ - **Key Files**: src/api/__init__.py, src/models/base.py
146
+ - **Patterns**: Repository pattern, dependency injection
147
+ - **Dependencies**: FastAPI, SQLAlchemy, Pydantic
148
+
149
+ ## Success Criteria
150
+ - [ ] All CRUD endpoints return correct status codes
151
+ - [ ] Authentication enforced on protected routes
152
+ - [ ] Test coverage exceeds 80%
153
+ - [ ] API response times under 200ms
154
+
155
+ ## Important Notes
156
+ - Database migrations must be reversible
157
+ - All endpoints require input validation
158
+ - Search must support pagination
159
+
160
+ ## References
161
+ - FastAPI docs: https://fastapi.tiangolo.com
162
+ - Project API spec: docs/openapi.yaml
163
+ ```
56
164
 
57
165
 
58
166
  ## EXPORT PRINCIPLES
@@ -7,7 +7,7 @@ Your extensive expertise spans, among other things:
7
7
  ## KEY RULES
8
8
 
9
9
  {% if interactive_mode %}
10
- 0. Always ask for review and go ahead to move forward after writing files.
10
+ 0. Always ask CLARIFYING QUESTIONS if the user's request is ambiguous or lacks sufficient detail. Do not make assumptions about what the user wants.
11
11
  {% endif %}
12
12
  1. Above all, prefer using tools to do the work and NEVER respond with text.
13
13
  2. IMPORTANT: Always ask for review and go ahead to move forward after using write_file().
@@ -2,72 +2,143 @@ You are an experienced Project Manager and Strategic Planner.
2
2
 
3
3
  Your job is to help create comprehensive, actionable plans for software projects and maintain the plan.md file.
4
4
 
5
+ ⚠️ **CRITICAL RULE**: If you use ANY time references (Week, Day, Month, Hour, Quarter, Year), your plan is INVALID and will be rejected. Use ONLY Stage/Step numbering based on technical dependencies.
6
+
5
7
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
8
 
7
9
  ## MEMORY MANAGEMENT PROTOCOL
8
10
 
9
11
  - You have exclusive write access to: `plan.md`
10
- - SHOULD READ `research.md` and `specification.md` for context but CANNOT write to them
12
+ - MUST READ `research.md` and `specification.md` BEFORE asking questions or creating plans
13
+ - Cannot write to research.md or specification.md - they are read-only context
11
14
  - This is your persistent memory store - ALWAYS load it first
12
15
  - Compress content regularly to stay within context limits
13
16
  - Keep your file updated as you work - it's your memory across sessions
14
- - When adding new plans, archive completed phases and compress old plans
17
+ - When adding new plans, archive completed stages and compress old plans
15
18
  - Keep active plan at top, archived/completed plans compressed at bottom
16
19
 
17
20
  ## AI AGENT PIPELINE AWARENESS
18
21
 
19
22
  **CRITICAL**: Your output will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
20
- - These agents already know how to code - don't teach programming concepts
21
- - Create implementation roadmaps, not learning paths
22
- - Each step must reference specific files and functions to create/modify
23
- - Replace "learn X" with "implement Y in file Z"
24
- - Include concrete validation checkpoints (run tests, check endpoints)
25
- - Break down into atomic, executable steps
26
- - Reference specific code patterns from the research
27
- - Every plan step should be a direct instruction an AI agent can execute
23
+
24
+ **NEVER INCLUDE:**
25
+ - Weeks, days, hours, months, quarters, or ANY time measurements
26
+ - Timeline overviews, Gantt charts, or project schedules
27
+ - "Phase 1 (Week 1-2)" or "Day 1-2" style headers
28
+ - Calendar-based planning or duration estimates
29
+ - "8-10 weeks to complete" or similar time predictions
30
+
31
+ **ALWAYS USE:**
32
+ - "Stage 1", "Stage 2" or "Step 1", "Step 2" (NO time references)
33
+ - Prerequisites and technical dependencies
34
+ - High-level components and architecture
35
+ - Success criteria without implementation details
36
+ - Purpose-driven descriptions (WHY each stage exists)
37
+
38
+ **REMEMBER:**
39
+ - Plans should be HIGH-LEVEL architecture and approach
40
+ - Leave specific file paths and function names to the task agent
41
+ - Focus on WHAT to build, not HOW to code it
42
+ - AI agents execute immediately based on dependencies, not schedules
28
43
 
29
44
  ## PLANNING WORKFLOW
30
45
 
31
46
  For PLANNING tasks:
32
47
  1. **Load existing plan**: ALWAYS first use `read_file("plan.md")` to see what plans already exist (if the file exists)
33
- 2. **Check related files**: Read `specification.md` and `research.md` if they exist to understand context
34
- 3. **Analyze requirements**: Understand project goals and constraints from available documentation
35
- 4. **Define specifications**: Create detailed technical and functional plans
36
- 5. **Structure documentation**: Use `write_file("plan.md", content)` to save the comprehensive plan
48
+ 2. **MANDATORY: Load context files**: You MUST read `specification.md` and `research.md` (if they exist) BEFORE doing anything else, including asking questions
49
+ 3. **Analyze requirements**: Understand project goals and constraints from the loaded documentation
50
+ 4. **Define specifications**: Create detailed technical and functional plans based on the context
51
+ 5. **REQUIRED: Write the plan**: You MUST use `write_file("plan.md", content)` to save the plan. NOT writing the plan means FAILURE.
52
+
53
+ **CRITICAL RULES**:
54
+ - You CANNOT ask questions until you have first attempted to read both `research.md` and `specification.md`
55
+ - You MUST write your plan to `plan.md` - not writing the file means you have failed your task
56
+ - ANY time reference (week, day, month) makes the plan INVALID
57
+
58
+ ## PLAN FORMAT EXAMPLE
59
+
60
+ **CORRECT high-level plan format:**
61
+
62
+ ```markdown
63
+ # API Implementation Plan
64
+
65
+ ## Stage 1: Database Layer
66
+ ### Purpose: Establish data persistence
67
+ ### Prerequisites: None
68
+ ### Key Components:
69
+ - User and session models
70
+ - Database schema and migrations
71
+ ### Success Criteria:
72
+ - Data models support all required operations
73
+ - Database can be reliably initialized
74
+
75
+ ## Stage 2: Business Logic
76
+ ### Purpose: Implement core functionality
77
+ ### Prerequisites: Database layer complete
78
+ ### Key Components:
79
+ - Authentication service
80
+ - Validation rules
81
+ - Business logic layer
82
+ ### Success Criteria:
83
+ - All business rules enforced
84
+ - Services handle edge cases properly
85
+ ```
86
+
87
+ **NEVER write plans like this:**
88
+ - "Week 1-2: Setup database"
89
+ - "Phase 1 (5 days): Foundation"
90
+ - "Timeline: 8-10 weeks"
91
+ - "Day 1: Initialize project"
37
92
 
38
93
  ## PLANNING PRINCIPLES
39
94
 
40
95
  - Build on existing research and previous plans
41
- - Create SMART goals (Specific, Measurable, Achievable, Relevant, Time-bound)
42
- - Break down complex objectives into manageable phases
43
- - Consider dependencies between tasks and potential risks
44
- - Include resource requirements and success criteria
45
- - Focus on actionable, specific steps rather than vague suggestions
46
- - Consider feasibility and prioritize high-impact actions
96
+ - Create clear goals that are Specific, Measurable, Achievable, and Relevant
97
+ - Break down complex objectives into sequential implementation stages
98
+ - Consider dependencies between components and potential risks
99
+ - Include technical requirements and success criteria
100
+ - Focus on high-level architecture rather than implementation details
101
+ - Consider feasibility and prioritize high-impact components
47
102
  - Keep plan.md as the single source of truth
48
- - Organize plans by phases, milestones, or components
103
+ - Organize plans by implementation order, dependencies, or components
49
104
 
50
105
  IMPORTANT RULES:
51
106
  - Make at most 1 plan file write per request
52
107
  - Always base plans on available specifications and research when relevant
53
- - Create actionable, specific steps rather than vague suggestions
54
- - Consider feasibility and prioritize high-impact actions
108
+ - **ABSOLUTELY NO TIME REFERENCES** (weeks, days, months, hours, quarters, years)
109
+ - If you write "Week", "Day", "Month" or any time unit, the plan is INVALID
110
+ - Structure ONLY by Stages/Steps with technical dependencies
111
+ - Focus on high-level architecture, not specific file implementations
112
+ - Leave detailed tasks for the task agent to create
55
113
  - Be concise but comprehensive
56
114
 
57
115
  {% if interactive_mode %}
58
116
  USER INTERACTION - REDUCE UNCERTAINTY:
59
117
 
60
- - ALWAYS ask clarifying questions when the goal is vague or ambiguous
61
- - Use ask_user tool frequently to gather specific details about:
62
- - Budget considerations
63
- - Risk tolerance and priorities
64
- - Ask follow-up questions to drill down into specifics
118
+ - FIRST read `research.md` and `specification.md` before asking ANY questions
119
+ - ONLY ask clarifying questions AFTER reading the context files
120
+ - Questions should be about gaps not covered in research/specification
121
+ - Use ask_user tool to gather specific details about:
122
+ - Information not found in the context files
123
+ - Clarifications on ambiguous specifications
124
+ - Priorities when multiple options exist
65
125
  - Better to ask 2-3 targeted questions than create a generic plan
66
126
  - Confirm major changes to existing plans before proceeding
67
127
  {% else %}
68
128
  NON-INTERACTIVE MODE - MAKE REASONABLE ASSUMPTIONS:
69
129
 
70
130
  - Focus on creating a practical, actionable plan
71
- - Include common project phases and considerations
72
- - Assume standard timelines and resource allocations
73
- {% endif %}
131
+ - Include logical implementation steps and considerations
132
+ - Structure by dependencies and execution order, not calendar time
133
+ {% endif %}
134
+
135
+ ## FINAL VALIDATION BEFORE WRITING
136
+
137
+ Before writing to plan.md, verify:
138
+ ✅ NO time references (week, day, month, hour, year, quarter)
139
+ ✅ Uses Stage/Step numbering only
140
+ ✅ Based on technical dependencies, not schedules
141
+ ✅ High-level architecture focus (details for task agent)
142
+ ✅ Follows the example format shown above
143
+
144
+ If your plan contains ANY time reference, DELETE IT and rewrite using Stages.
@@ -21,11 +21,13 @@ No files currently exist in your allowed directories. You can create:
21
21
  {% endif %}
22
22
 
23
23
  {% if markdown_toc %}
24
- ## Document Structure
24
+ ## Document Table of Contents - READ THE ENTIRE FILE TO UNDERSTAND MORE
25
25
 
26
- The current document contains the following sections:
27
26
  ```
28
27
  {{ markdown_toc }}
29
28
  ```
30
- Review these existing sections before adding new content to avoid duplication.
29
+
30
+ **IMPORTANT**: The above shows ONLY the Table of Contents from prior stages in the pipeline. Review this context before asking questions or creating new content.
31
+ {% else %}
32
+ Review the existing documents above before adding new content to avoid duplication.
31
33
  {% endif %}
@@ -43,6 +43,7 @@ from shotgun.sdk.codebase import CodebaseSDK
43
43
  from shotgun.sdk.exceptions import CodebaseNotFoundError, InvalidPathError
44
44
  from shotgun.sdk.services import get_codebase_service
45
45
  from shotgun.tui.commands import CommandHandler
46
+ from shotgun.tui.screens.chat_screen.hint_message import HintMessage
46
47
  from shotgun.tui.screens.chat_screen.history import ChatHistory
47
48
 
48
49
  from ..components.prompt_input import PromptInput
@@ -322,7 +323,7 @@ class ChatScreen(Screen[None]):
322
323
  value = reactive("")
323
324
  mode = reactive(AgentType.RESEARCH)
324
325
  history: PromptHistory = PromptHistory()
325
- messages = reactive(list[ModelMessage]())
326
+ messages = reactive(list[ModelMessage | HintMessage]())
326
327
  working = reactive(False)
327
328
  question: reactive[UserQuestion | None] = reactive(None)
328
329
  indexing_job: reactive[CodebaseIndexSelection | None] = reactive(None)
@@ -375,7 +376,7 @@ class ChatScreen(Screen[None]):
375
376
  dir.is_dir() and dir.name in ["__pycache__", ".git", ".shotgun"]
376
377
  for dir in cur_dir.iterdir()
377
378
  )
378
- if is_empty:
379
+ if is_empty or self.continue_session:
379
380
  return
380
381
 
381
382
  # Check if the current directory has any accessible codebases
@@ -417,7 +418,7 @@ class ChatScreen(Screen[None]):
417
418
  spinner.set_classes("" if is_working else "hidden")
418
419
  spinner.display = is_working
419
420
 
420
- def watch_messages(self, messages: list[ModelMessage]) -> None:
421
+ def watch_messages(self, messages: list[ModelMessage | HintMessage]) -> None:
421
422
  """Update the chat history when messages change."""
422
423
  if self.is_mounted:
423
424
  chat_history = self.query_one(ChatHistory)
@@ -479,14 +480,8 @@ class ChatScreen(Screen[None]):
479
480
  yield Static("", id="indexing-job-display")
480
481
 
481
482
  def mount_hint(self, markdown: str) -> None:
482
- chat_history = self.query_one(ChatHistory)
483
- if not chat_history.vertical_tail:
484
- return
485
- chat_history.vertical_tail.mount(Markdown(markdown))
486
- # Scroll to bottom after mounting hint
487
- chat_history.vertical_tail.call_after_refresh(
488
- chat_history.vertical_tail.scroll_end, animate=False
489
- )
483
+ hint = HintMessage(message=markdown)
484
+ self.agent_manager.add_hint_message(hint)
490
485
 
491
486
  @on(PartialResponseMessage)
492
487
  def handle_partial_response(self, event: PartialResponseMessage) -> None:
@@ -543,9 +538,7 @@ class ChatScreen(Screen[None]):
543
538
  f"📁 Modified {num_files} files in: `{path_obj.parent}`"
544
539
  )
545
540
 
546
- # Add this as a simple markdown widget
547
- file_info_widget = Markdown(message)
548
- chat_history.vertical_tail.mount(file_info_widget)
541
+ self.mount_hint(message)
549
542
 
550
543
  @on(PromptInput.Submitted)
551
544
  async def handle_submit(self, message: PromptInput.Submitted) -> None:
@@ -730,6 +723,7 @@ class ChatScreen(Screen[None]):
730
723
  last_agent_model=state.agent_type,
731
724
  )
732
725
  conversation.set_agent_messages(state.agent_messages)
726
+ conversation.set_ui_messages(state.ui_messages)
733
727
 
734
728
  # Save to file
735
729
  self.conversation_manager.save(conversation)
@@ -742,10 +736,12 @@ class ChatScreen(Screen[None]):
742
736
 
743
737
  # Restore agent state
744
738
  agent_messages = conversation.get_agent_messages()
739
+ ui_messages = conversation.get_ui_messages()
745
740
 
746
741
  # Create ConversationState for restoration
747
742
  state = ConversationState(
748
743
  agent_messages=agent_messages,
744
+ ui_messages=ui_messages,
749
745
  agent_type=conversation.last_agent_model,
750
746
  )
751
747
 
@@ -0,0 +1,40 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import BaseModel
4
+ from textual.app import ComposeResult
5
+ from textual.widget import Widget
6
+ from textual.widgets import Markdown
7
+
8
+
9
+ class HintMessage(BaseModel):
10
+ message: str
11
+ kind: Literal["hint"] = "hint"
12
+
13
+
14
+ class HintMessageWidget(Widget):
15
+ """A message for the user generated by shotgun, not the agent.."""
16
+
17
+ DEFAULT_CSS = """
18
+ HintMessageWidget {
19
+ background: $secondary-background-darken-1;
20
+ height: auto;
21
+ margin: 1;
22
+ margin-left: 1;
23
+ padding: 1;
24
+
25
+ * > Markdown {
26
+ height: auto;
27
+ offset-x: -1;
28
+ padding: 0;
29
+ margin: 0;
30
+ }
31
+ }
32
+
33
+ """
34
+
35
+ def __init__(self, message: HintMessage) -> None:
36
+ super().__init__()
37
+ self.message = message
38
+
39
+ def compose(self) -> ComposeResult:
40
+ yield Markdown(markdown=f"{self.message.message}")
@@ -19,6 +19,7 @@ from textual.widget import Widget
19
19
  from textual.widgets import Markdown
20
20
 
21
21
  from shotgun.tui.components.vertical_tail import VerticalTail
22
+ from shotgun.tui.screens.chat_screen.hint_message import HintMessage, HintMessageWidget
22
23
 
23
24
 
24
25
  class PartialResponseWidget(Widget): # TODO: doesn't work lol
@@ -75,16 +76,19 @@ class ChatHistory(Widget):
75
76
 
76
77
  def __init__(self) -> None:
77
78
  super().__init__()
78
- self.items: list[ModelMessage] = []
79
+ self.items: list[ModelMessage | HintMessage] = []
79
80
  self.vertical_tail: VerticalTail | None = None
80
81
  self.partial_response = None
81
82
 
82
83
  def compose(self) -> ComposeResult:
83
84
  self.vertical_tail = VerticalTail()
85
+
84
86
  with self.vertical_tail:
85
87
  for item in self.items:
86
88
  if isinstance(item, ModelRequest):
87
89
  yield UserQuestionWidget(item)
90
+ elif isinstance(item, HintMessage):
91
+ yield HintMessageWidget(item)
88
92
  elif isinstance(item, ModelResponse):
89
93
  yield AgentResponseWidget(item)
90
94
  yield PartialResponseWidget(self.partial_response).data_bind(
@@ -94,7 +98,7 @@ class ChatHistory(Widget):
94
98
  def watch_partial_response(self, _partial_response: ModelMessage | None) -> None:
95
99
  self.call_after_refresh(self.autoscroll)
96
100
 
97
- def update_messages(self, messages: list[ModelMessage]) -> None:
101
+ def update_messages(self, messages: list[ModelMessage | HintMessage]) -> None:
98
102
  """Update the displayed messages without recomposing."""
99
103
  if not self.vertical_tail:
100
104
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.1.0.dev25
3
+ Version: 0.1.0.dev26
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,12 +7,12 @@ 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=ApRzriE3mvAms5144rQ4Vjv1JWvRS89DruTtBvgVPdg,20235
11
- shotgun/agents/common.py,sha256=z4MOOHXpGWVpnxfGbOmfz-gYX9r8gjzcPPIOAJ9-2hc,15704
12
- shotgun/agents/conversation_history.py,sha256=vw7LMOCmpkidQGAidPIxPly2sh1k1K-5NF3iYkXOAAU,1815
10
+ shotgun/agents/agent_manager.py,sha256=mIRGf5xaIvMuvUQRzPa3IqP-VlGCwVoxS1ftNgbeFPU,20943
11
+ shotgun/agents/common.py,sha256=C5-hpIgyeQ5n22fIiSouJkdzbiLXAtvVxo176FIyeYM,19034
12
+ shotgun/agents/conversation_history.py,sha256=5J8_1yxdZiiWTq22aDio88DkBDZ4_Lh_p5Iy5_ENszc,3898
13
13
  shotgun/agents/conversation_manager.py,sha256=fxAvXbEl3Cl2ugJ4N9aWXaqZtkrnfj3QzwjWC4LFXwI,3514
14
14
  shotgun/agents/export.py,sha256=Zke952DbJ_lOBUmN-TPHw7qmjbfqsFu1uycBRQI_pkg,2969
15
- shotgun/agents/models.py,sha256=MzQJFHZ7F_q2VEl48LDzuwroi0bvPR74g9qq5Zkqkq4,7339
15
+ shotgun/agents/models.py,sha256=fljmjHoCzNXPWOHSA-1KmQk1epk8ovowqDM7j5zZKB8,7853
16
16
  shotgun/agents/plan.py,sha256=s-WfILBOW4l8kY59RUOVtX5MJSuSzFm1nGp6b17If78,3030
17
17
  shotgun/agents/research.py,sha256=lYG7Rytcitop8mXs3isMI3XvYzzI3JH9u0VZz6K9zfo,3274
18
18
  shotgun/agents/specify.py,sha256=7MoMxfIn34G27mw6wrp_F0i2O5rid476L3kHFONDCd0,3137
@@ -73,16 +73,16 @@ shotgun/codebase/core/parser_loader.py,sha256=LZRrDS8Sp518jIu3tQW-BxdwJ86lnsTteI
73
73
  shotgun/prompts/__init__.py,sha256=RswUm0HMdfm2m2YKUwUsEdRIwoczdbI7zlucoEvHYRo,132
74
74
  shotgun/prompts/loader.py,sha256=jy24-E02pCSmz2651aCT2NgHfRrHAGMYvKrD6gs0Er8,4424
75
75
  shotgun/prompts/agents/__init__.py,sha256=YRIJMbzpArojNX1BP5gfxxois334z_GQga8T-xyWMbY,39
76
- shotgun/prompts/agents/export.j2,sha256=qnb_V4QZycaOKDevb-9ZzAY10pEgBxbdk3kKyIRDex8,5466
77
- shotgun/prompts/agents/plan.j2,sha256=npu7x1p2O2O_ONI0nmkSvG7Kv6OC1dU8_IuqTOV1sHU,3420
76
+ shotgun/prompts/agents/export.j2,sha256=-6lpRmIkSiDqm1G0Va_cf0JG3sJ14cQKQ8beQ0pBh94,8422
77
+ shotgun/prompts/agents/plan.j2,sha256=MyZDyOS21V-zrHNzbIhIdzcESGh_3KVbA4qh9rZR2_E,6086
78
78
  shotgun/prompts/agents/research.j2,sha256=JBtjXaMVDRuNTt7-Ai8gUb2InfolfqCkQoEkn9PsQZk,3929
79
79
  shotgun/prompts/agents/specify.j2,sha256=AP7XrA3KE7GZsCvW4guASxZHBM2mnrMw3irdZ3RUOBs,2808
80
80
  shotgun/prompts/agents/tasks.j2,sha256=Vm6nFSgYzdwRBySUzwMzWHhfYR12Cb_xKPqif7yMuhs,4909
81
81
  shotgun/prompts/agents/partials/codebase_understanding.j2,sha256=7WH-PVd-TRBFQUdOdKkwwn9hAUaJznFZMAGHhO7IGGU,5633
82
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=f5cpo2Ds7EceHvXYUHNs_1NoXv_K4BrWduXYcT2PL40,1803
82
+ shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=eFuc3z1pSJzQtPJfjMIDNHv5XX9lP6YVrmKcbbskJj8,1877
83
83
  shotgun/prompts/agents/partials/content_formatting.j2,sha256=MG0JB7SSp8YV5akDWpbs2f9DcdREIYqLp38NnoWLeQ0,1854
84
84
  shotgun/prompts/agents/partials/interactive_mode.j2,sha256=9sYPbyc46HXg3k1FT_LugIQvOyNDnMQwsMIgOgN-_aY,1100
85
- shotgun/prompts/agents/state/system_state.j2,sha256=k7WICOLFCZ7yhH004AzqCBJ1U0MCF56ODSzdb7fe7Ck,905
85
+ shotgun/prompts/agents/state/system_state.j2,sha256=XYAlf2_5PiIcJqdu-dBG4zyQBfD5h4rmjpI1fEIUW8c,1080
86
86
  shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2,sha256=U-hy-H9bPwV0sYIHTZ5TESxc5EOCtntI8GUZOmJipJw,601
87
87
  shotgun/prompts/codebase/__init__.py,sha256=NYuPMtmYM2ptuwf3YxVuotNlJOUq0hnjmwlzKcJkGK4,42
88
88
  shotgun/prompts/codebase/cypher_query_patterns.j2,sha256=ufTx_xT3VoS76KcVUbIgGQx-bJoJHx3bBE3dagAXv18,8913
@@ -107,22 +107,23 @@ shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4Ugad
107
107
  shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
108
108
  shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
109
109
  shotgun/tui/components/vertical_tail.py,sha256=kkCH0WjAh54jDvRzIaOffRZXUKn_zHFZ_ichfUpgzaE,1071
110
- shotgun/tui/screens/chat.py,sha256=UlyFrd3OISB-M62R3fGBb-E9CoD6G4untbMVfDUSV3U,27820
110
+ shotgun/tui/screens/chat.py,sha256=474e6W6r2QgQZvWwZoFds9Y7YmhjNukR_bXvwutHetM,27690
111
111
  shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
112
112
  shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
113
113
  shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
114
114
  shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw,706
115
115
  shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
116
  shotgun/tui/screens/chat_screen/command_providers.py,sha256=55JIH9T8QnyHRsMoXhOi87FiVM-d6o7OKpCe82uDP9I,7840
117
- shotgun/tui/screens/chat_screen/history.py,sha256=AP8wdXCxQ0uZeZE29WnLF6RCaZjcJzG97tjzqXFceoY,7711
117
+ shotgun/tui/screens/chat_screen/hint_message.py,sha256=WOpbk8q7qt7eOHTyyHvh_IQIaublVDeJGaLpsxEk9FA,933
118
+ shotgun/tui/screens/chat_screen/history.py,sha256=PKUqj3kYk0NqQyQRoM7fTn4lsivfTOlKqm_77cO5RG4,7930
118
119
  shotgun/tui/utils/__init__.py,sha256=cFjDfoXTRBq29wgP7TGRWUu1eFfiIG-LLOzjIGfadgI,150
119
120
  shotgun/tui/utils/mode_progress.py,sha256=lseRRo7kMWLkBzI3cU5vqJmS2ZcCjyRYf9Zwtvc-v58,10931
120
121
  shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
121
122
  shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,1057
122
123
  shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
123
124
  shotgun/utils/update_checker.py,sha256=Xf-7w3Pos3etzCoT771gJe2HLkA8_V2GrqWy7ni9UqA,11373
124
- shotgun_sh-0.1.0.dev25.dist-info/METADATA,sha256=GkDNaK-wokG1FYKaeQOLGZ2vVS0AehWd82rYBpjmbes,11197
125
- shotgun_sh-0.1.0.dev25.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
126
- shotgun_sh-0.1.0.dev25.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
127
- shotgun_sh-0.1.0.dev25.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
128
- shotgun_sh-0.1.0.dev25.dist-info/RECORD,,
125
+ shotgun_sh-0.1.0.dev26.dist-info/METADATA,sha256=YyEZvsV43Hgvv34CVTQU9i_CRlt9DagOoz3oy3c1WXY,11197
126
+ shotgun_sh-0.1.0.dev26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
127
+ shotgun_sh-0.1.0.dev26.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
128
+ shotgun_sh-0.1.0.dev26.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
129
+ shotgun_sh-0.1.0.dev26.dist-info/RECORD,,