shotgun-sh 0.1.6__py3-none-any.whl → 0.1.8.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.

@@ -12,8 +12,8 @@ POSTHOG_API_KEY = ''
12
12
  POSTHOG_PROJECT_ID = '191396'
13
13
 
14
14
  # Logfire configuration embedded at build time (only for dev builds)
15
- LOGFIRE_ENABLED = ''
16
- LOGFIRE_TOKEN = ''
15
+ LOGFIRE_ENABLED = 'true'
16
+ LOGFIRE_TOKEN = 'pylf_v1_us_KZ5NM1pP3NwgJkbBJt6Ftdzk8mMhmrXcGJHQQgDJ1LfK'
17
17
 
18
18
  # Build metadata
19
19
  BUILD_TIME_ENV = "production" if SENTRY_DSN else "development"
shotgun/main.py CHANGED
@@ -22,7 +22,7 @@ from shotgun.posthog_telemetry import setup_posthog_observability
22
22
  from shotgun.sentry_telemetry import setup_sentry_observability
23
23
  from shotgun.telemetry import setup_logfire_observability
24
24
  from shotgun.tui import app as tui_app
25
- from shotgun.utils.update_checker import check_and_install_updates_async
25
+ from shotgun.utils.update_checker import check_for_updates_async
26
26
 
27
27
  # Load environment variables from .env file
28
28
  load_dotenv()
@@ -52,7 +52,6 @@ logger.debug("PostHog analytics enabled: %s", _posthog_enabled)
52
52
 
53
53
  # Global variable to store update notification
54
54
  _update_notification: str | None = None
55
- _update_progress: str | None = None
56
55
 
57
56
 
58
57
  def _update_callback(notification: str) -> None:
@@ -61,13 +60,6 @@ def _update_callback(notification: str) -> None:
61
60
  _update_notification = notification
62
61
 
63
62
 
