shotgun-sh 0.1.12.dev2__py3-none-any.whl → 0.1.12.dev4__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/codebase/core/manager.py +13 -1
- shotgun/codebase/service.py +4 -0
- shotgun/main.py +9 -1
- shotgun/tui/app.py +4 -0
- shotgun/tui/screens/chat.py +12 -4
- shotgun/tui/screens/chat_screen/history.py +84 -12
- {shotgun_sh-0.1.12.dev2.dist-info → shotgun_sh-0.1.12.dev4.dist-info}/METADATA +1 -1
- {shotgun_sh-0.1.12.dev2.dist-info → shotgun_sh-0.1.12.dev4.dist-info}/RECORD +11 -11
- {shotgun_sh-0.1.12.dev2.dist-info → shotgun_sh-0.1.12.dev4.dist-info}/WHEEL +0 -0
- {shotgun_sh-0.1.12.dev2.dist-info → shotgun_sh-0.1.12.dev4.dist-info}/entry_points.txt +0 -0
- {shotgun_sh-0.1.12.dev2.dist-info → shotgun_sh-0.1.12.dev4.dist-info}/licenses/LICENSE +0 -0
shotgun/codebase/core/manager.py
CHANGED
|
@@ -353,7 +353,19 @@ class CodebaseGraphManager:
|
|
|
353
353
|
|
|
354
354
|
# Check if graph already exists
|
|
355
355
|
if graph_path.exists():
|
|
356
|
-
|
|
356
|
+
# Verify it's not corrupted by checking if we can load the Project node
|
|
357
|
+
existing_graph = await self.get_graph(graph_id)
|
|
358
|
+
if existing_graph:
|
|
359
|
+
# Valid existing graph
|
|
360
|
+
raise CodebaseAlreadyIndexedError(repo_path)
|
|
361
|
+
else:
|
|
362
|
+
# Corrupted database - remove and re-index
|
|
363
|
+
logger.warning(
|
|
364
|
+
f"Found corrupted database at {graph_path}, removing for re-indexing..."
|
|
365
|
+
)
|
|
366
|
+
import shutil
|
|
367
|
+
|
|
368
|
+
shutil.rmtree(graph_path)
|
|
357
369
|
|
|
358
370
|
# Import the builder from local core module
|
|
359
371
|
from shotgun.codebase.core import CodebaseIngestor
|
shotgun/codebase/service.py
CHANGED
|
@@ -69,6 +69,10 @@ class CodebaseService:
|
|
|
69
69
|
# Otherwise, check if current directory is in the allowed list
|
|
70
70
|
elif target_path in graph.indexed_from_cwds:
|
|
71
71
|
filtered_graphs.append(graph)
|
|
72
|
+
# Also allow access if current directory IS the repository itself
|
|
73
|
+
# Use Path.resolve() for robust comparison (handles symlinks, etc.)
|
|
74
|
+
elif Path(target_path).resolve() == Path(graph.repo_path).resolve():
|
|
75
|
+
filtered_graphs.append(graph)
|
|
72
76
|
|
|
73
77
|
return filtered_graphs
|
|
74
78
|
|
shotgun/main.py
CHANGED
|
@@ -118,7 +118,15 @@ def main(
|
|
|
118
118
|
|
|
119
119
|
if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
|
|
120
120
|
logger.debug("Launching shotgun TUI application")
|
|
121
|
-
|
|
121
|
+
try:
|
|
122
|
+
tui_app.run(
|
|
123
|
+
no_update_check=no_update_check, continue_session=continue_session
|
|
124
|
+
)
|
|
125
|
+
finally:
|
|
126
|
+
# Ensure PostHog is shut down cleanly even if TUI exits unexpectedly
|
|
127
|
+
from shotgun.posthog_telemetry import shutdown
|
|
128
|
+
|
|
129
|
+
shutdown()
|
|
122
130
|
raise typer.Exit()
|
|
123
131
|
|
|
124
132
|
# For CLI commands, register PostHog shutdown handler
|
shotgun/tui/app.py
CHANGED
|
@@ -83,6 +83,10 @@ class ShotgunApp(App[None]):
|
|
|
83
83
|
|
|
84
84
|
async def action_quit(self) -> None:
|
|
85
85
|
"""Quit the application."""
|
|
86
|
+
# Shut down PostHog client to prevent threading errors
|
|
87
|
+
from shotgun.posthog_telemetry import shutdown
|
|
88
|
+
|
|
89
|
+
shutdown()
|
|
86
90
|
self.exit()
|
|
87
91
|
|
|
88
92
|
def get_system_commands(self, screen: Screen[Any]) -> Iterable[SystemCommand]:
|
shotgun/tui/screens/chat.py
CHANGED
|
@@ -16,6 +16,7 @@ from textual import events, on, work
|
|
|
16
16
|
from textual.app import ComposeResult
|
|
17
17
|
from textual.command import CommandPalette
|
|
18
18
|
from textual.containers import Container, Grid
|
|
19
|
+
from textual.keys import Keys
|
|
19
20
|
from textual.reactive import reactive
|
|
20
21
|
from textual.screen import ModalScreen, Screen
|
|
21
22
|
from textual.widget import Widget
|
|
@@ -285,13 +286,18 @@ class ChatScreen(Screen[None]):
|
|
|
285
286
|
|
|
286
287
|
async def on_key(self, event: events.Key) -> None:
|
|
287
288
|
"""Handle key presses for cancellation."""
|
|
288
|
-
# If escape is pressed while agent is working, cancel the operation
|
|
289
|
-
if
|
|
290
|
-
|
|
289
|
+
# If escape or ctrl+c is pressed while agent is working, cancel the operation
|
|
290
|
+
if (
|
|
291
|
+
event.key in (Keys.Escape, Keys.ControlC)
|
|
292
|
+
and self.working
|
|
293
|
+
and self._current_worker
|
|
294
|
+
):
|
|
295
|
+
# Track cancellation event
|
|
291
296
|
track_event(
|
|
292
|
-
"
|
|
297
|
+
"agent_cancelled",
|
|
293
298
|
{
|
|
294
299
|
"agent_mode": self.mode.value,
|
|
300
|
+
"cancel_key": event.key,
|
|
295
301
|
},
|
|
296
302
|
)
|
|
297
303
|
|
|
@@ -302,6 +308,8 @@ class ChatScreen(Screen[None]):
|
|
|
302
308
|
# Re-enable the input
|
|
303
309
|
prompt_input = self.query_one(PromptInput)
|
|
304
310
|
prompt_input.focus()
|
|
311
|
+
# Prevent the event from propagating (don't quit the app)
|
|
312
|
+
event.stop()
|
|
305
313
|
|
|
306
314
|
@work
|
|
307
315
|
async def check_if_codebase_is_indexed(self) -> None:
|
|
@@ -238,25 +238,97 @@ class AgentResponseWidget(Widget):
|
|
|
238
238
|
continue
|
|
239
239
|
return acc.strip()
|
|
240
240
|
|
|
241
|
+
def _truncate(self, text: str, max_length: int = 100) -> str:
|
|
242
|
+
"""Truncate text to max_length characters, adding ellipsis if needed."""
|
|
243
|
+
if len(text) <= max_length:
|
|
244
|
+
return text
|
|
245
|
+
return text[: max_length - 3] + "..."
|
|
246
|
+
|
|
247
|
+
def _parse_args(self, args: dict[str, object] | str | None) -> dict[str, object]:
|
|
248
|
+
"""Parse tool call arguments, handling both dict and JSON string formats."""
|
|
249
|
+
if args is None:
|
|
250
|
+
return {}
|
|
251
|
+
if isinstance(args, str):
|
|
252
|
+
try:
|
|
253
|
+
return json.loads(args) if args.strip() else {}
|
|
254
|
+
except json.JSONDecodeError:
|
|
255
|
+
return {}
|
|
256
|
+
return args if isinstance(args, dict) else {}
|
|
257
|
+
|
|
241
258
|
def _format_tool_call_part(self, part: ToolCallPart) -> str:
|
|
242
259
|
if part.tool_name == "ask_user":
|
|
243
260
|
return self._format_ask_user_part(part)
|
|
261
|
+
|
|
262
|
+
# Parse args once (handles both JSON string and dict)
|
|
263
|
+
args = self._parse_args(part.args)
|
|
264
|
+
|
|
265
|
+
# Codebase tools - show friendly names
|
|
266
|
+
if part.tool_name == "query_graph":
|
|
267
|
+
if "query" in args:
|
|
268
|
+
query = self._truncate(str(args["query"]))
|
|
269
|
+
return f'Querying code: "{query}"'
|
|
270
|
+
return "Querying code"
|
|
271
|
+
|
|
272
|
+
if part.tool_name == "retrieve_code":
|
|
273
|
+
if "qualified_name" in args:
|
|
274
|
+
return f'Retrieving code: "{args["qualified_name"]}"'
|
|
275
|
+
return "Retrieving code"
|
|
276
|
+
|
|
277
|
+
if part.tool_name == "file_read":
|
|
278
|
+
if "file_path" in args:
|
|
279
|
+
return f'Reading file: "{args["file_path"]}"'
|
|
280
|
+
return "Reading file"
|
|
281
|
+
|
|
282
|
+
if part.tool_name == "directory_lister":
|
|
283
|
+
if "directory" in args:
|
|
284
|
+
return f'Listing directory: "{args["directory"]}"'
|
|
285
|
+
return "Listing directory"
|
|
286
|
+
|
|
287
|
+
if part.tool_name == "codebase_shell":
|
|
288
|
+
command = args.get("command", "")
|
|
289
|
+
cmd_args = args.get("args", [])
|
|
290
|
+
# Handle cmd_args as list of strings
|
|
291
|
+
if isinstance(cmd_args, list):
|
|
292
|
+
args_str = " ".join(str(arg) for arg in cmd_args)
|
|
293
|
+
else:
|
|
294
|
+
args_str = ""
|
|
295
|
+
full_cmd = f"{command} {args_str}".strip()
|
|
296
|
+
if full_cmd:
|
|
297
|
+
return f'Running shell: "{self._truncate(full_cmd)}"'
|
|
298
|
+
return "Running shell"
|
|
299
|
+
|
|
300
|
+
# File management tools
|
|
301
|
+
if part.tool_name == "read_file":
|
|
302
|
+
if "filename" in args:
|
|
303
|
+
return f'Reading file: "{args["filename"]}"'
|
|
304
|
+
return "Reading file"
|
|
305
|
+
|
|
306
|
+
# Web search tools
|
|
307
|
+
if part.tool_name in [
|
|
308
|
+
"openai_web_search_tool",
|
|
309
|
+
"anthropic_web_search_tool",
|
|
310
|
+
"gemini_web_search_tool",
|
|
311
|
+
]:
|
|
312
|
+
if "query" in args:
|
|
313
|
+
query = self._truncate(str(args["query"]))
|
|
314
|
+
return f'Searching web: "{query}"'
|
|
315
|
+
return "Searching web"
|
|
316
|
+
|
|
244
317
|
# write_file
|
|
245
318
|
if part.tool_name == "write_file" or part.tool_name == "append_file":
|
|
246
|
-
if
|
|
247
|
-
return f"{part.tool_name}({
|
|
248
|
-
|
|
249
|
-
|
|
319
|
+
if "filename" in args:
|
|
320
|
+
return f"{part.tool_name}({args['filename']})"
|
|
321
|
+
return f"{part.tool_name}()"
|
|
322
|
+
|
|
250
323
|
if part.tool_name == "write_artifact_section":
|
|
251
|
-
if
|
|
252
|
-
return f"{part.tool_name}({
|
|
253
|
-
|
|
254
|
-
|
|
324
|
+
if "section_title" in args:
|
|
325
|
+
return f"{part.tool_name}({args['section_title']})"
|
|
326
|
+
return f"{part.tool_name}()"
|
|
327
|
+
|
|
255
328
|
if part.tool_name == "create_artifact":
|
|
256
|
-
if
|
|
257
|
-
return f"{part.tool_name}({
|
|
258
|
-
|
|
259
|
-
return f"▪ {part.tool_name}()"
|
|
329
|
+
if "name" in args:
|
|
330
|
+
return f"{part.tool_name}({args['name']})"
|
|
331
|
+
return f"▪ {part.tool_name}()"
|
|
260
332
|
|
|
261
333
|
return f"{part.tool_name}({part.args})"
|
|
262
334
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
shotgun/__init__.py,sha256=P40K0fnIsb7SKcQrFnXZ4aREjpWchVDhvM1HxI4cyIQ,104
|
|
2
2
|
shotgun/build_constants.py,sha256=RXNxMz46HaB5jucgMVpw8a2yCJqjbhTOh0PddyEVMN8,713
|
|
3
3
|
shotgun/logging_config.py,sha256=UKenihvgH8OA3W0b8ZFcItYaFJVe9MlsMYlcevyW1HY,7440
|
|
4
|
-
shotgun/main.py,sha256=
|
|
4
|
+
shotgun/main.py,sha256=Fbg4MNEOR-FPibcbIQ7LwdQIOdYMNYMbMCPPjasbJyA,4834
|
|
5
5
|
shotgun/posthog_telemetry.py,sha256=tu5FLao8uXd76RcKMyWQ9RWPCCJos749XJ_9uT_NNwI,4294
|
|
6
6
|
shotgun/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
shotgun/sentry_telemetry.py,sha256=L7jFMNAnDIENWVeQYSLpyul2nmIm2w3wnOp2kDP_cic,2902
|
|
@@ -62,14 +62,14 @@ shotgun/cli/codebase/commands.py,sha256=zvcM9gjHHO6styhXojb_1bnpq-Cozh2c77ZOIjw4
|
|
|
62
62
|
shotgun/cli/codebase/models.py,sha256=B9vs-d-Bq0aS6FZKebhHT-9tw90Y5f6k_t71VlZpL8k,374
|
|
63
63
|
shotgun/codebase/__init__.py,sha256=QBgFE2Abd5Vl7_NdYOglF9S6d-vIjkb3C0cpIYoHZEU,309
|
|
64
64
|
shotgun/codebase/models.py,sha256=hxjbfDUka8loTApXq9KTvkXKt272fzdjr5u2ImYrNtk,4367
|
|
65
|
-
shotgun/codebase/service.py,sha256=
|
|
65
|
+
shotgun/codebase/service.py,sha256=Ulcj6Y8EzBjFhKaOne_AypTZ2bIbl1jUi1rwmcRJars,7789
|
|
66
66
|
shotgun/codebase/core/__init__.py,sha256=GWWhJEqChiDXAF4omYCgzgoZmJjwsAf6P1aZ5Bl8OE0,1170
|
|
67
67
|
shotgun/codebase/core/change_detector.py,sha256=kWCYLWzRzb3IGGOj71KBn7UOCOKMpINJbOBDf98aMxE,12409
|
|
68
68
|
shotgun/codebase/core/code_retrieval.py,sha256=_JVyyQKHDFm3dxOOua1mw9eIIOHIVz3-I8aZtEsEj1E,7927
|
|
69
69
|
shotgun/codebase/core/cypher_models.py,sha256=Yfysfa9lLguILftkmtuJCN3kLBFIo7WW7NigM-Zr-W4,1735
|
|
70
70
|
shotgun/codebase/core/ingestor.py,sha256=H_kVCqdOKmnQpjcXvUdPFpep8OC2AbOhhE-9HKr_XZM,59836
|
|
71
71
|
shotgun/codebase/core/language_config.py,sha256=vsqHyuFnumRPRBV1lMOxWKNOIiClO6FyfKQR0fGrtl4,8934
|
|
72
|
-
shotgun/codebase/core/manager.py,sha256=
|
|
72
|
+
shotgun/codebase/core/manager.py,sha256=cGxcRAKuw-M4NDP7xRMBG1YzTD6tr9CO09nAReBAuaM,59788
|
|
73
73
|
shotgun/codebase/core/nl_query.py,sha256=kPoSJXBlm5rLhzOofZhqPVMJ_Lj3rV2H6sld6BwtMdg,16115
|
|
74
74
|
shotgun/codebase/core/parser_loader.py,sha256=LZRrDS8Sp518jIu3tQW-BxdwJ86lnsTteI478ER9Td8,4278
|
|
75
75
|
shotgun/prompts/__init__.py,sha256=RswUm0HMdfm2m2YKUwUsEdRIwoczdbI7zlucoEvHYRo,132
|
|
@@ -102,7 +102,7 @@ shotgun/sdk/exceptions.py,sha256=qBcQv0v7ZTwP7CMcxZST4GqCsfOWtOUjSzGBo0-heqo,412
|
|
|
102
102
|
shotgun/sdk/models.py,sha256=X9nOTUHH0cdkQW1NfnMEDu-QgK9oUsEISh1Jtwr5Am4,5496
|
|
103
103
|
shotgun/sdk/services.py,sha256=J4PJFSxCQ6--u7rb3Ta-9eYtlYcxcbnzrMP6ThyCnw4,705
|
|
104
104
|
shotgun/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
105
|
-
shotgun/tui/app.py,sha256=
|
|
105
|
+
shotgun/tui/app.py,sha256=3_g11ZyhJ0avcnX0vundJ9dF2EkkcZnHBBSYzg-P_54,3583
|
|
106
106
|
shotgun/tui/filtered_codebase_service.py,sha256=lJ8gTMhIveTatmvmGLP299msWWTkVYKwvY_2FhuL2s4,1687
|
|
107
107
|
shotgun/tui/styles.tcss,sha256=ETyyw1bpMBOqTi5RLcAJUScdPWTvAWEqE9YcT0kVs_E,121
|
|
108
108
|
shotgun/tui/commands/__init__.py,sha256=8D5lvtpqMW5-fF7Bg3oJtUzU75cKOv6aUaHYYszydU8,2518
|
|
@@ -110,7 +110,7 @@ shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4Ugad
|
|
|
110
110
|
shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
|
|
111
111
|
shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
|
|
112
112
|
shotgun/tui/components/vertical_tail.py,sha256=kROwTaRjUwVB7H35dtmNcUVPQqNYvvfq7K2tXBKEb6c,638
|
|
113
|
-
shotgun/tui/screens/chat.py,sha256=
|
|
113
|
+
shotgun/tui/screens/chat.py,sha256=HYHiHpvek465tOX2YBs_O1en29O524qaDlB3R_8Z9s4,27304
|
|
114
114
|
shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
|
|
115
115
|
shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
|
|
116
116
|
shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
|
|
@@ -118,7 +118,7 @@ shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw
|
|
|
118
118
|
shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
119
|
shotgun/tui/screens/chat_screen/command_providers.py,sha256=55JIH9T8QnyHRsMoXhOi87FiVM-d6o7OKpCe82uDP9I,7840
|
|
120
120
|
shotgun/tui/screens/chat_screen/hint_message.py,sha256=WOpbk8q7qt7eOHTyyHvh_IQIaublVDeJGaLpsxEk9FA,933
|
|
121
|
-
shotgun/tui/screens/chat_screen/history.py,sha256=
|
|
121
|
+
shotgun/tui/screens/chat_screen/history.py,sha256=NVLA3_tERTyB4vkH71w8ef_M5CszfkwbQOuMb100Fzc,12272
|
|
122
122
|
shotgun/tui/utils/__init__.py,sha256=cFjDfoXTRBq29wgP7TGRWUu1eFfiIG-LLOzjIGfadgI,150
|
|
123
123
|
shotgun/tui/utils/mode_progress.py,sha256=lseRRo7kMWLkBzI3cU5vqJmS2ZcCjyRYf9Zwtvc-v58,10931
|
|
124
124
|
shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
|
|
@@ -126,8 +126,8 @@ shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,10
|
|
|
126
126
|
shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
|
|
127
127
|
shotgun/utils/source_detection.py,sha256=Co6Q03R3fT771TF3RzB-70stfjNP2S4F_ArZKibwzm8,454
|
|
128
128
|
shotgun/utils/update_checker.py,sha256=IgzPHRhS1ETH7PnJR_dIx6lxgr1qHpCkMTgzUxvGjhI,7586
|
|
129
|
-
shotgun_sh-0.1.12.
|
|
130
|
-
shotgun_sh-0.1.12.
|
|
131
|
-
shotgun_sh-0.1.12.
|
|
132
|
-
shotgun_sh-0.1.12.
|
|
133
|
-
shotgun_sh-0.1.12.
|
|
129
|
+
shotgun_sh-0.1.12.dev4.dist-info/METADATA,sha256=nbxRumvsLXrH-6l0FrdWsD4wQWEb3Yg9WkV3Kb5Gh7A,11197
|
|
130
|
+
shotgun_sh-0.1.12.dev4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
131
|
+
shotgun_sh-0.1.12.dev4.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
|
|
132
|
+
shotgun_sh-0.1.12.dev4.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
|
|
133
|
+
shotgun_sh-0.1.12.dev4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|