shotgun-sh 0.1.11.dev1__py3-none-any.whl → 0.1.12.dev1__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/tui/filtered_codebase_service.py +46 -0
- shotgun/tui/screens/chat.py +23 -122
- shotgun/tui/screens/chat_screen/history.py +36 -6
- {shotgun_sh-0.1.11.dev1.dist-info → shotgun_sh-0.1.12.dev1.dist-info}/METADATA +1 -1
- {shotgun_sh-0.1.11.dev1.dist-info → shotgun_sh-0.1.12.dev1.dist-info}/RECORD +8 -7
- {shotgun_sh-0.1.11.dev1.dist-info → shotgun_sh-0.1.12.dev1.dist-info}/WHEEL +0 -0
- {shotgun_sh-0.1.11.dev1.dist-info → shotgun_sh-0.1.12.dev1.dist-info}/entry_points.txt +0 -0
- {shotgun_sh-0.1.11.dev1.dist-info → shotgun_sh-0.1.12.dev1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Filtered codebase service that restricts access to current directory's codebase only."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from shotgun.codebase.models import CodebaseGraph
|
|
6
|
+
from shotgun.codebase.service import CodebaseService
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FilteredCodebaseService(CodebaseService):
|
|
10
|
+
"""CodebaseService subclass that filters graphs to only those accessible from CWD.
|
|
11
|
+
|
|
12
|
+
This ensures TUI agents can only see and access the codebase indexed from the
|
|
13
|
+
current working directory, providing isolation between different project directories.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, storage_dir: Path | str):
|
|
17
|
+
"""Initialize the filtered service.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
storage_dir: Directory to store graph databases
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(storage_dir)
|
|
23
|
+
self._cwd = str(Path.cwd().resolve())
|
|
24
|
+
|
|
25
|
+
async def list_graphs(self) -> list[CodebaseGraph]:
|
|
26
|
+
"""List only graphs accessible from the current working directory.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Filtered list of CodebaseGraph objects accessible from CWD
|
|
30
|
+
"""
|
|
31
|
+
# Use the existing filtering logic from list_graphs_for_directory
|
|
32
|
+
return await super().list_graphs_for_directory(self._cwd)
|
|
33
|
+
|
|
34
|
+
async def list_graphs_for_directory(
|
|
35
|
+
self, directory: Path | str | None = None
|
|
36
|
+
) -> list[CodebaseGraph]:
|
|
37
|
+
"""List graphs for directory - always filters to CWD for TUI context.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
directory: Ignored in TUI context, always uses CWD
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Filtered list of CodebaseGraph objects accessible from CWD
|
|
44
|
+
"""
|
|
45
|
+
# Always use CWD regardless of what directory is passed
|
|
46
|
+
return await super().list_graphs_for_directory(self._cwd)
|
shotgun/tui/screens/chat.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
-
from collections.abc import Iterable
|
|
4
3
|
from dataclasses import dataclass
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from typing import cast
|
|
@@ -20,7 +19,7 @@ from textual.containers import Container, Grid
|
|
|
20
19
|
from textual.reactive import reactive
|
|
21
20
|
from textual.screen import ModalScreen, Screen
|
|
22
21
|
from textual.widget import Widget
|
|
23
|
-
from textual.widgets import Button,
|
|
22
|
+
from textual.widgets import Button, Label, Markdown, Static
|
|
24
23
|
|
|
25
24
|
from shotgun.agents.agent_manager import (
|
|
26
25
|
AgentManager,
|
|
@@ -44,10 +43,11 @@ from shotgun.codebase.core.manager import CodebaseAlreadyIndexedError
|
|
|
44
43
|
from shotgun.posthog_telemetry import track_event
|
|
45
44
|
from shotgun.sdk.codebase import CodebaseSDK
|
|
46
45
|
from shotgun.sdk.exceptions import CodebaseNotFoundError, InvalidPathError
|
|
47
|
-
from shotgun.sdk.services import get_codebase_service
|
|
48
46
|
from shotgun.tui.commands import CommandHandler
|
|
47
|
+
from shotgun.tui.filtered_codebase_service import FilteredCodebaseService
|
|
49
48
|
from shotgun.tui.screens.chat_screen.hint_message import HintMessage
|
|
50
49
|
from shotgun.tui.screens.chat_screen.history import ChatHistory
|
|
50
|
+
from shotgun.utils import get_shotgun_home
|
|
51
51
|
|
|
52
52
|
from ..components.prompt_input import PromptInput
|
|
53
53
|
from ..components.spinner import Spinner
|
|
@@ -167,11 +167,6 @@ class ModeIndicator(Widget):
|
|
|
167
167
|
return f"[bold $text-accent]{mode_title}{status_icon} mode[/][$foreground-muted] ({description})[/]"
|
|
168
168
|
|
|
169
169
|
|
|
170
|
-
class FilteredDirectoryTree(DirectoryTree):
|
|
171
|
-
def filter_paths(self, paths: Iterable[Path]) -> Iterable[Path]:
|
|
172
|
-
return [path for path in paths if path.is_dir()]
|
|
173
|
-
|
|
174
|
-
|
|
175
170
|
class CodebaseIndexPromptScreen(ModalScreen[bool]):
|
|
176
171
|
"""Modal dialog asking whether to index the detected codebase."""
|
|
177
172
|
|
|
@@ -226,105 +221,6 @@ class CodebaseIndexPromptScreen(ModalScreen[bool]):
|
|
|
226
221
|
self.dismiss(True)
|
|
227
222
|
|
|
228
223
|
|
|
229
|
-
class CodebaseIndexScreen(ModalScreen[CodebaseIndexSelection | None]):
|
|
230
|
-
"""Modal dialog for choosing a repository and name to index."""
|
|
231
|
-
|
|
232
|
-
DEFAULT_CSS = """
|
|
233
|
-
CodebaseIndexScreen {
|
|
234
|
-
align: center middle;
|
|
235
|
-
background: rgba(0, 0, 0, 0.0);
|
|
236
|
-
}
|
|
237
|
-
CodebaseIndexScreen > #index-dialog {
|
|
238
|
-
width: 80%;
|
|
239
|
-
max-width: 80;
|
|
240
|
-
height: 80%;
|
|
241
|
-
max-height: 40;
|
|
242
|
-
border: wide $primary;
|
|
243
|
-
padding: 1;
|
|
244
|
-
layout: vertical;
|
|
245
|
-
background: $surface;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
#index-dialog DirectoryTree {
|
|
249
|
-
height: 1fr;
|
|
250
|
-
border: solid $accent;
|
|
251
|
-
overflow: auto;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
#index-dialog-controls {
|
|
255
|
-
layout: horizontal;
|
|
256
|
-
align-horizontal: right;
|
|
257
|
-
padding-top: 1;
|
|
258
|
-
}
|
|
259
|
-
"""
|
|
260
|
-
|
|
261
|
-
def __init__(self, start_path: Path | None = None) -> None:
|
|
262
|
-
super().__init__()
|
|
263
|
-
self.start_path = Path(start_path or Path.cwd())
|
|
264
|
-
self.selected_path: Path | None = self.start_path
|
|
265
|
-
|
|
266
|
-
def compose(self) -> ComposeResult:
|
|
267
|
-
with Container(id="index-dialog"):
|
|
268
|
-
yield Label("Index a codebase", id="index-dialog-title")
|
|
269
|
-
yield FilteredDirectoryTree(self.start_path, id="index-directory-tree")
|
|
270
|
-
yield Input(
|
|
271
|
-
placeholder="Enter a name for the codebase",
|
|
272
|
-
id="index-codebase-name",
|
|
273
|
-
)
|
|
274
|
-
with Container(id="index-dialog-controls"):
|
|
275
|
-
yield Button("Cancel", id="index-cancel")
|
|
276
|
-
yield Button(
|
|
277
|
-
"Index",
|
|
278
|
-
id="index-confirm",
|
|
279
|
-
variant="primary",
|
|
280
|
-
disabled=True,
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
def on_mount(self) -> None:
|
|
284
|
-
name_input = self.query_one("#index-codebase-name", Input)
|
|
285
|
-
if not name_input.value and self.selected_path:
|
|
286
|
-
name_input.value = self.selected_path.name
|
|
287
|
-
self._update_confirm()
|
|
288
|
-
|
|
289
|
-
def _update_confirm(self) -> None:
|
|
290
|
-
confirm = self.query_one("#index-confirm", Button)
|
|
291
|
-
name_input = self.query_one("#index-codebase-name", Input)
|
|
292
|
-
confirm.disabled = not (self.selected_path and name_input.value.strip())
|
|
293
|
-
|
|
294
|
-
@on(DirectoryTree.DirectorySelected, "#index-directory-tree")
|
|
295
|
-
def handle_directory_selected(self, event: DirectoryTree.DirectorySelected) -> None:
|
|
296
|
-
event.stop()
|
|
297
|
-
selected = event.path if event.path.is_dir() else event.path.parent
|
|
298
|
-
self.selected_path = selected
|
|
299
|
-
name_input = self.query_one("#index-codebase-name", Input)
|
|
300
|
-
if not name_input.value:
|
|
301
|
-
name_input.value = selected.name
|
|
302
|
-
self._update_confirm()
|
|
303
|
-
|
|
304
|
-
@on(Input.Changed, "#index-codebase-name")
|
|
305
|
-
def handle_name_changed(self, event: Input.Changed) -> None:
|
|
306
|
-
event.stop()
|
|
307
|
-
self._update_confirm()
|
|
308
|
-
|
|
309
|
-
@on(Button.Pressed, "#index-cancel")
|
|
310
|
-
def handle_cancel(self, event: Button.Pressed) -> None:
|
|
311
|
-
event.stop()
|
|
312
|
-
self.dismiss(None)
|
|
313
|
-
|
|
314
|
-
@on(Button.Pressed, "#index-confirm")
|
|
315
|
-
def handle_confirm(self, event: Button.Pressed) -> None:
|
|
316
|
-
event.stop()
|
|
317
|
-
name_input = self.query_one("#index-codebase-name", Input)
|
|
318
|
-
if not self.selected_path:
|
|
319
|
-
self.dismiss(None)
|
|
320
|
-
return
|
|
321
|
-
selection = CodebaseIndexSelection(
|
|
322
|
-
repo_path=self.selected_path,
|
|
323
|
-
name=name_input.value.strip(),
|
|
324
|
-
)
|
|
325
|
-
self.dismiss(selection)
|
|
326
|
-
|
|
327
|
-
|
|
328
224
|
class ChatScreen(Screen[None]):
|
|
329
225
|
CSS_PATH = "chat.tcss"
|
|
330
226
|
|
|
@@ -349,7 +245,9 @@ class ChatScreen(Screen[None]):
|
|
|
349
245
|
super().__init__()
|
|
350
246
|
# Get the model configuration and services
|
|
351
247
|
model_config = get_provider_model()
|
|
352
|
-
|
|
248
|
+
# Use filtered service in TUI to restrict access to CWD codebase only
|
|
249
|
+
storage_dir = get_shotgun_home() / "codebases"
|
|
250
|
+
codebase_service = FilteredCodebaseService(storage_dir)
|
|
353
251
|
self.codebase_sdk = CodebaseSDK()
|
|
354
252
|
|
|
355
253
|
# Create shared deps without system_prompt_fn (agents provide their own)
|
|
@@ -423,6 +321,7 @@ class ChatScreen(Screen[None]):
|
|
|
423
321
|
self.mount_hint(help_text_with_codebase(already_indexed=True))
|
|
424
322
|
return
|
|
425
323
|
|
|
324
|
+
# Ask user if they want to index the current directory
|
|
426
325
|
should_index = await self.app.push_screen_wait(CodebaseIndexPromptScreen())
|
|
427
326
|
if not should_index:
|
|
428
327
|
self.mount_hint(help_text_empty_dir())
|
|
@@ -430,7 +329,10 @@ class ChatScreen(Screen[None]):
|
|
|
430
329
|
|
|
431
330
|
self.mount_hint(help_text_with_codebase(already_indexed=False))
|
|
432
331
|
|
|
433
|
-
|
|
332
|
+
# Auto-index the current directory with its name
|
|
333
|
+
cwd_name = cur_dir.name
|
|
334
|
+
selection = CodebaseIndexSelection(repo_path=cur_dir, name=cwd_name)
|
|
335
|
+
self.call_later(lambda: self.index_codebase(selection))
|
|
434
336
|
|
|
435
337
|
def watch_mode(self, new_mode: AgentType) -> None:
|
|
436
338
|
"""React to mode changes by updating the agent manager."""
|
|
@@ -529,12 +431,16 @@ class ChatScreen(Screen[None]):
|
|
|
529
431
|
@on(PartialResponseMessage)
|
|
530
432
|
def handle_partial_response(self, event: PartialResponseMessage) -> None:
|
|
531
433
|
self.partial_message = event.message
|
|
532
|
-
|
|
533
434
|
history = self.query_one(ChatHistory)
|
|
534
|
-
|
|
535
|
-
|
|
435
|
+
|
|
436
|
+
# Only update messages if the message list changed
|
|
437
|
+
new_message_list = self.messages + cast(
|
|
438
|
+
list[ModelMessage | HintMessage], event.messages
|
|
536
439
|
)
|
|
440
|
+
if len(new_message_list) != len(history.items):
|
|
441
|
+
history.update_messages(new_message_list)
|
|
537
442
|
|
|
443
|
+
# Always update the partial response (reactive property handles the update)
|
|
538
444
|
history.partial_response = self.partial_message
|
|
539
445
|
|
|
540
446
|
def _clear_partial_response(self) -> None:
|
|
@@ -640,16 +546,11 @@ class ChatScreen(Screen[None]):
|
|
|
640
546
|
return self.placeholder_hints.get_placeholder_for_mode(mode)
|
|
641
547
|
|
|
642
548
|
def index_codebase_command(self) -> None:
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
self.app.push_screen(
|
|
650
|
-
CodebaseIndexScreen(start_path=start_path),
|
|
651
|
-
handle_result,
|
|
652
|
-
)
|
|
549
|
+
# Simplified: always index current working directory with its name
|
|
550
|
+
cur_dir = Path.cwd().resolve()
|
|
551
|
+
cwd_name = cur_dir.name
|
|
552
|
+
selection = CodebaseIndexSelection(repo_path=cur_dir, name=cwd_name)
|
|
553
|
+
self.call_later(lambda: self.index_codebase(selection))
|
|
653
554
|
|
|
654
555
|
def delete_codebase_command(self) -> None:
|
|
655
556
|
self.app.push_screen(
|
|
@@ -41,7 +41,6 @@ class PartialResponseWidget(Widget): # TODO: doesn't work lol
|
|
|
41
41
|
self.item = item
|
|
42
42
|
|
|
43
43
|
def compose(self) -> ComposeResult:
|
|
44
|
-
yield Markdown(markdown="**partial response**")
|
|
45
44
|
if self.item is None:
|
|
46
45
|
pass
|
|
47
46
|
elif self.item.kind == "response":
|
|
@@ -82,12 +81,14 @@ class ChatHistory(Widget):
|
|
|
82
81
|
self.items: Sequence[ModelMessage | HintMessage] = []
|
|
83
82
|
self.vertical_tail: VerticalTail | None = None
|
|
84
83
|
self.partial_response = None
|
|
84
|
+
self._rendered_count = 0 # Track how many messages have been mounted
|
|
85
85
|
|
|
86
86
|
def compose(self) -> ComposeResult:
|
|
87
87
|
self.vertical_tail = VerticalTail()
|
|
88
88
|
|
|
89
|
+
filtered = list(self.filtered_items())
|
|
89
90
|
with self.vertical_tail:
|
|
90
|
-
for item in
|
|
91
|
+
for item in filtered:
|
|
91
92
|
if isinstance(item, ModelRequest):
|
|
92
93
|
yield UserQuestionWidget(item)
|
|
93
94
|
elif isinstance(item, HintMessage):
|
|
@@ -97,6 +98,9 @@ class ChatHistory(Widget):
|
|
|
97
98
|
yield PartialResponseWidget(self.partial_response).data_bind(
|
|
98
99
|
item=ChatHistory.partial_response
|
|
99
100
|
)
|
|
101
|
+
|
|
102
|
+
# Track how many messages were rendered during initial compose
|
|
103
|
+
self._rendered_count = len(filtered)
|
|
100
104
|
self.call_later(self.autoscroll)
|
|
101
105
|
|
|
102
106
|
def filtered_items(self) -> Generator[ModelMessage | HintMessage, None, None]:
|
|
@@ -138,17 +142,43 @@ class ChatHistory(Widget):
|
|
|
138
142
|
yield next_item
|
|
139
143
|
|
|
140
144
|
def update_messages(self, messages: list[ModelMessage | HintMessage]) -> None:
|
|
141
|
-
"""Update the displayed messages
|
|
145
|
+
"""Update the displayed messages using incremental mounting."""
|
|
142
146
|
if not self.vertical_tail:
|
|
143
147
|
return
|
|
144
148
|
|
|
145
149
|
self.items = messages
|
|
146
|
-
self.
|
|
147
|
-
|
|
150
|
+
filtered = list(self.filtered_items())
|
|
151
|
+
|
|
152
|
+
# Only mount new messages that haven't been rendered yet
|
|
153
|
+
if len(filtered) > self._rendered_count:
|
|
154
|
+
new_messages = filtered[self._rendered_count :]
|
|
155
|
+
for item in new_messages:
|
|
156
|
+
widget: Widget
|
|
157
|
+
if isinstance(item, ModelRequest):
|
|
158
|
+
widget = UserQuestionWidget(item)
|
|
159
|
+
elif isinstance(item, HintMessage):
|
|
160
|
+
widget = HintMessageWidget(item)
|
|
161
|
+
elif isinstance(item, ModelResponse):
|
|
162
|
+
widget = AgentResponseWidget(item)
|
|
163
|
+
else:
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
# Mount before the PartialResponseWidget
|
|
167
|
+
self.vertical_tail.mount(widget, before=self.vertical_tail.children[-1])
|
|
168
|
+
|
|
169
|
+
self._rendered_count = len(filtered)
|
|
170
|
+
self.call_after_refresh(self.autoscroll)
|
|
148
171
|
|
|
149
172
|
def autoscroll(self) -> None:
|
|
173
|
+
"""Smoothly scroll to the bottom after new content is added."""
|
|
150
174
|
if self.vertical_tail:
|
|
151
|
-
|
|
175
|
+
# Scroll to absolute bottom - more reliable during recomposition
|
|
176
|
+
self.vertical_tail.scroll_end(animate=False, force=True)
|
|
177
|
+
|
|
178
|
+
def watch_partial_response(self, partial_response: ModelMessage | None) -> None:
|
|
179
|
+
"""Trigger autoscroll when partial response updates during streaming."""
|
|
180
|
+
if partial_response is not None:
|
|
181
|
+
self.call_after_refresh(self.autoscroll)
|
|
152
182
|
|
|
153
183
|
|
|
154
184
|
class UserQuestionWidget(Widget):
|
|
@@ -103,13 +103,14 @@ 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
105
|
shotgun/tui/app.py,sha256=rNi1a2vIhu385-DylE1rYgVj3_cok65X_z1lEamrFqo,3445
|
|
106
|
+
shotgun/tui/filtered_codebase_service.py,sha256=lJ8gTMhIveTatmvmGLP299msWWTkVYKwvY_2FhuL2s4,1687
|
|
106
107
|
shotgun/tui/styles.tcss,sha256=ETyyw1bpMBOqTi5RLcAJUScdPWTvAWEqE9YcT0kVs_E,121
|
|
107
108
|
shotgun/tui/commands/__init__.py,sha256=8D5lvtpqMW5-fF7Bg3oJtUzU75cKOv6aUaHYYszydU8,2518
|
|
108
109
|
shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4UgadMXpbdXr40,2229
|
|
109
110
|
shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
|
|
110
111
|
shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
|
|
111
112
|
shotgun/tui/components/vertical_tail.py,sha256=GavHXNMq1X8hc0juDLKDWTW9seRLk3VlhBBMl60uPG0,439
|
|
112
|
-
shotgun/tui/screens/chat.py,sha256=
|
|
113
|
+
shotgun/tui/screens/chat.py,sha256=0fIERVokK06L-kIko_q57gx85j9M95hNpx7OPVZUGjc,27067
|
|
113
114
|
shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
|
|
114
115
|
shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
|
|
115
116
|
shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
|
|
@@ -117,7 +118,7 @@ shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw
|
|
|
117
118
|
shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
118
119
|
shotgun/tui/screens/chat_screen/command_providers.py,sha256=55JIH9T8QnyHRsMoXhOi87FiVM-d6o7OKpCe82uDP9I,7840
|
|
119
120
|
shotgun/tui/screens/chat_screen/hint_message.py,sha256=WOpbk8q7qt7eOHTyyHvh_IQIaublVDeJGaLpsxEk9FA,933
|
|
120
|
-
shotgun/tui/screens/chat_screen/history.py,sha256=
|
|
121
|
+
shotgun/tui/screens/chat_screen/history.py,sha256=qITuZH1dqeVlbtExh6EkLqcwQfjFt6Kn4VYqRHwS3iM,10356
|
|
121
122
|
shotgun/tui/utils/__init__.py,sha256=cFjDfoXTRBq29wgP7TGRWUu1eFfiIG-LLOzjIGfadgI,150
|
|
122
123
|
shotgun/tui/utils/mode_progress.py,sha256=lseRRo7kMWLkBzI3cU5vqJmS2ZcCjyRYf9Zwtvc-v58,10931
|
|
123
124
|
shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
|
|
@@ -125,8 +126,8 @@ shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,10
|
|
|
125
126
|
shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
|
|
126
127
|
shotgun/utils/source_detection.py,sha256=Co6Q03R3fT771TF3RzB-70stfjNP2S4F_ArZKibwzm8,454
|
|
127
128
|
shotgun/utils/update_checker.py,sha256=IgzPHRhS1ETH7PnJR_dIx6lxgr1qHpCkMTgzUxvGjhI,7586
|
|
128
|
-
shotgun_sh-0.1.
|
|
129
|
-
shotgun_sh-0.1.
|
|
130
|
-
shotgun_sh-0.1.
|
|
131
|
-
shotgun_sh-0.1.
|
|
132
|
-
shotgun_sh-0.1.
|
|
129
|
+
shotgun_sh-0.1.12.dev1.dist-info/METADATA,sha256=HArvIlxxxiQ9eSFZIhSyW_87DTijn5s4qn1RFMuONUc,11197
|
|
130
|
+
shotgun_sh-0.1.12.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
131
|
+
shotgun_sh-0.1.12.dev1.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
|
|
132
|
+
shotgun_sh-0.1.12.dev1.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
|
|
133
|
+
shotgun_sh-0.1.12.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|