64
- def _update_progress_callback(progress: str) -> None:
65
- """Callback to store update progress."""
66
- global _update_progress
67
- _update_progress = progress
68
- logger.debug(f"Update progress: {progress}")
69
-
70
-
71
63
  app = typer.Typer(
72
64
  name="shotgun",
73
65
  help="Shotgun - AI-powered CLI tool for research, planning, and task management",
@@ -129,12 +121,10 @@ def main(
129
121
  """Shotgun - AI-powered CLI tool."""
130
122
  logger.debug("Starting shotgun CLI application")
131
123
 
132
- # Start async update check and install (non-blocking)
124
+ # Start async update check (non-blocking)
133
125
  if not ctx.resilient_parsing:
134
- check_and_install_updates_async(
135
- callback=_update_callback,
136
- no_update_check=no_update_check,
137
- progress_callback=_update_progress_callback,
126
+ check_for_updates_async(
127
+ callback=_update_callback, no_update_check=no_update_check
138
128
  )
139
129
 
140
130
  if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
shotgun/tui/app.py CHANGED
@@ -9,7 +9,7 @@ from shotgun.agents.config import ConfigManager, get_config_manager
9
9
  from shotgun.logging_config import get_logger
10
10
  from shotgun.tui.screens.splash import SplashScreen
11
11
  from shotgun.utils.file_system_utils import get_shotgun_base_path
12
- from shotgun.utils.update_checker import check_and_install_updates_async
12
+ from shotgun.utils.update_checker import check_for_updates_async
13
13
 
14
14
  from .screens.chat import ChatScreen
15
15
  from .screens.directory_setup import DirectorySetupScreen
@@ -37,26 +37,16 @@ class ShotgunApp(App[None]):
37
37
  self.no_update_check = no_update_check
38
38
  self.continue_session = continue_session
39
39
  self.update_notification: str | None = None
40
- self.update_progress: str | None = None
41
40
 
42
- # Start async update check and install
41
+ # Start async update check
43
42
  if not no_update_check:
44
- check_and_install_updates_async(
45
- callback=self._update_callback,
46
- no_update_check=no_update_check,
47
- progress_callback=self._update_progress_callback,
48
- )
43
+ check_for_updates_async(callback=self._update_callback)
49
44
 
50
45
  def _update_callback(self, notification: str) -> None:
51
46
  """Store update notification to show later."""
52
47
  self.update_notification = notification
53
48
  logger.debug(f"Update notification received: {notification}")
54
49
 
55
- def _update_progress_callback(self, progress: str) -> None:
56
- """Store update progress."""
57
- self.update_progress = progress
58
- logger.debug(f"Update progress: {progress}")
59
-
60
50
  def on_mount(self) -> None:
61
51
  self.theme = "gruvbox"
62
52
  # Track TUI startup
@@ -249,9 +249,6 @@ def perform_update(force: bool = False) -> tuple[bool, str]:
249
249
  if not compare_versions(__version__, latest):
250
250
  return False, f"Already at latest version ({__version__})"
251
251
 
252
- # Store current version for comparison
253
- current_version = __version__
254
-
255
252
  # Detect installation method
256
253
  method = detect_installation_method()
257
254
  command = get_update_command(method)
@@ -263,114 +260,8 @@ def perform_update(force: bool = False) -> tuple[bool, str]:
263
260
 
264
261
  result = subprocess.run(command, capture_output=True, text=True, timeout=60) # noqa: S603
265
262
 
266
- # Log output for debugging
267
- if result.stdout:
268
- logger.debug(f"Update stdout: {result.stdout}")
269
- if result.stderr:
270
- logger.debug(f"Update stderr: {result.stderr}")
271
- logger.debug(f"Update return code: {result.returncode}")
272
-
273
- # Check for success patterns in output (pipx specific)
274
- output_combined = (result.stdout or "") + (result.stderr or "")
275
-
276
- # For pipx, check if it mentions successful upgrade or already at latest
277
- pipx_success_patterns = [
278
- "successfully upgraded",
279
- "is already at latest version",
280
- f"installed package shotgun-sh {latest}",
281
- "upgrading shotgun-sh...",
282
- ]
283
-
284
- pipx_success = method == "pipx" and any(
285
- pattern.lower() in output_combined.lower()
286
- for pattern in pipx_success_patterns
287
- )
288
-
289
- # Verify actual installation by checking version
290
- update_successful = False
291
-
292
- # For pipx with return code 0, trust it succeeded
293
- if method == "pipx" and result.returncode == 0:
294
- update_successful = True
295
- logger.debug("Pipx returned 0, trusting update succeeded")
296
- elif result.returncode == 0 or pipx_success:
297
- # Give the system a moment to update the package metadata
298
- import time
299
-
300
- time.sleep(1)
301
-
302
- # Try to verify the installed version
303
- try:
304
- # For pipx, we need to check differently
305
- if method == "pipx":
306
- # Use pipx list to verify the installed version
307
- verify_result = subprocess.run(
308
- ["pipx", "list", "--json"], # noqa: S607
309
- capture_output=True,
310
- text=True,
311
- timeout=5, # noqa: S603
312
- )
313
- if verify_result.returncode == 0:
314
- try:
315
- pipx_data = json.loads(verify_result.stdout)
316
- venvs = pipx_data.get("venvs", {})
317
- shotgun_info = venvs.get("shotgun-sh", {})
318
- metadata = shotgun_info.get("metadata", {})
319
- main_package = metadata.get("main_package", {})
320
- installed_version = main_package.get("package_version", "")
321
- if installed_version == latest:
322
- update_successful = True
323
- logger.debug(
324
- f"Pipx verification successful: version {installed_version}"
325
- )
326
- except (json.JSONDecodeError, KeyError) as e:
327
- logger.debug(
328
- f"Pipx JSON parsing failed: {e}, trusting patterns"
329
- )
330
- update_successful = pipx_success
331
- else:
332
- # Fallback to checking with command
333
- import shutil
334
-
335
- shotgun_path = shutil.which("shotgun")
336
- if shotgun_path:
337
- verify_result = subprocess.run( # noqa: S603
338
- [shotgun_path, "--version"],
339
- capture_output=True,
340
- text=True,
341
- timeout=5,
342
- )
343
- if (
344
- verify_result.returncode == 0
345
- and latest in verify_result.stdout
346
- ):
347
- update_successful = True
348
- logger.debug(
349
- f"Version verification successful: {verify_result.stdout.strip()}"
350
- )
351
- else:
352
- update_successful = pipx_success
353
- else:
354
- # For pip/venv, check with python module
355
- verify_result = subprocess.run( # noqa: S603
356
- [sys.executable, "-m", "shotgun", "--version"],
357
- capture_output=True,
358
- text=True,
359
- timeout=5,
360
- )
361
- if verify_result.returncode == 0 and latest in verify_result.stdout:
362
- update_successful = True
363
- logger.debug(
364
- f"Version verification successful: {verify_result.stdout.strip()}"
365
- )
366
- except Exception as e:
367
- logger.debug(f"Version verification failed: {e}")
368
- # If verification fails but initial command succeeded, trust it
369
- if not update_successful:
370
- update_successful = result.returncode == 0 or pipx_success
371
-
372
- if update_successful:
373
- message = f"Successfully updated from {current_version} to {latest}"
263
+ if result.returncode == 0:
264
+ message = f"Successfully updated from {__version__} to {latest}"
374
265
  logger.info(message)
375
266
 
376
267
  # Clear cache to trigger fresh check next time
@@ -380,13 +271,7 @@ def perform_update(force: bool = False) -> tuple[bool, str]:
380
271
 
381
272
  return True, message
382
273
  else:
383
- # Only use stderr for error message, stdout often contains normal progress
384
- if result.stderr:
385
- error_msg = f"Update failed: {result.stderr}"
386
- elif result.returncode != 0:
387
- error_msg = f"Update failed with exit code {result.returncode}: {result.stdout or 'No output'}"
388
- else:
389
- error_msg = "Update verification failed but command may have succeeded"
274
+ error_msg = f"Update failed: {result.stderr or result.stdout}"
390
275
  logger.error(error_msg)
391
276
  return False, error_msg
392
277
 
@@ -409,31 +294,6 @@ def format_update_notification(current: str, latest: str) -> str:
409
294
  return f"Update available: {current} → {latest}. Run 'shotgun update' to upgrade."
410
295
 
411
296
 
412
- def format_update_status(
413
- status: str, current: str | None = None, latest: str | None = None
414
- ) -> str:
415
- """Format update status messages.
416
-
417
- Args:
418
- status: Status type ('installing', 'success', 'failed', 'checking').
419
- current: Current version (optional).
420
- latest: Latest version (optional).
421
-
422
- Returns:
423
- Formatted status message.
424
- """
425
- if status == "checking":
426
- return "Checking for updates..."
427
- elif status == "installing" and current and latest:
428
- return f"Installing update: {current} → {latest}..."
429
- elif status == "success" and latest:
430
- return f"✓ Successfully updated to version {latest}. Restart your terminal to use the new version."
431
- elif status == "failed":
432
- return "Update failed. Run 'shotgun update' to try manually."
433
- else:
434
- return ""
435
-
436
-
437
297
  def check_for_updates_sync(no_update_check: bool = False) -> str | None:
438
298
  """Synchronously check for updates and return notification if available.
439
299
 
@@ -476,69 +336,6 @@ def check_for_updates_sync(no_update_check: bool = False) -> str | None:
476
336
  return None
477
337
 
478
338
 
479
- def check_and_install_updates_sync(no_update_check: bool = False) -> tuple[str, bool]:
480
- """Synchronously check for updates and install if available.
481
-
482
- Args:
483
- no_update_check: If True, skip update checks and installation.
484
-
485
- Returns:
486
- Tuple of (status message, success boolean).
487
- """
488
- if no_update_check:
489
- return "", False
490
-
491
- if not should_check_for_updates(no_update_check):
492
- return "", False
493
-
494
- # Skip auto-install for development versions
495
- if is_dev_version():
496
- logger.debug("Skipping auto-install for development version")
497
- return "", False
498
-
499
- latest_version = get_latest_version()
500
- if not latest_version:
501
- return "", False
502
- latest = latest_version # Type narrowing
503
-
504
- # Check if update is needed
505
- if not compare_versions(__version__, latest):
506
- # Already up to date, update cache
507
- now = datetime.now(timezone.utc)
508
- cache_data = UpdateCache(
509
- last_check=now,
510
- latest_version=latest,
511
- current_version=__version__,
512
- update_available=False,
513
- )
514
- save_cache(cache_data)
515
- return "", False
516
-
517
- # Perform the update
518
- logger.info(f"Auto-installing update: {__version__} → {latest}")
519
- success, message = perform_update(force=False)
520
-
521
- if success:
522
- # Clear cache on successful update
523
- cache_file = get_cache_file()
524
- if cache_file.exists():
525
- cache_file.unlink()
526
- return format_update_status("success", latest=latest), True
527
- else:
528
- # Update cache to mark that we tried and failed
529
- # This prevents repeated attempts within the check interval
530
- now = datetime.now(timezone.utc)
531
- cache_data = UpdateCache(
532
- last_check=now,
533
- latest_version=latest,
534
- current_version=__version__,
535
- update_available=True, # Still available, but we failed to install
536
- )
537
- save_cache(cache_data)
538
- logger.warning(f"Auto-update failed: {message}")
539
- return format_update_status("failed"), False
540
-
541
-
542
339
  def check_for_updates_async(
543
340
  callback: Callable[[str], None] | None = None, no_update_check: bool = False
544
341
  ) -> threading.Thread:
@@ -565,117 +362,6 @@ def check_for_updates_async(
565
362
  return thread
566
363
 
567
364
 
568
- def check_and_install_updates_async(
569
- callback: Callable[[str], None] | None = None,
570
- no_update_check: bool = False,
571
- progress_callback: Callable[[str], None] | None = None,
572
- ) -> threading.Thread:
573
- """Asynchronously check for updates and install in a background thread.
574
-
575
- Args:
576
- callback: Optional callback function to call with final status message.
577
- no_update_check: If True, skip update checks and installation.
578
- progress_callback: Optional callback for progress updates.
579
-
580
- Returns:
581
- The thread object that was started.
582
- """
583
-
584
- def _check_and_install() -> None:
585
- try:
586
- # Send checking status if progress callback provided
587
- if progress_callback:
588
- progress_callback(format_update_status("checking"))
589
-
590
- # Skip if disabled
591
- if no_update_check:
592
- return
593
-
594
- # Skip for dev versions
595
- if is_dev_version():
596
- logger.debug("Skipping auto-install for development version")
597
- return
598
-
599
- # Check if we should check for updates
600
- if not should_check_for_updates(no_update_check):
601
- # Check cache to see if update is still pending
602
- cache = load_cache()
603
- if cache and cache.update_available:
604
- # We have a pending update from a previous check
605
- # Don't retry installation automatically to avoid repeated failures
606
- if callback:
607
- callback(
608
- format_update_notification(
609
- cache.current_version, cache.latest_version
610
- )
611
- )
612
- return
613
-
614
- # Get latest version
615
- latest_version = get_latest_version()
616
- if not latest_version:
617
- return
618
- latest = latest_version # Type narrowing
619
-
620
- # Check if update is needed
621
- if not compare_versions(__version__, latest):
622
- # Already up to date, update cache
623
- now = datetime.now(timezone.utc)
624
- cache_data = UpdateCache(
625
- last_check=now,
626
- latest_version=latest,
627
- current_version=__version__,
628
- update_available=False,
629
- )
630
- save_cache(cache_data)
631
- logger.debug(f"Already at latest version ({__version__})")
632
- return
633
-
634
- # Send installing status
635
- if progress_callback:
636
- progress_callback(
637
- format_update_status(
638
- "installing", current=__version__, latest=latest
639
- )
640
- )
641
-
642
- # Perform the update
643
- logger.info(f"Auto-installing update: {__version__} → {latest}")
644
- success, message = perform_update(force=False)
645
-
646
- if success:
647
- # Clear cache on successful update
648
- cache_file = get_cache_file()
649
- if cache_file.exists():
650
- cache_file.unlink()
651
-
652
- if callback:
653
- callback(format_update_status("success", latest=latest))
654
- else:
655
- # Update cache to mark that we tried and failed
656
- now = datetime.now(timezone.utc)
657
- cache_data = UpdateCache(
658
- last_check=now,
659
- latest_version=latest,
660
- current_version=__version__,
661
- update_available=True,
662
- )
663
- save_cache(cache_data)
664
- logger.warning(f"Auto-update failed: {message}")
665
-
666
- if callback:
667
- callback(format_update_status("failed"))
668
-
669
- except Exception as e:
670
- logger.debug(f"Error in async update check and install: {e}")
671
- if callback:
672
- callback(format_update_status("failed"))
673
-
674
- thread = threading.Thread(target=_check_and_install, daemon=True)
675
- thread.start()
676
- return thread
677
-
678
-
679
365
  __all__ = [
680
366
  "UpdateCache",
681
367
  "is_dev_version",
@@ -685,8 +371,5 @@ __all__ = [
685
371
  "perform_update",
686
372
  "check_for_updates_async",
687
373
  "check_for_updates_sync",
688
- "check_and_install_updates_async",
689
- "check_and_install_updates_sync",
690
374
  "format_update_notification",
691
- "format_update_status",
692
375
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.1.6
3
+ Version: 0.1.8.dev1
4
4
  Summary: AI-powered research, planning, and task management CLI tool
5
5
  Project-URL: Homepage, https://shotgun.sh/
6
6
  Project-URL: Repository, https://github.com/shotgun-sh/shotgun
@@ -1,7 +1,7 @@
1
1
  shotgun/__init__.py,sha256=P40K0fnIsb7SKcQrFnXZ4aREjpWchVDhvM1HxI4cyIQ,104
2
- shotgun/build_constants.py,sha256=hDFr6eO0lwN0iCqHQ1A5s0D68txR8sYrTJLGa7tSi0o,654
2
+ shotgun/build_constants.py,sha256=RXNxMz46HaB5jucgMVpw8a2yCJqjbhTOh0PddyEVMN8,713
3
3
  shotgun/logging_config.py,sha256=UKenihvgH8OA3W0b8ZFcItYaFJVe9MlsMYlcevyW1HY,7440
4
- shotgun/main.py,sha256=lFx8IsLIfMvOw6lMJGnzg8o9HKcuj59VxhjNgetMZP0,5854
4
+ shotgun/main.py,sha256=5WEtPs5kwD1tdeWCnM-jIAwarcwQNc4dhaqdPKCyxug,5510
5
5
  shotgun/posthog_telemetry.py,sha256=usfaJ8VyqckLIbLgoj2yhuNyDh0VWA5EJPRr7a0dyVs,5054
6
6
  shotgun/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  shotgun/sentry_telemetry.py,sha256=0W0o810ewFpIcdPsi_q4uKLiaP6zDYRRE5MHpIbQIPo,2954
@@ -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=AAoFQYw6A9_kVxB0c0p7g-BNdplexfZIQbrGDQ1m4KI,4407
105
+ shotgun/tui/app.py,sha256=t0IAQbGr0lKKEoBVnp85DcmZ-V92bi79SjyEE2uKpuw,3990
106
106
  shotgun/tui/styles.tcss,sha256=ETyyw1bpMBOqTi5RLcAJUScdPWTvAWEqE9YcT0kVs_E,121
107
107
  shotgun/tui/commands/__init__.py,sha256=8D5lvtpqMW5-fF7Bg3oJtUzU75cKOv6aUaHYYszydU8,2518
108
108
  shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4UgadMXpbdXr40,2229
@@ -123,9 +123,9 @@ shotgun/tui/utils/mode_progress.py,sha256=lseRRo7kMWLkBzI3cU5vqJmS2ZcCjyRYf9Zwtv
123
123
  shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
124
124
  shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,1057
125
125
  shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
126
- shotgun/utils/update_checker.py,sha256=7zdNV1GbEKrUrduibDZ6OeUcuyz87Pihr3GKayL5Kxk,23944
127
- shotgun_sh-0.1.6.dist-info/METADATA,sha256=-PbbQuJfK6Wfn-eC2LKft13vdiEpFcT1QMtHPGv0m1w,11191
128
- shotgun_sh-0.1.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
129
- shotgun_sh-0.1.6.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
130
- shotgun_sh-0.1.6.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
131
- shotgun_sh-0.1.6.dist-info/RECORD,,
126
+ shotgun/utils/update_checker.py,sha256=Xf-7w3Pos3etzCoT771gJe2HLkA8_V2GrqWy7ni9UqA,11373
127
+ shotgun_sh-0.1.8.dev1.dist-info/METADATA,sha256=Th2ky9U_hy_zxh_OP67Io7DJlWT9BjRAG61EAZb6OPE,11196
128
+ shotgun_sh-0.1.8.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
129
+ shotgun_sh-0.1.8.dev1.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
130
+ shotgun_sh-0.1.8.dev1.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
131
+ shotgun_sh-0.1.8.dev1.dist-info/RECORD,,