shotgun-sh 0.4.0.dev1__py3-none-any.whl → 0.6.2__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.
- shotgun/agents/agent_manager.py +307 -8
- shotgun/agents/cancellation.py +103 -0
- shotgun/agents/common.py +12 -0
- shotgun/agents/config/README.md +0 -1
- shotgun/agents/config/manager.py +10 -7
- shotgun/agents/config/models.py +5 -27
- shotgun/agents/config/provider.py +44 -27
- shotgun/agents/conversation/history/token_counting/base.py +51 -9
- shotgun/agents/file_read.py +176 -0
- shotgun/agents/messages.py +15 -3
- shotgun/agents/models.py +24 -1
- shotgun/agents/router/models.py +8 -0
- shotgun/agents/router/tools/delegation_tools.py +55 -1
- shotgun/agents/router/tools/plan_tools.py +88 -7
- shotgun/agents/runner.py +17 -2
- shotgun/agents/tools/__init__.py +8 -0
- shotgun/agents/tools/codebase/directory_lister.py +27 -39
- shotgun/agents/tools/codebase/file_read.py +26 -35
- shotgun/agents/tools/codebase/query_graph.py +9 -0
- shotgun/agents/tools/codebase/retrieve_code.py +9 -0
- shotgun/agents/tools/file_management.py +32 -2
- shotgun/agents/tools/file_read_tools/__init__.py +7 -0
- shotgun/agents/tools/file_read_tools/multimodal_file_read.py +167 -0
- shotgun/agents/tools/markdown_tools/__init__.py +62 -0
- shotgun/agents/tools/markdown_tools/insert_section.py +148 -0
- shotgun/agents/tools/markdown_tools/models.py +86 -0
- shotgun/agents/tools/markdown_tools/remove_section.py +114 -0
- shotgun/agents/tools/markdown_tools/replace_section.py +119 -0
- shotgun/agents/tools/markdown_tools/utils.py +453 -0
- shotgun/agents/tools/registry.py +44 -6
- shotgun/agents/tools/web_search/openai.py +42 -23
- shotgun/attachments/__init__.py +41 -0
- shotgun/attachments/errors.py +60 -0
- shotgun/attachments/models.py +107 -0
- shotgun/attachments/parser.py +257 -0
- shotgun/attachments/processor.py +193 -0
- shotgun/build_constants.py +4 -7
- shotgun/cli/clear.py +2 -2
- shotgun/cli/codebase/commands.py +181 -65
- shotgun/cli/compact.py +2 -2
- shotgun/cli/context.py +2 -2
- shotgun/cli/error_handler.py +2 -2
- shotgun/cli/run.py +90 -0
- shotgun/cli/spec/backup.py +2 -1
- shotgun/codebase/__init__.py +2 -0
- shotgun/codebase/benchmarks/__init__.py +35 -0
- shotgun/codebase/benchmarks/benchmark_runner.py +309 -0
- shotgun/codebase/benchmarks/exporters.py +119 -0
- shotgun/codebase/benchmarks/formatters/__init__.py +49 -0
- shotgun/codebase/benchmarks/formatters/base.py +34 -0
- shotgun/codebase/benchmarks/formatters/json_formatter.py +106 -0
- shotgun/codebase/benchmarks/formatters/markdown.py +136 -0
- shotgun/codebase/benchmarks/models.py +129 -0
- shotgun/codebase/core/__init__.py +4 -0
- shotgun/codebase/core/call_resolution.py +91 -0
- shotgun/codebase/core/change_detector.py +11 -6
- shotgun/codebase/core/errors.py +159 -0
- shotgun/codebase/core/extractors/__init__.py +23 -0
- shotgun/codebase/core/extractors/base.py +138 -0
- shotgun/codebase/core/extractors/factory.py +63 -0
- shotgun/codebase/core/extractors/go/__init__.py +7 -0
- shotgun/codebase/core/extractors/go/extractor.py +122 -0
- shotgun/codebase/core/extractors/javascript/__init__.py +7 -0
- shotgun/codebase/core/extractors/javascript/extractor.py +132 -0
- shotgun/codebase/core/extractors/protocol.py +109 -0
- shotgun/codebase/core/extractors/python/__init__.py +7 -0
- shotgun/codebase/core/extractors/python/extractor.py +141 -0
- shotgun/codebase/core/extractors/rust/__init__.py +7 -0
- shotgun/codebase/core/extractors/rust/extractor.py +139 -0
- shotgun/codebase/core/extractors/types.py +15 -0
- shotgun/codebase/core/extractors/typescript/__init__.py +7 -0
- shotgun/codebase/core/extractors/typescript/extractor.py +92 -0
- shotgun/codebase/core/gitignore.py +252 -0
- shotgun/codebase/core/ingestor.py +644 -354
- shotgun/codebase/core/kuzu_compat.py +119 -0
- shotgun/codebase/core/language_config.py +239 -0
- shotgun/codebase/core/manager.py +256 -46
- shotgun/codebase/core/metrics_collector.py +310 -0
- shotgun/codebase/core/metrics_types.py +347 -0
- shotgun/codebase/core/parallel_executor.py +424 -0
- shotgun/codebase/core/work_distributor.py +254 -0
- shotgun/codebase/core/worker.py +768 -0
- shotgun/codebase/indexing_state.py +86 -0
- shotgun/codebase/models.py +94 -0
- shotgun/codebase/service.py +13 -0
- shotgun/exceptions.py +9 -9
- shotgun/main.py +3 -16
- shotgun/posthog_telemetry.py +165 -24
- shotgun/prompts/agents/file_read.j2 +48 -0
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +19 -47
- shotgun/prompts/agents/partials/content_formatting.j2 +12 -33
- shotgun/prompts/agents/partials/interactive_mode.j2 +9 -32
- shotgun/prompts/agents/partials/router_delegation_mode.j2 +21 -22
- shotgun/prompts/agents/plan.j2 +14 -0
- shotgun/prompts/agents/router.j2 +531 -258
- shotgun/prompts/agents/specify.j2 +14 -0
- shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +14 -1
- shotgun/prompts/agents/state/system_state.j2 +13 -11
- shotgun/prompts/agents/tasks.j2 +14 -0
- shotgun/settings.py +49 -10
- shotgun/tui/app.py +149 -18
- shotgun/tui/commands/__init__.py +9 -1
- shotgun/tui/components/attachment_bar.py +87 -0
- shotgun/tui/components/prompt_input.py +25 -28
- shotgun/tui/components/status_bar.py +14 -7
- shotgun/tui/dependencies.py +3 -8
- shotgun/tui/protocols.py +18 -0
- shotgun/tui/screens/chat/chat.tcss +15 -0
- shotgun/tui/screens/chat/chat_screen.py +766 -235
- shotgun/tui/screens/chat/codebase_index_prompt_screen.py +8 -4
- shotgun/tui/screens/chat_screen/attachment_hint.py +40 -0
- shotgun/tui/screens/chat_screen/command_providers.py +0 -10
- shotgun/tui/screens/chat_screen/history/chat_history.py +54 -14
- shotgun/tui/screens/chat_screen/history/formatters.py +22 -0
- shotgun/tui/screens/chat_screen/history/user_question.py +25 -3
- shotgun/tui/screens/database_locked_dialog.py +219 -0
- shotgun/tui/screens/database_timeout_dialog.py +158 -0
- shotgun/tui/screens/kuzu_error_dialog.py +135 -0
- shotgun/tui/screens/model_picker.py +1 -3
- shotgun/tui/screens/models.py +11 -0
- shotgun/tui/state/processing_state.py +19 -0
- shotgun/tui/widgets/widget_coordinator.py +18 -0
- shotgun/utils/file_system_utils.py +4 -1
- {shotgun_sh-0.4.0.dev1.dist-info → shotgun_sh-0.6.2.dist-info}/METADATA +87 -34
- {shotgun_sh-0.4.0.dev1.dist-info → shotgun_sh-0.6.2.dist-info}/RECORD +128 -79
- shotgun/cli/export.py +0 -81
- shotgun/cli/plan.py +0 -73
- shotgun/cli/research.py +0 -93
- shotgun/cli/specify.py +0 -70
- shotgun/cli/tasks.py +0 -78
- shotgun/sentry_telemetry.py +0 -232
- shotgun/tui/screens/onboarding.py +0 -584
- {shotgun_sh-0.4.0.dev1.dist-info → shotgun_sh-0.6.2.dist-info}/WHEEL +0 -0
- {shotgun_sh-0.4.0.dev1.dist-info → shotgun_sh-0.6.2.dist-info}/entry_points.txt +0 -0
- {shotgun_sh-0.4.0.dev1.dist-info → shotgun_sh-0.6.2.dist-info}/licenses/LICENSE +0 -0
shotgun/cli/codebase/commands.py
CHANGED
|
@@ -16,6 +16,8 @@ from rich.progress import (
|
|
|
16
16
|
TimeElapsedColumn,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
from shotgun.codebase.benchmarks import BenchmarkRunner, MetricsExporter, get_formatter
|
|
20
|
+
from shotgun.codebase.benchmarks.formatters import MetricsDisplayOptions
|
|
19
21
|
from shotgun.codebase.models import (
|
|
20
22
|
CodebaseGraph,
|
|
21
23
|
IndexProgress,
|
|
@@ -69,81 +71,195 @@ def index(
|
|
|
69
71
|
format_type: Annotated[
|
|
70
72
|
OutputFormat, typer.Option("--format", "-f", help="Output format")
|
|
71
73
|
] = OutputFormat.TEXT,
|
|
74
|
+
# Benchmark flags
|
|
75
|
+
benchmark: Annotated[
|
|
76
|
+
bool,
|
|
77
|
+
typer.Option("--benchmark", help="Enable benchmark mode with detailed metrics"),
|
|
78
|
+
] = False,
|
|
79
|
+
iterations: Annotated[
|
|
80
|
+
int,
|
|
81
|
+
typer.Option(
|
|
82
|
+
"--benchmark-iterations",
|
|
83
|
+
help="Number of benchmark runs (requires --benchmark)",
|
|
84
|
+
),
|
|
85
|
+
] = 1,
|
|
86
|
+
warmup: Annotated[
|
|
87
|
+
int,
|
|
88
|
+
typer.Option(
|
|
89
|
+
"--benchmark-warmup", help="Number of warmup runs (requires --benchmark)"
|
|
90
|
+
),
|
|
91
|
+
] = 0,
|
|
92
|
+
benchmark_output: Annotated[
|
|
93
|
+
str,
|
|
94
|
+
typer.Option(
|
|
95
|
+
"--benchmark-output",
|
|
96
|
+
help="Benchmark output format: json|markdown",
|
|
97
|
+
),
|
|
98
|
+
] = "json",
|
|
99
|
+
benchmark_export: Annotated[
|
|
100
|
+
str | None,
|
|
101
|
+
typer.Option("--benchmark-export", help="Export metrics to file"),
|
|
102
|
+
] = None,
|
|
103
|
+
show_files: Annotated[
|
|
104
|
+
bool,
|
|
105
|
+
typer.Option("--show-files", help="Show per-file metrics in benchmark output"),
|
|
106
|
+
] = False,
|
|
107
|
+
show_workers: Annotated[
|
|
108
|
+
bool,
|
|
109
|
+
typer.Option(
|
|
110
|
+
"--show-workers", help="Show per-worker metrics in benchmark output"
|
|
111
|
+
),
|
|
112
|
+
] = False,
|
|
113
|
+
top_n: Annotated[
|
|
114
|
+
int | None,
|
|
115
|
+
typer.Option("--top-n", help="Show N slowest files (requires --benchmark)"),
|
|
116
|
+
] = None,
|
|
117
|
+
sequential: Annotated[
|
|
118
|
+
bool,
|
|
119
|
+
typer.Option(
|
|
120
|
+
"--sequential", help="Force sequential mode (disable parallelization)"
|
|
121
|
+
),
|
|
122
|
+
] = False,
|
|
72
123
|
) -> None:
|
|
73
|
-
"""Index a new codebase.
|
|
74
|
-
|
|
124
|
+
"""Index a new codebase.
|
|
125
|
+
|
|
126
|
+
By default, runs with a TUI progress display. Use --benchmark for detailed
|
|
127
|
+
metrics reporting.
|
|
128
|
+
"""
|
|
75
129
|
console = Console()
|
|
76
130
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
131
|
+
# Validate path
|
|
132
|
+
repo_path = Path(path).resolve()
|
|
133
|
+
if not repo_path.exists():
|
|
134
|
+
error_result = ErrorResult(error_message=f"Path does not exist: {repo_path}")
|
|
135
|
+
output_result(error_result, format_type)
|
|
136
|
+
raise typer.Exit(1)
|
|
137
|
+
|
|
138
|
+
# Benchmark mode
|
|
139
|
+
if benchmark:
|
|
140
|
+
try:
|
|
141
|
+
# Create and run benchmark
|
|
142
|
+
runner = BenchmarkRunner(
|
|
143
|
+
codebase_path=repo_path,
|
|
144
|
+
codebase_name=name,
|
|
145
|
+
iterations=iterations,
|
|
146
|
+
warmup_iterations=warmup,
|
|
147
|
+
parallel=not sequential,
|
|
148
|
+
collect_file_metrics=show_files or top_n is not None,
|
|
149
|
+
collect_worker_metrics=show_workers,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
console.print(f"\n[bold blue]Starting benchmark: {name}[/bold blue]")
|
|
153
|
+
console.print(f"Path: {repo_path}")
|
|
154
|
+
console.print(f"Mode: {'Sequential' if sequential else 'Parallel'}")
|
|
155
|
+
console.print(f"Iterations: {iterations} ({warmup} warmup)")
|
|
156
|
+
console.print()
|
|
157
|
+
|
|
158
|
+
results = asyncio.run(runner.run())
|
|
159
|
+
|
|
160
|
+
# Format output
|
|
161
|
+
formatter = get_formatter(benchmark_output)
|
|
162
|
+
options = MetricsDisplayOptions(
|
|
163
|
+
show_phase_metrics=True,
|
|
164
|
+
show_worker_metrics=show_workers,
|
|
165
|
+
show_file_metrics=show_files or top_n is not None,
|
|
166
|
+
top_n_files=top_n,
|
|
113
167
|
)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
168
|
+
output = formatter.format_results(results, options)
|
|
169
|
+
console.print(output)
|
|
170
|
+
|
|
171
|
+
# Export if requested
|
|
172
|
+
if benchmark_export:
|
|
173
|
+
exporter = MetricsExporter()
|
|
174
|
+
exporter.export(results, Path(benchmark_export), options=options)
|
|
175
|
+
console.print(
|
|
176
|
+
f"\n[green]Metrics exported to: {benchmark_export}[/green]"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
except Exception as e:
|
|
180
|
+
error_result = ErrorResult(
|
|
181
|
+
error_message=f"Benchmark error: {e}",
|
|
182
|
+
details=f"Full traceback:\n{traceback.format_exc()}",
|
|
119
183
|
)
|
|
184
|
+
output_result(error_result, format_type)
|
|
185
|
+
raise typer.Exit(1) from e
|
|
186
|
+
|
|
187
|
+
else:
|
|
188
|
+
# Normal mode with TUI progress display
|
|
189
|
+
sdk = CodebaseSDK()
|
|
190
|
+
|
|
191
|
+
# Create progress display
|
|
192
|
+
progress = Progress(
|
|
193
|
+
SpinnerColumn(),
|
|
194
|
+
TextColumn("[bold blue]{task.description}"),
|
|
195
|
+
BarColumn(),
|
|
196
|
+
TaskProgressColumn(),
|
|
197
|
+
TimeElapsedColumn(),
|
|
198
|
+
console=console,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Track tasks by phase
|
|
202
|
+
tasks = {}
|
|
120
203
|
|
|
121
|
-
|
|
122
|
-
|
|
204
|
+
def progress_callback(progress_info: IndexProgress) -> None:
|
|
205
|
+
"""Update progress display based on indexing phase."""
|
|
206
|
+
phase = progress_info.phase
|
|
207
|
+
|
|
208
|
+
# Create task if it doesn't exist
|
|
209
|
+
if phase not in tasks:
|
|
210
|
+
if progress_info.total is not None:
|
|
211
|
+
tasks[phase] = progress.add_task(
|
|
212
|
+
progress_info.phase_name, total=progress_info.total
|
|
213
|
+
)
|
|
214
|
+
else:
|
|
215
|
+
# Indeterminate progress (spinner only)
|
|
216
|
+
tasks[phase] = progress.add_task(
|
|
217
|
+
progress_info.phase_name, total=None
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
task_id = tasks[phase]
|
|
221
|
+
|
|
222
|
+
# Update task
|
|
123
223
|
if progress_info.total is not None:
|
|
124
|
-
progress.update(
|
|
224
|
+
progress.update(
|
|
225
|
+
task_id,
|
|
226
|
+
completed=progress_info.current,
|
|
227
|
+
total=progress_info.total,
|
|
228
|
+
description=f"[bold blue]{progress_info.phase_name}",
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
# Just update description for indeterminate tasks
|
|
232
|
+
progress.update(
|
|
233
|
+
task_id,
|
|
234
|
+
description=f"[bold blue]{progress_info.phase_name} ({progress_info.current} items)",
|
|
235
|
+
)
|
|
125
236
|
|
|
126
|
-
|
|
127
|
-
|
|
237
|
+
# Mark as complete if phase is done
|
|
238
|
+
if progress_info.phase_complete:
|
|
239
|
+
if progress_info.total is not None:
|
|
240
|
+
progress.update(task_id, completed=progress_info.total)
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
# Run indexing with progress display
|
|
244
|
+
with progress:
|
|
245
|
+
result = asyncio.run(
|
|
246
|
+
sdk.index_codebase(
|
|
247
|
+
repo_path, name, progress_callback=progress_callback
|
|
248
|
+
)
|
|
249
|
+
)
|
|
128
250
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
251
|
+
output_result(result, format_type)
|
|
252
|
+
except InvalidPathError as e:
|
|
253
|
+
error_result = ErrorResult(error_message=str(e))
|
|
254
|
+
output_result(error_result, format_type)
|
|
255
|
+
raise typer.Exit(1) from e
|
|
256
|
+
except Exception as e:
|
|
257
|
+
error_result = ErrorResult(
|
|
258
|
+
error_message=f"Error indexing codebase: {e}",
|
|
259
|
+
details=f"Full traceback:\n{traceback.format_exc()}",
|
|
133
260
|
)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
except InvalidPathError as e:
|
|
137
|
-
error_result = ErrorResult(error_message=str(e))
|
|
138
|
-
output_result(error_result, format_type)
|
|
139
|
-
raise typer.Exit(1) from e
|
|
140
|
-
except Exception as e:
|
|
141
|
-
error_result = ErrorResult(
|
|
142
|
-
error_message=f"Error indexing codebase: {e}",
|
|
143
|
-
details=f"Full traceback:\n{traceback.format_exc()}",
|
|
144
|
-
)
|
|
145
|
-
output_result(error_result, format_type)
|
|
146
|
-
raise typer.Exit(1) from e
|
|
261
|
+
output_result(error_result, format_type)
|
|
262
|
+
raise typer.Exit(1) from e
|
|
147
263
|
|
|
148
264
|
|
|
149
265
|
@app.command()
|
shotgun/cli/compact.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import json
|
|
5
|
-
from pathlib import Path
|
|
6
5
|
from typing import Annotated, Any
|
|
7
6
|
|
|
8
7
|
import typer
|
|
@@ -17,6 +16,7 @@ from shotgun.agents.conversation.history.token_estimation import (
|
|
|
17
16
|
)
|
|
18
17
|
from shotgun.cli.models import OutputFormat
|
|
19
18
|
from shotgun.logging_config import get_logger
|
|
19
|
+
from shotgun.utils import get_shotgun_home
|
|
20
20
|
|
|
21
21
|
app = typer.Typer(
|
|
22
22
|
name="compact", help="Compact the conversation history", no_args_is_help=False
|
|
@@ -74,7 +74,7 @@ async def compact_conversation() -> dict[str, Any]:
|
|
|
74
74
|
Dictionary with compaction statistics including before/after metrics
|
|
75
75
|
"""
|
|
76
76
|
# Get conversation file path
|
|
77
|
-
conversation_file =
|
|
77
|
+
conversation_file = get_shotgun_home() / "conversation.json"
|
|
78
78
|
|
|
79
79
|
if not conversation_file.exists():
|
|
80
80
|
raise FileNotFoundError(f"Conversation file not found at {conversation_file}")
|
shotgun/cli/context.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import json
|
|
5
|
-
from pathlib import Path
|
|
6
5
|
from typing import Annotated
|
|
7
6
|
|
|
8
7
|
import httpx
|
|
@@ -19,6 +18,7 @@ from shotgun.agents.conversation import ConversationManager
|
|
|
19
18
|
from shotgun.cli.models import OutputFormat
|
|
20
19
|
from shotgun.llm_proxy import BudgetInfo, LiteLLMProxyClient
|
|
21
20
|
from shotgun.logging_config import get_logger
|
|
21
|
+
from shotgun.utils import get_shotgun_home
|
|
22
22
|
|
|
23
23
|
app = typer.Typer(
|
|
24
24
|
name="context", help="Analyze conversation context usage", no_args_is_help=False
|
|
@@ -74,7 +74,7 @@ async def analyze_context() -> ContextAnalysisOutput:
|
|
|
74
74
|
ContextAnalysisOutput with both markdown and JSON representations of the analysis
|
|
75
75
|
"""
|
|
76
76
|
# Get conversation file path
|
|
77
|
-
conversation_file =
|
|
77
|
+
conversation_file = get_shotgun_home() / "conversation.json"
|
|
78
78
|
|
|
79
79
|
if not conversation_file.exists():
|
|
80
80
|
raise FileNotFoundError(f"Conversation file not found at {conversation_file}")
|
shotgun/cli/error_handler.py
CHANGED
|
@@ -6,12 +6,12 @@ by printing formatted messages to the console.
|
|
|
6
6
|
|
|
7
7
|
from rich.console import Console
|
|
8
8
|
|
|
9
|
-
from shotgun.exceptions import
|
|
9
|
+
from shotgun.exceptions import UserActionableError
|
|
10
10
|
|
|
11
11
|
console = Console(stderr=True)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def print_agent_error(exception:
|
|
14
|
+
def print_agent_error(exception: UserActionableError) -> None:
|
|
15
15
|
"""Print an agent error to the console in yellow.
|
|
16
16
|
|
|
17
17
|
Args:
|
shotgun/cli/run.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Run command for shotgun CLI - executes prompts using the Router agent."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import traceback
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from shotgun.agents.config import ProviderType
|
|
10
|
+
from shotgun.agents.models import AgentRuntimeOptions
|
|
11
|
+
from shotgun.agents.router import (
|
|
12
|
+
RouterMode,
|
|
13
|
+
create_router_agent,
|
|
14
|
+
run_router_agent,
|
|
15
|
+
)
|
|
16
|
+
from shotgun.cli.error_handler import print_agent_error
|
|
17
|
+
from shotgun.exceptions import UserActionableError
|
|
18
|
+
from shotgun.logging_config import get_logger
|
|
19
|
+
from shotgun.posthog_telemetry import track_event
|
|
20
|
+
|
|
21
|
+
app = typer.Typer(
|
|
22
|
+
name="run", help="Run a prompt using the Router agent", no_args_is_help=True
|
|
23
|
+
)
|
|
24
|
+
logger = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.callback(invoke_without_command=True)
|
|
28
|
+
def run(
|
|
29
|
+
prompt: Annotated[str, typer.Argument(help="The prompt to execute")],
|
|
30
|
+
non_interactive: Annotated[
|
|
31
|
+
bool,
|
|
32
|
+
typer.Option(
|
|
33
|
+
"--non-interactive", "-n", help="Disable user interaction (for CI/CD)"
|
|
34
|
+
),
|
|
35
|
+
] = False,
|
|
36
|
+
provider: Annotated[
|
|
37
|
+
ProviderType | None,
|
|
38
|
+
typer.Option("--provider", "-p", help="AI provider to use (overrides default)"),
|
|
39
|
+
] = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
"""Execute a prompt using the Router agent in drafting mode.
|
|
42
|
+
|
|
43
|
+
The Router agent orchestrates sub-agents (Research, Specify, Plan, Tasks, Export)
|
|
44
|
+
based on your prompt. In drafting mode, it auto-executes without confirmation.
|
|
45
|
+
"""
|
|
46
|
+
logger.info("Running prompt: %s", prompt[:100])
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
asyncio.run(async_run(prompt, non_interactive, provider))
|
|
50
|
+
except Exception as e:
|
|
51
|
+
logger.error("Error during execution: %s", str(e))
|
|
52
|
+
logger.debug("Full traceback:\n%s", traceback.format_exc())
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def async_run(
|
|
56
|
+
prompt: str,
|
|
57
|
+
non_interactive: bool,
|
|
58
|
+
provider: ProviderType | None = None,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Async implementation of the run command."""
|
|
61
|
+
track_event(
|
|
62
|
+
"run_command",
|
|
63
|
+
{
|
|
64
|
+
"non_interactive": non_interactive,
|
|
65
|
+
"provider": provider.value if provider else "default",
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Create agent runtime options
|
|
70
|
+
agent_runtime_options = AgentRuntimeOptions(
|
|
71
|
+
interactive_mode=not non_interactive,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Create the router agent
|
|
75
|
+
agent, deps = await create_router_agent(agent_runtime_options, provider)
|
|
76
|
+
|
|
77
|
+
# Set drafting mode for CLI (auto-execute without confirmation)
|
|
78
|
+
deps.router_mode = RouterMode.DRAFTING
|
|
79
|
+
|
|
80
|
+
logger.info("Starting Router agent in drafting mode...")
|
|
81
|
+
try:
|
|
82
|
+
result = await run_router_agent(agent, prompt, deps)
|
|
83
|
+
print("Complete!")
|
|
84
|
+
print("Response:")
|
|
85
|
+
print(result.output)
|
|
86
|
+
except UserActionableError as e:
|
|
87
|
+
print_agent_error(e)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.exception("Unexpected error in run command")
|
|
90
|
+
print(f"An unexpected error occurred: {str(e)}")
|
shotgun/cli/spec/backup.py
CHANGED
|
@@ -6,11 +6,12 @@ from datetime import datetime, timezone
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
8
|
from shotgun.logging_config import get_logger
|
|
9
|
+
from shotgun.utils import get_shotgun_home
|
|
9
10
|
|
|
10
11
|
logger = get_logger(__name__)
|
|
11
12
|
|
|
12
13
|
# Backup directory location
|
|
13
|
-
BACKUP_DIR =
|
|
14
|
+
BACKUP_DIR = get_shotgun_home() / "backups"
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
async def create_backup(shotgun_dir: Path) -> str | None:
|
shotgun/codebase/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Shotgun codebase analysis and graph management."""
|
|
2
2
|
|
|
3
|
+
from shotgun.codebase.indexing_state import IndexingState
|
|
3
4
|
from shotgun.codebase.models import CodebaseGraph, GraphStatus, QueryResult, QueryType
|
|
4
5
|
from shotgun.codebase.service import CodebaseService
|
|
5
6
|
|
|
@@ -7,6 +8,7 @@ __all__ = [
|
|
|
7
8
|
"CodebaseService",
|
|
8
9
|
"CodebaseGraph",
|
|
9
10
|
"GraphStatus",
|
|
11
|
+
"IndexingState",
|
|
10
12
|
"QueryResult",
|
|
11
13
|
"QueryType",
|
|
12
14
|
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Benchmark system for codebase indexing performance analysis.
|
|
2
|
+
|
|
3
|
+
This package provides tools for running benchmarks and reporting metrics
|
|
4
|
+
for the codebase indexing pipeline.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from shotgun.codebase.benchmarks.benchmark_runner import BenchmarkRunner
|
|
8
|
+
from shotgun.codebase.benchmarks.exporters import MetricsExporter
|
|
9
|
+
from shotgun.codebase.benchmarks.formatters import (
|
|
10
|
+
JsonFormatter,
|
|
11
|
+
MarkdownFormatter,
|
|
12
|
+
MetricsDisplayOptions,
|
|
13
|
+
get_formatter,
|
|
14
|
+
)
|
|
15
|
+
from shotgun.codebase.benchmarks.models import (
|
|
16
|
+
BenchmarkConfig,
|
|
17
|
+
BenchmarkMode,
|
|
18
|
+
BenchmarkResults,
|
|
19
|
+
BenchmarkRun,
|
|
20
|
+
OutputFormat,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"BenchmarkConfig",
|
|
25
|
+
"BenchmarkMode",
|
|
26
|
+
"BenchmarkResults",
|
|
27
|
+
"BenchmarkRun",
|
|
28
|
+
"BenchmarkRunner",
|
|
29
|
+
"JsonFormatter",
|
|
30
|
+
"MarkdownFormatter",
|
|
31
|
+
"MetricsDisplayOptions",
|
|
32
|
+
"MetricsExporter",
|
|
33
|
+
"OutputFormat",
|
|
34
|
+
"get_formatter",
|
|
35
|
+
]
|