shotgun-sh 0.1.0.dev19__py3-none-any.whl → 0.1.0.dev22__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.
- shotgun/agents/agent_manager.py +5 -1
- shotgun/agents/common.py +3 -4
- shotgun/agents/models.py +5 -0
- shotgun/agents/tools/codebase/codebase_shell.py +2 -2
- shotgun/agents/tools/codebase/directory_lister.py +1 -1
- shotgun/agents/tools/codebase/file_read.py +1 -1
- shotgun/agents/tools/codebase/query_graph.py +1 -1
- shotgun/agents/tools/codebase/retrieve_code.py +1 -1
- shotgun/prompts/agents/partials/codebase_understanding.j2 +9 -0
- shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +5 -1
- shotgun/sdk/models.py +1 -1
- shotgun/tui/screens/chat.py +38 -25
- shotgun/tui/screens/chat_screen/history.py +0 -1
- shotgun/tui/utils/__init__.py +5 -0
- shotgun/tui/utils/mode_progress.py +224 -0
- {shotgun_sh-0.1.0.dev19.dist-info → shotgun_sh-0.1.0.dev22.dist-info}/METADATA +1 -1
- {shotgun_sh-0.1.0.dev19.dist-info → shotgun_sh-0.1.0.dev22.dist-info}/RECORD +20 -18
- {shotgun_sh-0.1.0.dev19.dist-info → shotgun_sh-0.1.0.dev22.dist-info}/WHEEL +0 -0
- {shotgun_sh-0.1.0.dev19.dist-info → shotgun_sh-0.1.0.dev22.dist-info}/entry_points.txt +0 -0
- {shotgun_sh-0.1.0.dev19.dist-info → shotgun_sh-0.1.0.dev22.dist-info}/licenses/LICENSE +0 -0
shotgun/agents/agent_manager.py
CHANGED
|
@@ -32,7 +32,7 @@ from pydantic_ai.messages import (
|
|
|
32
32
|
from textual.message import Message
|
|
33
33
|
from textual.widget import Widget
|
|
34
34
|
|
|
35
|
-
from shotgun.agents.common import add_system_prompt_message
|
|
35
|
+
from shotgun.agents.common import add_system_prompt_message, add_system_status_message
|
|
36
36
|
|
|
37
37
|
from .export import create_export_agent
|
|
38
38
|
from .history.compaction import apply_persistent_compaction
|
|
@@ -122,6 +122,7 @@ class AgentManager(Widget):
|
|
|
122
122
|
agent_runtime_options = AgentRuntimeOptions(
|
|
123
123
|
interactive_mode=self.deps.interactive_mode,
|
|
124
124
|
working_directory=self.deps.working_directory,
|
|
125
|
+
is_tui_context=self.deps.is_tui_context,
|
|
125
126
|
max_iterations=self.deps.max_iterations,
|
|
126
127
|
queue=self.deps.queue,
|
|
127
128
|
tasks=self.deps.tasks,
|
|
@@ -280,6 +281,9 @@ class AgentManager(Widget):
|
|
|
280
281
|
# Start with persistent message history
|
|
281
282
|
message_history = self.message_history
|
|
282
283
|
|
|
284
|
+
# Add a system status message so the agent knows whats going on
|
|
285
|
+
message_history = await add_system_status_message(deps, message_history)
|
|
286
|
+
|
|
283
287
|
# Check if the message history already has a system prompt
|
|
284
288
|
has_system_prompt = any(
|
|
285
289
|
hasattr(msg, "parts")
|
shotgun/agents/common.py
CHANGED
|
@@ -15,9 +15,7 @@ from pydantic_ai.agent import AgentRunResult
|
|
|
15
15
|
from pydantic_ai.messages import (
|
|
16
16
|
ModelMessage,
|
|
17
17
|
ModelRequest,
|
|
18
|
-
ModelResponse,
|
|
19
18
|
SystemPromptPart,
|
|
20
|
-
TextPart,
|
|
21
19
|
)
|
|
22
20
|
|
|
23
21
|
from shotgun.agents.config import ProviderType, get_config_manager, get_provider_model
|
|
@@ -79,13 +77,14 @@ async def add_system_status_message(
|
|
|
79
77
|
system_state = prompt_loader.render(
|
|
80
78
|
"agents/state/system_state.j2",
|
|
81
79
|
codebase_understanding_graphs=codebase_understanding_graphs,
|
|
80
|
+
is_tui_context=deps.is_tui_context,
|
|
82
81
|
**artifact_state,
|
|
83
82
|
)
|
|
84
83
|
|
|
85
84
|
message_history.append(
|
|
86
|
-
|
|
85
|
+
ModelRequest(
|
|
87
86
|
parts=[
|
|
88
|
-
|
|
87
|
+
SystemPromptPart(content=system_state),
|
|
89
88
|
]
|
|
90
89
|
)
|
|
91
90
|
)
|
shotgun/agents/models.py
CHANGED
|
@@ -60,6 +60,11 @@ class AgentRuntimeOptions(BaseModel):
|
|
|
60
60
|
description="Working directory for agent operations",
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
+
is_tui_context: bool = Field(
|
|
64
|
+
default=False,
|
|
65
|
+
description="Whether the agent is running in TUI context",
|
|
66
|
+
)
|
|
67
|
+
|
|
63
68
|
max_iterations: int = Field(
|
|
64
69
|
default=10,
|
|
65
70
|
ge=1,
|
|
@@ -87,7 +87,7 @@ async def codebase_shell(
|
|
|
87
87
|
success=False,
|
|
88
88
|
command=command,
|
|
89
89
|
args=args,
|
|
90
|
-
error="No codebase
|
|
90
|
+
error="No codebase indexed",
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
# Security validation
|
|
@@ -129,7 +129,7 @@ async def codebase_shell(
|
|
|
129
129
|
success=False,
|
|
130
130
|
command=command,
|
|
131
131
|
args=args,
|
|
132
|
-
error="No
|
|
132
|
+
error="No codebase indexed. Index a codebase first.",
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
# Select the appropriate graph
|
|
@@ -40,6 +40,15 @@ Important:
|
|
|
40
40
|
- Always think about a plan first and communicate this plan back to the user BEFORE calling any codebase management or codebase understanding tools.
|
|
41
41
|
- **GRAPH ID vs NAME**: Every graph has both a NAME (like "Shotgun2") and an ID (like "993ec896213d"). The name is for human reference only. ALL TOOLS REQUIRE THE GRAPH ID, NOT THE NAME!
|
|
42
42
|
|
|
43
|
+
## User Communication Guidelines
|
|
44
|
+
|
|
45
|
+
**CRITICAL**: When communicating with users about codebases:
|
|
46
|
+
- NEVER mention "graph ID" to users - use the codebase name (e.g., "Shotgun2") or path (e.g., "/Users/scott/project")
|
|
47
|
+
- When multiple codebases are available, ask "Which codebase would you like to analyze: Shotgun2 at /path/to/repo?"
|
|
48
|
+
- Internal tools still require graph_id parameters, but don't expose these IDs to users
|
|
49
|
+
- Say "the codebase 'ProjectName'" or "the codebase at /path" instead of "graph xyz123"
|
|
50
|
+
- If asking users to confirm a codebase, show the name and path, not the ID
|
|
51
|
+
|
|
43
52
|
**CRITICAL RULES:**
|
|
44
53
|
0. **ALWAYS USE GRAPH ID**: When calling ANY tool that requires a graph_id parameter, you MUST use the ID (e.g., "993ec896213d"), NOT the name (e.g., "Shotgun2"). The name is only for human reference.
|
|
45
54
|
1. **TOOL-ONLY ANSWERS**: You must ONLY use information from the tools provided. Do not use external knowledge.
|
|
@@ -10,6 +10,10 @@ You have access to the following codebase graphs:
|
|
|
10
10
|
|
|
11
11
|
{% else -%}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
{% if is_tui_context -%}
|
|
14
|
+
No codebase has been indexed yet. To enable code analysis, please tell the user to restart the TUI and follow the prompt to 'Index this codebase?' when it appears.
|
|
15
|
+
{% else -%}
|
|
16
|
+
No codebase has been indexed yet. If the user needs code analysis, ask them to index a codebase first.
|
|
17
|
+
{% endif -%}
|
|
14
18
|
|
|
15
19
|
{% endif %}
|
shotgun/sdk/models.py
CHANGED
|
@@ -15,7 +15,7 @@ class ListResult(BaseModel):
|
|
|
15
15
|
def __str__(self) -> str:
|
|
16
16
|
"""Format list result as plain text table."""
|
|
17
17
|
if not self.graphs:
|
|
18
|
-
return "No codebases found."
|
|
18
|
+
return "No indexed codebases found."
|
|
19
19
|
|
|
20
20
|
lines = [
|
|
21
21
|
f"{'ID':<12} {'Name':<30} {'Status':<10} {'Files':<8} {'Path'}",
|
shotgun/tui/screens/chat.py
CHANGED
|
@@ -42,6 +42,7 @@ from shotgun.tui.screens.chat_screen.history import ChatHistory
|
|
|
42
42
|
|
|
43
43
|
from ..components.prompt_input import PromptInput
|
|
44
44
|
from ..components.spinner import Spinner
|
|
45
|
+
from ..utils.mode_progress import PlaceholderHints
|
|
45
46
|
from .chat_screen.command_providers import (
|
|
46
47
|
AgentModeProvider,
|
|
47
48
|
CodebaseCommandProvider,
|
|
@@ -116,6 +117,7 @@ class ModeIndicator(Widget):
|
|
|
116
117
|
"""
|
|
117
118
|
super().__init__()
|
|
118
119
|
self.mode = mode
|
|
120
|
+
self.progress_checker = PlaceholderHints().progress_checker
|
|
119
121
|
|
|
120
122
|
def render(self) -> str:
|
|
121
123
|
"""Render the mode indicator."""
|
|
@@ -137,7 +139,11 @@ class ModeIndicator(Widget):
|
|
|
137
139
|
mode_title = mode_display.get(self.mode, self.mode.value.title())
|
|
138
140
|
description = mode_description.get(self.mode, "")
|
|
139
141
|
|
|
140
|
-
|
|
142
|
+
# Check if mode has content
|
|
143
|
+
has_content = self.progress_checker.has_mode_content(self.mode)
|
|
144
|
+
status_icon = " ✓" if has_content else ""
|
|
145
|
+
|
|
146
|
+
return f"[bold $text-accent]{mode_title}{status_icon} mode[/][$foreground-muted] ({description})[/]"
|
|
141
147
|
|
|
142
148
|
|
|
143
149
|
class FilteredDirectoryTree(DirectoryTree):
|
|
@@ -174,9 +180,11 @@ class CodebaseIndexPromptScreen(ModalScreen[bool]):
|
|
|
174
180
|
|
|
175
181
|
def compose(self) -> ComposeResult:
|
|
176
182
|
with Container(id="index-prompt-dialog"):
|
|
177
|
-
yield Label("Index
|
|
183
|
+
yield Label("Index this codebase?", id="index-prompt-title")
|
|
178
184
|
yield Static(
|
|
179
|
-
"
|
|
185
|
+
f"Would you like to index the codebase at:\n{Path.cwd()}\n\n"
|
|
186
|
+
"This is required for the agent to understand your code and answer "
|
|
187
|
+
"questions about it. Without indexing, the agent cannot analyze your codebase."
|
|
180
188
|
)
|
|
181
189
|
with Container(id="index-prompt-buttons"):
|
|
182
190
|
yield Button(
|
|
@@ -306,24 +314,6 @@ class ChatScreen(Screen[None]):
|
|
|
306
314
|
|
|
307
315
|
COMMANDS = {AgentModeProvider, ProviderSetupProvider, CodebaseCommandProvider}
|
|
308
316
|
|
|
309
|
-
_PLACEHOLDER_BY_MODE: dict[AgentType, str] = {
|
|
310
|
-
AgentType.RESEARCH: (
|
|
311
|
-
"Ask for investigations, e.g. research strengths and weaknesses of PydanticAI vs its rivals"
|
|
312
|
-
),
|
|
313
|
-
AgentType.PLAN: (
|
|
314
|
-
"Describe a goal to plan, e.g. draft a rollout plan for launching our Slack automation"
|
|
315
|
-
),
|
|
316
|
-
AgentType.TASKS: (
|
|
317
|
-
"Request actionable work, e.g. break down tasks to wire OpenTelemetry into the API"
|
|
318
|
-
),
|
|
319
|
-
AgentType.SPECIFY: (
|
|
320
|
-
"Request detailed specifications, e.g. create a comprehensive spec for user authentication system"
|
|
321
|
-
),
|
|
322
|
-
AgentType.EXPORT: (
|
|
323
|
-
"Request export tasks, e.g. export research findings to Markdown or convert tasks to CSV"
|
|
324
|
-
),
|
|
325
|
-
}
|
|
326
|
-
|
|
327
317
|
value = reactive("")
|
|
328
318
|
mode = reactive(AgentType.RESEARCH)
|
|
329
319
|
history: PromptHistory = PromptHistory()
|
|
@@ -350,6 +340,7 @@ class ChatScreen(Screen[None]):
|
|
|
350
340
|
|
|
351
341
|
self.deps = AgentDeps(
|
|
352
342
|
interactive_mode=True,
|
|
343
|
+
is_tui_context=True,
|
|
353
344
|
llm_model=model_config,
|
|
354
345
|
codebase_service=codebase_service,
|
|
355
346
|
artifact_service=artifact_service,
|
|
@@ -357,6 +348,7 @@ class ChatScreen(Screen[None]):
|
|
|
357
348
|
)
|
|
358
349
|
self.agent_manager = AgentManager(deps=self.deps, initial_type=self.mode)
|
|
359
350
|
self.command_handler = CommandHandler()
|
|
351
|
+
self.placeholder_hints = PlaceholderHints()
|
|
360
352
|
|
|
361
353
|
def on_mount(self) -> None:
|
|
362
354
|
self.query_one(PromptInput).focus(scroll_visible=True)
|
|
@@ -407,7 +399,10 @@ class ChatScreen(Screen[None]):
|
|
|
407
399
|
mode_indicator.refresh()
|
|
408
400
|
|
|
409
401
|
prompt_input = self.query_one(PromptInput)
|
|
410
|
-
|
|
402
|
+
# Force new hint selection when mode changes
|
|
403
|
+
prompt_input.placeholder = self._placeholder_for_mode(
|
|
404
|
+
new_mode, force_new=True
|
|
405
|
+
)
|
|
411
406
|
prompt_input.refresh()
|
|
412
407
|
|
|
413
408
|
def watch_working(self, is_working: bool) -> None:
|
|
@@ -503,6 +498,14 @@ class ChatScreen(Screen[None]):
|
|
|
503
498
|
self._clear_partial_response()
|
|
504
499
|
self.messages = event.messages
|
|
505
500
|
|
|
501
|
+
# Refresh placeholder and mode indicator in case artifacts were created
|
|
502
|
+
prompt_input = self.query_one(PromptInput)
|
|
503
|
+
prompt_input.placeholder = self._placeholder_for_mode(self.mode)
|
|
504
|
+
prompt_input.refresh()
|
|
505
|
+
|
|
506
|
+
mode_indicator = self.query_one(ModeIndicator)
|
|
507
|
+
mode_indicator.refresh()
|
|
508
|
+
|
|
506
509
|
# If there are file operations, add a message showing the modified files
|
|
507
510
|
if event.file_operations:
|
|
508
511
|
chat_history = self.query_one(ChatHistory)
|
|
@@ -577,9 +580,19 @@ class ChatScreen(Screen[None]):
|
|
|
577
580
|
prompt_input = self.query_one(PromptInput)
|
|
578
581
|
prompt_input.clear()
|
|
579
582
|
|
|
580
|
-
def _placeholder_for_mode(self, mode: AgentType) -> str:
|
|
581
|
-
"""Return the placeholder text appropriate for the current mode.
|
|
582
|
-
|
|
583
|
+
def _placeholder_for_mode(self, mode: AgentType, force_new: bool = False) -> str:
|
|
584
|
+
"""Return the placeholder text appropriate for the current mode.
|
|
585
|
+
|
|
586
|
+
Args:
|
|
587
|
+
mode: The current agent mode.
|
|
588
|
+
force_new: If True, force selection of a new random hint.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
Dynamic placeholder hint based on mode and progress.
|
|
592
|
+
"""
|
|
593
|
+
return self.placeholder_hints.get_placeholder_for_mode(
|
|
594
|
+
mode, force_new=force_new
|
|
595
|
+
)
|
|
583
596
|
|
|
584
597
|
def index_codebase_command(self) -> None:
|
|
585
598
|
start_path = Path.cwd()
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""Utility module for checking mode progress in .shotgun directories."""
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from shotgun.agents.agent_manager import AgentType
|
|
7
|
+
from shotgun.artifacts.models import AgentMode
|
|
8
|
+
from shotgun.utils.file_system_utils import get_shotgun_base_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ModeProgressChecker:
|
|
12
|
+
"""Checks progress across different agent modes based on .shotgun directory contents."""
|
|
13
|
+
|
|
14
|
+
# Minimum file size in characters to consider a mode as "started"
|
|
15
|
+
MIN_CONTENT_SIZE = 20
|
|
16
|
+
|
|
17
|
+
def __init__(self, base_path: Path | None = None):
|
|
18
|
+
"""Initialize the progress checker.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
base_path: Base path for .shotgun directory. Defaults to current directory.
|
|
22
|
+
"""
|
|
23
|
+
self.base_path = base_path or get_shotgun_base_path()
|
|
24
|
+
|
|
25
|
+
def has_mode_content(self, mode: AgentType | AgentMode) -> bool:
|
|
26
|
+
"""Check if a mode directory has meaningful content.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
mode: The agent mode to check.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
True if the mode has at least one file with >20 characters.
|
|
33
|
+
"""
|
|
34
|
+
mode_value = mode.value if hasattr(mode, "value") else str(mode)
|
|
35
|
+
mode_path = self.base_path / mode_value
|
|
36
|
+
|
|
37
|
+
if not mode_path.exists() or not mode_path.is_dir():
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
# Check all subdirectories and files
|
|
41
|
+
for item in mode_path.rglob("*"):
|
|
42
|
+
if item.is_file() and not item.name.startswith("."):
|
|
43
|
+
try:
|
|
44
|
+
content = item.read_text(encoding="utf-8")
|
|
45
|
+
# Check if file has meaningful content
|
|
46
|
+
if len(content.strip()) > self.MIN_CONTENT_SIZE:
|
|
47
|
+
return True
|
|
48
|
+
except (OSError, UnicodeDecodeError):
|
|
49
|
+
# Skip files that can't be read
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
def get_next_suggested_mode(self, current_mode: AgentType) -> AgentType | None:
|
|
55
|
+
"""Get the next suggested mode based on current progress.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
current_mode: The current agent mode.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
The next suggested mode, or None if no suggestion.
|
|
62
|
+
"""
|
|
63
|
+
mode_order = [
|
|
64
|
+
AgentType.RESEARCH,
|
|
65
|
+
AgentType.SPECIFY,
|
|
66
|
+
AgentType.TASKS,
|
|
67
|
+
AgentType.EXPORT,
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
current_index = mode_order.index(current_mode)
|
|
72
|
+
except ValueError:
|
|
73
|
+
# Mode not in standard order (e.g., PLAN mode)
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
# Check if current mode has content
|
|
77
|
+
if not self.has_mode_content(current_mode):
|
|
78
|
+
# Current mode is empty, no suggestion for next mode
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
# Get next mode in sequence
|
|
82
|
+
if current_index < len(mode_order) - 1:
|
|
83
|
+
return mode_order[current_index + 1]
|
|
84
|
+
|
|
85
|
+
# Export mode cycles back to Research
|
|
86
|
+
return mode_order[0]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class PlaceholderHints:
|
|
90
|
+
"""Manages dynamic placeholder hints for each mode based on progress."""
|
|
91
|
+
|
|
92
|
+
# Placeholder variations for each mode and state
|
|
93
|
+
HINTS = {
|
|
94
|
+
# Research mode
|
|
95
|
+
AgentType.RESEARCH: {
|
|
96
|
+
False: [
|
|
97
|
+
"Research a product or idea (SHIFT+TAB to cycle modes)",
|
|
98
|
+
"What would you like to explore? Start your research journey here (SHIFT+TAB to switch modes)",
|
|
99
|
+
"Dive into discovery mode - research anything that sparks curiosity (SHIFT+TAB for mode menu)",
|
|
100
|
+
"Ready to investigate? Feed me your burning questions (SHIFT+TAB to explore other modes)",
|
|
101
|
+
" 🔍 The research rabbit hole awaits! What shall we uncover? (SHIFT+TAB for mode carousel)",
|
|
102
|
+
],
|
|
103
|
+
True: [
|
|
104
|
+
"Research complete! SHIFT+TAB to move to Specify mode",
|
|
105
|
+
"Great research! Time to specify (SHIFT+TAB to Specify mode)",
|
|
106
|
+
"Research done! Ready to create specifications (SHIFT+TAB to Specify)",
|
|
107
|
+
"Findings gathered! Move to specifications (SHIFT+TAB for Specify mode)",
|
|
108
|
+
" 🎯 Research complete! Advance to Specify mode (SHIFT+TAB)",
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
# Specify mode
|
|
112
|
+
AgentType.SPECIFY: {
|
|
113
|
+
False: [
|
|
114
|
+
"Create detailed specifications and requirements (SHIFT+TAB to switch modes)",
|
|
115
|
+
"Define your project specifications here (SHIFT+TAB to navigate modes)",
|
|
116
|
+
"Time to get specific - write comprehensive specs (SHIFT+TAB for mode options)",
|
|
117
|
+
"Specification station: Document requirements and designs (SHIFT+TAB to change modes)",
|
|
118
|
+
" 📋 Spec-tacular time! Let's architect your ideas (SHIFT+TAB for mode magic)",
|
|
119
|
+
],
|
|
120
|
+
True: [
|
|
121
|
+
"Specifications complete! SHIFT+TAB to create a Plan",
|
|
122
|
+
"Specs ready! Time to plan (SHIFT+TAB to Plan mode)",
|
|
123
|
+
"Requirements defined! Move to planning (SHIFT+TAB to Plan)",
|
|
124
|
+
"Specifications done! Create your roadmap (SHIFT+TAB for Plan mode)",
|
|
125
|
+
" 🚀 Specs complete! Advance to Plan mode (SHIFT+TAB)",
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
# Tasks mode
|
|
129
|
+
AgentType.TASKS: {
|
|
130
|
+
False: [
|
|
131
|
+
"Create actionable tasks and work items (SHIFT+TAB to switch modes)",
|
|
132
|
+
"Define your task list and action items (SHIFT+TAB to explore modes)",
|
|
133
|
+
"Task creation time - build your work breakdown (SHIFT+TAB for mode selection)",
|
|
134
|
+
"The task forge awaits - create doable chunks of work (SHIFT+TAB to change modes)",
|
|
135
|
+
" ⚡ Task mode activated! Let's define what needs doing (SHIFT+TAB for mode journey)",
|
|
136
|
+
],
|
|
137
|
+
True: [
|
|
138
|
+
"Tasks complete! SHIFT+TAB to Export mode",
|
|
139
|
+
"Task list ready! Time to export (SHIFT+TAB to Export)",
|
|
140
|
+
"Work items defined! Export your artifacts (SHIFT+TAB to Export mode)",
|
|
141
|
+
"Tasks done! Ship them out (SHIFT+TAB for Export mode)",
|
|
142
|
+
" 🎉 Tasks complete! Advance to Export mode (SHIFT+TAB)",
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
# Export mode
|
|
146
|
+
AgentType.EXPORT: {
|
|
147
|
+
False: [
|
|
148
|
+
"Export artifacts to Claude Code, Cursor, or other tools (SHIFT+TAB to switch modes)",
|
|
149
|
+
"Ready to export! Send work to your favorite IDE (SHIFT+TAB to navigate modes)",
|
|
150
|
+
"Export central - Ship artifacts to dev tools (SHIFT+TAB for mode options)",
|
|
151
|
+
"Time to set your work free! Export anywhere (SHIFT+TAB to change modes)",
|
|
152
|
+
" 🚢 Launch pad ready! Blast artifacts to Claude Code & beyond (SHIFT+TAB for mode menu)",
|
|
153
|
+
],
|
|
154
|
+
True: [
|
|
155
|
+
"Exports complete! SHIFT+TAB to start new Research cycle",
|
|
156
|
+
"Artifacts exported! Begin fresh research (SHIFT+TAB to Research mode)",
|
|
157
|
+
"Export done! Start a new journey (SHIFT+TAB for Research)",
|
|
158
|
+
"Work shipped! New research awaits (SHIFT+TAB to Research mode)",
|
|
159
|
+
" 🎊 Export complete! Loop back to Research (SHIFT+TAB)",
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
# Plan mode (special case - not in main flow)
|
|
163
|
+
AgentType.PLAN: {
|
|
164
|
+
False: [
|
|
165
|
+
"Create comprehensive plans with milestones (SHIFT+TAB to switch modes)",
|
|
166
|
+
"Plan your project roadmap and milestones (SHIFT+TAB to explore modes)",
|
|
167
|
+
"Strategic planning mode - design your journey (SHIFT+TAB for mode options)",
|
|
168
|
+
"The planning parlor - where ideas become roadmaps (SHIFT+TAB to navigate)",
|
|
169
|
+
" 📅 Planning paradise! Chart your course to success (SHIFT+TAB for modes)",
|
|
170
|
+
],
|
|
171
|
+
True: [
|
|
172
|
+
"Plan complete! SHIFT+TAB to create Tasks",
|
|
173
|
+
"Roadmap ready! Time for tasks (SHIFT+TAB to Tasks mode)",
|
|
174
|
+
"Planning done! Break it down to tasks (SHIFT+TAB to Tasks)",
|
|
175
|
+
"Strategy set! Move to task creation (SHIFT+TAB for Tasks mode)",
|
|
176
|
+
" 🗺️ Plan complete! Advance to Tasks mode (SHIFT+TAB)",
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
def __init__(self, base_path: Path | None = None):
|
|
182
|
+
"""Initialize the placeholder hints manager.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
base_path: Base path for .shotgun directory.
|
|
186
|
+
"""
|
|
187
|
+
self.progress_checker = ModeProgressChecker(base_path)
|
|
188
|
+
self._last_hints: dict[str, str] = {} # Cache last selected hint per mode
|
|
189
|
+
|
|
190
|
+
def get_placeholder_for_mode(self, mode: AgentType, force_new: bool = False) -> str:
|
|
191
|
+
"""Get a random placeholder hint for the given mode based on progress.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
mode: The current agent mode.
|
|
195
|
+
force_new: If True, always select a new random hint.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
A randomly selected placeholder hint appropriate for the mode and progress.
|
|
199
|
+
"""
|
|
200
|
+
# Determine if mode has content
|
|
201
|
+
has_content = self.progress_checker.has_mode_content(mode)
|
|
202
|
+
|
|
203
|
+
# Get hints for this mode and state
|
|
204
|
+
mode_hints = self.HINTS.get(mode, {})
|
|
205
|
+
state_hints = mode_hints.get(has_content, [])
|
|
206
|
+
|
|
207
|
+
if not state_hints:
|
|
208
|
+
# Fallback if mode not configured
|
|
209
|
+
return (
|
|
210
|
+
f"Type your message for {mode.value} mode (SHIFT+TAB to switch modes)"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Cache key for this mode/state combination
|
|
214
|
+
cache_key = f"{mode.value}_{has_content}"
|
|
215
|
+
|
|
216
|
+
# If not forcing new and we have a cached hint, return it
|
|
217
|
+
if not force_new and cache_key in self._last_hints:
|
|
218
|
+
return self._last_hints[cache_key]
|
|
219
|
+
|
|
220
|
+
# Select a random hint
|
|
221
|
+
hint = random.choice(state_hints) # noqa: S311 - random is fine for UI hints
|
|
222
|
+
self._last_hints[cache_key] = hint
|
|
223
|
+
|
|
224
|
+
return hint
|
|
@@ -7,11 +7,11 @@ 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=
|
|
10
|
+
shotgun/agents/agent_manager.py,sha256=BGnvBOxQQ2sy0XCoE5FmVEZgaNdxl4AwnWg1BHqqfrs,17354
|
|
11
11
|
shotgun/agents/artifact_state.py,sha256=WkspYQe-9CvBS90PapBsX997yvJ5KWH-qtSXIWmfvp0,2121
|
|
12
|
-
shotgun/agents/common.py,sha256=
|
|
12
|
+
shotgun/agents/common.py,sha256=XdJTvPhI4YPcyyBLEn57cwPu7tAHtkL8R75N_M5sYn4,11466
|
|
13
13
|
shotgun/agents/export.py,sha256=wGsGoucbonzPu9DExFrxDY02jr5niTy1xEJrhdCM43M,2904
|
|
14
|
-
shotgun/agents/models.py,sha256=
|
|
14
|
+
shotgun/agents/models.py,sha256=ekrtdug-fafsgr4OmBck9l041NJ-zwl0dneGgf5yeFg,7258
|
|
15
15
|
shotgun/agents/plan.py,sha256=mn0S4r-uXWjerMTzfJLJo7n0pweNp_v8TI53wOxMdZ4,2984
|
|
16
16
|
shotgun/agents/research.py,sha256=tee5gHT0d1Iupr5MI9ogNTh35xqh0j2N71rmb4dUtG0,3224
|
|
17
17
|
shotgun/agents/specify.py,sha256=E9hYxTTVEOkpym-D-q74FI3L_mwllY6QOu8C3U6SEww,3088
|
|
@@ -35,12 +35,12 @@ shotgun/agents/tools/artifact_management.py,sha256=f8WvCCcXb_sMK0U4Y8D1RLUhcj2rh
|
|
|
35
35
|
shotgun/agents/tools/file_management.py,sha256=6ru6DXAl-S6DiCt2HLGTDrK2rJBJpn-t6RkSHzYbxc4,4571
|
|
36
36
|
shotgun/agents/tools/user_interaction.py,sha256=b3ncEpvoD06Cz4hwsS-ppVbQajQj640iWnVfA5WBjAA,1236
|
|
37
37
|
shotgun/agents/tools/codebase/__init__.py,sha256=ceAGkK006NeOYaIJBLQsw7Q46sAyCRK9PYDs8feMQVw,661
|
|
38
|
-
shotgun/agents/tools/codebase/codebase_shell.py,sha256=
|
|
39
|
-
shotgun/agents/tools/codebase/directory_lister.py,sha256=
|
|
40
|
-
shotgun/agents/tools/codebase/file_read.py,sha256=
|
|
38
|
+
shotgun/agents/tools/codebase/codebase_shell.py,sha256=9b7ZStAVFprdGqp1O23ZgwkToMytlUdp_R4MhvmENhc,8584
|
|
39
|
+
shotgun/agents/tools/codebase/directory_lister.py,sha256=eX5GKDSmbKggKDvjPpYMa2WPSGPYQAtUEZ4eN01T0t8,4703
|
|
40
|
+
shotgun/agents/tools/codebase/file_read.py,sha256=EGK5yNqiS4cbIEQfDtdKVoJSJYk20NbZv1AQKNBUKVc,5051
|
|
41
41
|
shotgun/agents/tools/codebase/models.py,sha256=8eR3_8DQiBNgB2twu0aC_evIJbugN9KW3gtxMZdGYCE,10087
|
|
42
|
-
shotgun/agents/tools/codebase/query_graph.py,sha256=
|
|
43
|
-
shotgun/agents/tools/codebase/retrieve_code.py,sha256=
|
|
42
|
+
shotgun/agents/tools/codebase/query_graph.py,sha256=vOeyN4-OZj-vpTSk3Z9W5TjraZAepJ-Qjk_zzvum3fU,2115
|
|
43
|
+
shotgun/agents/tools/codebase/retrieve_code.py,sha256=2VjiqVKJMd9rPV-mGrL4C-N8fqGjYLW6ZInFGbcTxOM,2878
|
|
44
44
|
shotgun/agents/tools/web_search/__init__.py,sha256=Sj1tVokrCsJiLRWWTq0zrAolMHEGntRIYnqiyFi8L2E,1840
|
|
45
45
|
shotgun/agents/tools/web_search/anthropic.py,sha256=IEcSujX5F7-b-87HZqcCHfp3C_E0WSSlb3Hvjq43KvE,4908
|
|
46
46
|
shotgun/agents/tools/web_search/gemini.py,sha256=hXjWUF-aTX3B9ViaKe5aF2aHXlaoBA5am40cgilinGE,2981
|
|
@@ -93,14 +93,14 @@ shotgun/prompts/agents/research.j2,sha256=cLwPdIvv1MvVaHZYLdBhON-8qk-c3kjrRTF1-7
|
|
|
93
93
|
shotgun/prompts/agents/specify.j2,sha256=1CC2SHsxA1Yma0gSFsq-k3VpwtEohN9nh2qeRMMRPRA,1809
|
|
94
94
|
shotgun/prompts/agents/tasks.j2,sha256=OYW1zsYRJxoQF4yVMqJNgi4SNz3YmcP4sljHmmqAu4Q,3613
|
|
95
95
|
shotgun/prompts/agents/partials/artifact_system.j2,sha256=kaqkMU-t2x3M7z-4HU4KffSFug1WM5VDsin6tCkxjHg,1528
|
|
96
|
-
shotgun/prompts/agents/partials/codebase_understanding.j2,sha256=
|
|
96
|
+
shotgun/prompts/agents/partials/codebase_understanding.j2,sha256=7WH-PVd-TRBFQUdOdKkwwn9hAUaJznFZMAGHhO7IGGU,5633
|
|
97
97
|
shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=FFqN6C9pT64_yo5EZ4rmUNIn4LmHjSzwE_IT9QlHueA,1906
|
|
98
98
|
shotgun/prompts/agents/partials/content_formatting.j2,sha256=MG0JB7SSp8YV5akDWpbs2f9DcdREIYqLp38NnoWLeQ0,1854
|
|
99
99
|
shotgun/prompts/agents/partials/interactive_mode.j2,sha256=9sYPbyc46HXg3k1FT_LugIQvOyNDnMQwsMIgOgN-_aY,1100
|
|
100
100
|
shotgun/prompts/agents/state/artifact_templates_available.j2,sha256=Jb31uOnURfLSG8RKQxHZE8zivans_sG6hKgPbC91pfk,819
|
|
101
101
|
shotgun/prompts/agents/state/existing_artifacts_available.j2,sha256=gb5gKYeOXcJmIkkDS1JOm68AEymLutlxNow5HTtev7I,739
|
|
102
102
|
shotgun/prompts/agents/state/system_state.j2,sha256=NFuBOo7cGy0tQrnDUs3wGO19oytGNHK2K8tgoG4cw1M,274
|
|
103
|
-
shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2,sha256=
|
|
103
|
+
shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2,sha256=U-hy-H9bPwV0sYIHTZ5TESxc5EOCtntI8GUZOmJipJw,601
|
|
104
104
|
shotgun/prompts/codebase/__init__.py,sha256=NYuPMtmYM2ptuwf3YxVuotNlJOUq0hnjmwlzKcJkGK4,42
|
|
105
105
|
shotgun/prompts/codebase/cypher_query_patterns.j2,sha256=ufTx_xT3VoS76KcVUbIgGQx-bJoJHx3bBE3dagAXv18,8913
|
|
106
106
|
shotgun/prompts/codebase/cypher_system.j2,sha256=kV-OJ8gM3vsBo8hW4mLSEHpJW-wV_2tNaPck3HUM52c,1497
|
|
@@ -116,7 +116,7 @@ shotgun/sdk/artifact_models.py,sha256=5txP6KCCqwmGl9eBbJt5yyic9p1FeTk58ox8AZ_u6a
|
|
|
116
116
|
shotgun/sdk/artifacts.py,sha256=YbGPdDFd9ORt1vDWSbbPhGlSZ6MXLS6N0kcucxDDEc4,14818
|
|
117
117
|
shotgun/sdk/codebase.py,sha256=T8QprL7_PKmAFNpo341NjHczJsd1lfptAR2ZQ-oNK3Q,6064
|
|
118
118
|
shotgun/sdk/exceptions.py,sha256=qBcQv0v7ZTwP7CMcxZST4GqCsfOWtOUjSzGBo0-heqo,412
|
|
119
|
-
shotgun/sdk/models.py,sha256=
|
|
119
|
+
shotgun/sdk/models.py,sha256=X9nOTUHH0cdkQW1NfnMEDu-QgK9oUsEISh1Jtwr5Am4,5496
|
|
120
120
|
shotgun/sdk/services.py,sha256=WJi_AANWJZPdWdq9LntP5nlYgLxLlsFyXt28DGYNoJo,1132
|
|
121
121
|
shotgun/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
122
|
shotgun/tui/app.py,sha256=LjqQ4ylwVS7278bB6zZ5Uey6oD2pH9dljWymUVgYyPE,3661
|
|
@@ -126,20 +126,22 @@ shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4Ugad
|
|
|
126
126
|
shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
|
|
127
127
|
shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
|
|
128
128
|
shotgun/tui/components/vertical_tail.py,sha256=kkCH0WjAh54jDvRzIaOffRZXUKn_zHFZ_ichfUpgzaE,1071
|
|
129
|
-
shotgun/tui/screens/chat.py,sha256
|
|
129
|
+
shotgun/tui/screens/chat.py,sha256=-NGIrAT572I0gxErFeV72o2RZSfGqZ5rtTGXrYpvKSQ,25408
|
|
130
130
|
shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
|
|
131
131
|
shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
|
|
132
132
|
shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
|
|
133
133
|
shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw,706
|
|
134
134
|
shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
135
135
|
shotgun/tui/screens/chat_screen/command_providers.py,sha256=O7ZiKb6Id4pbWC2SnQxYBJ09zNklylQrnVTmCkDVC0Q,7847
|
|
136
|
-
shotgun/tui/screens/chat_screen/history.py,sha256=
|
|
136
|
+
shotgun/tui/screens/chat_screen/history.py,sha256=qFgAAhxrJtge8NE1TK_Ii9iHLnouT4YPZlu0jZjp3-o,7409
|
|
137
|
+
shotgun/tui/utils/__init__.py,sha256=cFjDfoXTRBq29wgP7TGRWUu1eFfiIG-LLOzjIGfadgI,150
|
|
138
|
+
shotgun/tui/utils/mode_progress.py,sha256=U1j2-XI87Nj0iFQmUxLyNPy7VUTH9veVHGCFrvvGrFA,9756
|
|
137
139
|
shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
|
|
138
140
|
shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,1057
|
|
139
141
|
shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
|
|
140
142
|
shotgun/utils/update_checker.py,sha256=Xf-7w3Pos3etzCoT771gJe2HLkA8_V2GrqWy7ni9UqA,11373
|
|
141
|
-
shotgun_sh-0.1.0.
|
|
142
|
-
shotgun_sh-0.1.0.
|
|
143
|
-
shotgun_sh-0.1.0.
|
|
144
|
-
shotgun_sh-0.1.0.
|
|
145
|
-
shotgun_sh-0.1.0.
|
|
143
|
+
shotgun_sh-0.1.0.dev22.dist-info/METADATA,sha256=6pQPtXbghIK_4T6SA-TmLGxp0lBDObsQrpu7gHe7oS0,11271
|
|
144
|
+
shotgun_sh-0.1.0.dev22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
145
|
+
shotgun_sh-0.1.0.dev22.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
|
|
146
|
+
shotgun_sh-0.1.0.dev22.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
|
|
147
|
+
shotgun_sh-0.1.0.dev22.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|