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

Files changed (51) hide show
  1. shotgun/agents/agent_manager.py +95 -15
  2. shotgun/agents/common.py +139 -24
  3. shotgun/agents/conversation_history.py +56 -0
  4. shotgun/agents/conversation_manager.py +105 -0
  5. shotgun/agents/export.py +5 -2
  6. shotgun/agents/models.py +16 -7
  7. shotgun/agents/plan.py +2 -1
  8. shotgun/agents/research.py +2 -1
  9. shotgun/agents/specify.py +2 -1
  10. shotgun/agents/tasks.py +5 -2
  11. shotgun/agents/tools/file_management.py +67 -2
  12. shotgun/main.py +9 -1
  13. shotgun/prompts/agents/export.j2 +14 -11
  14. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +6 -9
  15. shotgun/prompts/agents/plan.j2 +9 -13
  16. shotgun/prompts/agents/research.j2 +11 -14
  17. shotgun/prompts/agents/specify.j2 +9 -12
  18. shotgun/prompts/agents/state/system_state.j2 +27 -5
  19. shotgun/prompts/agents/tasks.j2 +12 -12
  20. shotgun/sdk/services.py +0 -14
  21. shotgun/tui/app.py +9 -4
  22. shotgun/tui/screens/chat.py +57 -8
  23. shotgun/tui/screens/chat_screen/command_providers.py +1 -1
  24. shotgun/tui/screens/chat_screen/history.py +6 -0
  25. shotgun/tui/utils/mode_progress.py +111 -78
  26. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev23.dist-info}/METADATA +8 -9
  27. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev23.dist-info}/RECORD +30 -49
  28. shotgun/agents/artifact_state.py +0 -58
  29. shotgun/agents/tools/artifact_management.py +0 -481
  30. shotgun/artifacts/__init__.py +0 -17
  31. shotgun/artifacts/exceptions.py +0 -89
  32. shotgun/artifacts/manager.py +0 -530
  33. shotgun/artifacts/models.py +0 -334
  34. shotgun/artifacts/service.py +0 -463
  35. shotgun/artifacts/templates/__init__.py +0 -10
  36. shotgun/artifacts/templates/loader.py +0 -252
  37. shotgun/artifacts/templates/models.py +0 -136
  38. shotgun/artifacts/templates/plan/delivery_and_release_plan.yaml +0 -66
  39. shotgun/artifacts/templates/research/market_research.yaml +0 -585
  40. shotgun/artifacts/templates/research/sdk_comparison.yaml +0 -257
  41. shotgun/artifacts/templates/specify/prd.yaml +0 -331
  42. shotgun/artifacts/templates/specify/product_spec.yaml +0 -301
  43. shotgun/artifacts/utils.py +0 -76
  44. shotgun/prompts/agents/partials/artifact_system.j2 +0 -32
  45. shotgun/prompts/agents/state/artifact_templates_available.j2 +0 -20
  46. shotgun/prompts/agents/state/existing_artifacts_available.j2 +0 -25
  47. shotgun/sdk/artifact_models.py +0 -186
  48. shotgun/sdk/artifacts.py +0 -448
  49. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev23.dist-info}/WHEEL +0 -0
  50. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev23.dist-info}/entry_points.txt +0 -0
  51. {shotgun_sh-0.1.0.dev22.dist-info → shotgun_sh-0.1.0.dev23.dist-info}/licenses/LICENSE +0 -0
shotgun/sdk/artifacts.py DELETED
@@ -1,448 +0,0 @@
1
- """Artifact SDK for framework-agnostic business logic."""
2
-
3
- from collections.abc import Callable
4
- from pathlib import Path
5
- from typing import Any
6
-
7
- from shotgun.artifacts.exceptions import (
8
- ArtifactAlreadyExistsError,
9
- ArtifactError,
10
- ArtifactNotFoundError,
11
- SectionAlreadyExistsError,
12
- SectionNotFoundError,
13
- )
14
- from shotgun.artifacts.models import AgentMode, ArtifactSection
15
- from shotgun.artifacts.service import ArtifactService
16
- from shotgun.artifacts.utils import generate_artifact_name
17
-
18
- from .artifact_models import (
19
- ArtifactCreateResult,
20
- ArtifactDeleteResult,
21
- ArtifactErrorResult,
22
- ArtifactInfoResult,
23
- ArtifactListResult,
24
- SectionContentResult,
25
- SectionCreateResult,
26
- SectionDeleteResult,
27
- SectionUpdateResult,
28
- )
29
-
30
-
31
- class ArtifactSDK:
32
- """Framework-agnostic SDK for artifact operations.
33
-
34
- This SDK provides business logic for artifact management that can be
35
- used by both CLI and TUI implementations without framework dependencies.
36
- """
37
-
38
- def __init__(self, base_path: Path | None = None):
39
- """Initialize SDK with optional base path.
40
-
41
- Args:
42
- base_path: Optional custom base path for artifacts.
43
- Defaults to .shotgun in current directory.
44
- """
45
- self.service = ArtifactService(base_path)
46
-
47
- # Artifact operations
48
-
49
- def list_artifacts(
50
- self, agent_mode: AgentMode | None = None
51
- ) -> ArtifactListResult | ArtifactErrorResult:
52
- """List all artifacts, optionally filtered by agent mode.
53
-
54
- Args:
55
- agent_mode: Optional agent mode filter
56
-
57
- Returns:
58
- ArtifactListResult containing list of artifacts or ArtifactErrorResult
59
- """
60
- try:
61
- artifacts = self.service.list_artifacts(agent_mode)
62
- return ArtifactListResult(artifacts=artifacts, agent_mode=agent_mode)
63
- except ArtifactError as e:
64
- return ArtifactErrorResult(error_message=str(e), agent_mode=agent_mode)
65
-
66
- def create_artifact(
67
- self,
68
- artifact_id: str,
69
- agent_mode: AgentMode,
70
- name: str,
71
- template_id: str | None = None,
72
- ) -> ArtifactCreateResult | ArtifactErrorResult:
73
- """Create a new artifact.
74
-
75
- Args:
76
- artifact_id: Unique identifier for the artifact
77
- agent_mode: Agent mode this artifact belongs to
78
- name: Human-readable name for the artifact
79
- template_id: Optional template ID to use for creating the artifact
80
-
81
- Returns:
82
- ArtifactCreateResult or ArtifactErrorResult
83
- """
84
- try:
85
- self.service.create_artifact(artifact_id, agent_mode, name, template_id)
86
- return ArtifactCreateResult(
87
- artifact_id=artifact_id,
88
- agent_mode=agent_mode,
89
- name=name,
90
- )
91
- except ArtifactAlreadyExistsError as e:
92
- return ArtifactErrorResult(
93
- error_message="Artifact already exists",
94
- artifact_id=artifact_id,
95
- agent_mode=agent_mode,
96
- details=str(e),
97
- )
98
- except ArtifactError as e:
99
- return ArtifactErrorResult(
100
- error_message=str(e),
101
- artifact_id=artifact_id,
102
- agent_mode=agent_mode,
103
- )
104
-
105
- def delete_artifact(
106
- self,
107
- artifact_id: str,
108
- agent_mode: AgentMode,
109
- confirm_callback: Callable[[str, AgentMode], bool] | None = None,
110
- ) -> ArtifactDeleteResult | ArtifactErrorResult:
111
- """Delete an artifact with optional confirmation.
112
-
113
- Args:
114
- artifact_id: ID of the artifact to delete
115
- agent_mode: Agent mode
116
- confirm_callback: Optional callback for confirmation that receives
117
- artifact_id and agent_mode and returns boolean.
118
-
119
- Returns:
120
- ArtifactDeleteResult or ArtifactErrorResult
121
- """
122
- try:
123
- # Handle confirmation callback if provided
124
- if confirm_callback and not confirm_callback(artifact_id, agent_mode):
125
- return ArtifactDeleteResult(
126
- artifact_id=artifact_id,
127
- agent_mode=agent_mode,
128
- deleted=False,
129
- cancelled=True,
130
- )
131
-
132
- self.service.delete_artifact(artifact_id, agent_mode)
133
- return ArtifactDeleteResult(
134
- artifact_id=artifact_id,
135
- agent_mode=agent_mode,
136
- deleted=True,
137
- )
138
- except ArtifactNotFoundError as e:
139
- return ArtifactErrorResult(
140
- error_message="Artifact not found",
141
- artifact_id=artifact_id,
142
- agent_mode=agent_mode,
143
- details=str(e),
144
- )
145
- except ArtifactError as e:
146
- return ArtifactErrorResult(
147
- error_message=str(e),
148
- artifact_id=artifact_id,
149
- agent_mode=agent_mode,
150
- )
151
-
152
- def get_artifact_info(
153
- self, artifact_id: str, agent_mode: AgentMode
154
- ) -> ArtifactInfoResult | ArtifactErrorResult:
155
- """Get detailed information about an artifact.
156
-
157
- Args:
158
- artifact_id: ID of the artifact to get info for
159
- agent_mode: Agent mode
160
-
161
- Returns:
162
- ArtifactInfoResult or ArtifactErrorResult
163
- """
164
- try:
165
- artifact = self.service.get_artifact(artifact_id, agent_mode, "")
166
- return ArtifactInfoResult(artifact=artifact)
167
- except ArtifactNotFoundError as e:
168
- return ArtifactErrorResult(
169
- error_message="Artifact not found",
170
- artifact_id=artifact_id,
171
- agent_mode=agent_mode,
172
- details=str(e),
173
- )
174
- except ArtifactError as e:
175
- return ArtifactErrorResult(
176
- error_message=str(e),
177
- artifact_id=artifact_id,
178
- agent_mode=agent_mode,
179
- )
180
-
181
- # Section operations
182
-
183
- def create_section(
184
- self,
185
- artifact_id: str,
186
- agent_mode: AgentMode,
187
- section_number: int,
188
- section_slug: str,
189
- section_title: str,
190
- content: str = "",
191
- ) -> SectionCreateResult | ArtifactErrorResult:
192
- """Create a new section in an artifact.
193
-
194
- Args:
195
- artifact_id: Artifact identifier
196
- agent_mode: Agent mode
197
- section_number: Section number
198
- section_slug: Section slug
199
- section_title: Section title
200
- content: Section content
201
-
202
- Returns:
203
- SectionCreateResult or ArtifactErrorResult
204
- """
205
- try:
206
- section = ArtifactSection(
207
- number=section_number,
208
- slug=section_slug,
209
- title=section_title,
210
- content=content,
211
- )
212
- self.service.add_section(artifact_id, agent_mode, section)
213
- return SectionCreateResult(
214
- artifact_id=artifact_id,
215
- agent_mode=agent_mode,
216
- section_number=section_number,
217
- section_title=section_title,
218
- )
219
- except (SectionAlreadyExistsError, ArtifactNotFoundError) as e:
220
- return ArtifactErrorResult(
221
- error_message=str(e),
222
- artifact_id=artifact_id,
223
- agent_mode=agent_mode,
224
- section_number=section_number,
225
- )
226
- except ArtifactError as e:
227
- return ArtifactErrorResult(
228
- error_message=str(e),
229
- artifact_id=artifact_id,
230
- agent_mode=agent_mode,
231
- section_number=section_number,
232
- )
233
-
234
- def update_section(
235
- self,
236
- artifact_id: str,
237
- agent_mode: AgentMode,
238
- section_number: int,
239
- **kwargs: Any,
240
- ) -> SectionUpdateResult | ArtifactErrorResult:
241
- """Update a section in an artifact.
242
-
243
- Args:
244
- artifact_id: Artifact identifier
245
- agent_mode: Agent mode
246
- section_number: Section number to update
247
- **kwargs: Fields to update
248
-
249
- Returns:
250
- SectionUpdateResult or ArtifactErrorResult
251
- """
252
- try:
253
- self.service.update_section(
254
- artifact_id, agent_mode, section_number, **kwargs
255
- )
256
- return SectionUpdateResult(
257
- artifact_id=artifact_id,
258
- agent_mode=agent_mode,
259
- section_number=section_number,
260
- updated_fields=list(kwargs.keys()),
261
- )
262
- except (SectionNotFoundError, ArtifactNotFoundError) as e:
263
- return ArtifactErrorResult(
264
- error_message=str(e),
265
- artifact_id=artifact_id,
266
- agent_mode=agent_mode,
267
- section_number=section_number,
268
- )
269
- except ArtifactError as e:
270
- return ArtifactErrorResult(
271
- error_message=str(e),
272
- artifact_id=artifact_id,
273
- agent_mode=agent_mode,
274
- section_number=section_number,
275
- )
276
-
277
- def delete_section(
278
- self,
279
- artifact_id: str,
280
- agent_mode: AgentMode,
281
- section_number: int,
282
- ) -> SectionDeleteResult | ArtifactErrorResult:
283
- """Delete a section from an artifact.
284
-
285
- Args:
286
- artifact_id: Artifact identifier
287
- agent_mode: Agent mode
288
- section_number: Section number to delete
289
-
290
- Returns:
291
- SectionDeleteResult or ArtifactErrorResult
292
- """
293
- try:
294
- self.service.delete_section(artifact_id, agent_mode, section_number)
295
- return SectionDeleteResult(
296
- artifact_id=artifact_id,
297
- agent_mode=agent_mode,
298
- section_number=section_number,
299
- )
300
- except (SectionNotFoundError, ArtifactNotFoundError) as e:
301
- return ArtifactErrorResult(
302
- error_message=str(e),
303
- artifact_id=artifact_id,
304
- agent_mode=agent_mode,
305
- section_number=section_number,
306
- )
307
- except ArtifactError as e:
308
- return ArtifactErrorResult(
309
- error_message=str(e),
310
- artifact_id=artifact_id,
311
- agent_mode=agent_mode,
312
- section_number=section_number,
313
- )
314
-
315
- def get_section_content(
316
- self,
317
- artifact_id: str,
318
- agent_mode: AgentMode,
319
- section_number: int,
320
- ) -> SectionContentResult | ArtifactErrorResult:
321
- """Get the content of a section.
322
-
323
- Args:
324
- artifact_id: Artifact identifier
325
- agent_mode: Agent mode
326
- section_number: Section number
327
-
328
- Returns:
329
- SectionContentResult or ArtifactErrorResult
330
- """
331
- try:
332
- content = self.service.get_section_content(
333
- artifact_id, agent_mode, section_number
334
- )
335
- return SectionContentResult(
336
- artifact_id=artifact_id,
337
- agent_mode=agent_mode,
338
- section_number=section_number,
339
- content=content,
340
- )
341
- except (SectionNotFoundError, ArtifactNotFoundError) as e:
342
- return ArtifactErrorResult(
343
- error_message=str(e),
344
- artifact_id=artifact_id,
345
- agent_mode=agent_mode,
346
- section_number=section_number,
347
- )
348
- except ArtifactError as e:
349
- return ArtifactErrorResult(
350
- error_message=str(e),
351
- artifact_id=artifact_id,
352
- agent_mode=agent_mode,
353
- section_number=section_number,
354
- )
355
-
356
- # Template operations
357
-
358
- def list_templates(
359
- self, agent_mode: AgentMode | None = None
360
- ) -> list[Any] | ArtifactErrorResult:
361
- """List available artifact templates.
362
-
363
- Args:
364
- agent_mode: Optional agent mode filter
365
-
366
- Returns:
367
- List of template summaries or ArtifactErrorResult
368
- """
369
- try:
370
- return self.service.list_templates(agent_mode)
371
- except Exception as e:
372
- return ArtifactErrorResult(
373
- error_message=f"Failed to list templates: {str(e)}",
374
- agent_mode=agent_mode,
375
- )
376
-
377
- # Convenience methods
378
-
379
- def ensure_artifact_exists(
380
- self,
381
- artifact_id: str,
382
- agent_mode: AgentMode,
383
- name: str | None = None,
384
- ) -> ArtifactCreateResult | ArtifactInfoResult | ArtifactErrorResult:
385
- """Ensure an artifact exists, creating it if necessary.
386
-
387
- Args:
388
- artifact_id: Artifact identifier
389
- agent_mode: Agent mode
390
- name: Optional name (defaults to formatted artifact_id)
391
-
392
- Returns:
393
- ArtifactCreateResult if created, ArtifactInfoResult if already existed, ArtifactErrorResult on error
394
- """
395
- if name is None:
396
- name = generate_artifact_name(artifact_id)
397
-
398
- # Try to get existing artifact
399
- info_result = self.get_artifact_info(artifact_id, agent_mode)
400
- if isinstance(info_result, ArtifactInfoResult):
401
- return info_result
402
-
403
- # Create new artifact
404
- create_result = self.create_artifact(artifact_id, agent_mode, name)
405
- return create_result
406
-
407
- def ensure_section_exists(
408
- self,
409
- artifact_id: str,
410
- agent_mode: AgentMode,
411
- section_number: int,
412
- section_slug: str,
413
- section_title: str,
414
- initial_content: str = "",
415
- ) -> SectionCreateResult | SectionContentResult | ArtifactErrorResult:
416
- """Ensure a section exists, creating it if necessary.
417
-
418
- Args:
419
- artifact_id: Artifact identifier
420
- agent_mode: Agent mode
421
- section_number: Section number
422
- section_slug: Section slug
423
- section_title: Section title
424
- initial_content: Initial content for new sections
425
-
426
- Returns:
427
- SectionCreateResult if created, SectionContentResult if already existed, ArtifactErrorResult on error
428
- """
429
- # Try to get existing section
430
- content_result = self.get_section_content(
431
- artifact_id, agent_mode, section_number
432
- )
433
- if isinstance(content_result, SectionContentResult):
434
- return content_result
435
-
436
- # Ensure artifact exists first
437
- self.ensure_artifact_exists(artifact_id, agent_mode)
438
-
439
- # Create new section
440
- create_result = self.create_section(
441
- artifact_id,
442
- agent_mode,
443
- section_number,
444
- section_slug,
445
- section_title,
446
- initial_content,
447
- )
448
- return create_result