signalpilot-ai-internal 0.5.1__py3-none-any.whl → 0.6.0__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 signalpilot-ai-internal might be problematic. Click here for more details.

Files changed (46) hide show
  1. signalpilot_ai_internal/_version.py +1 -1
  2. signalpilot_ai_internal/cache_service.py +152 -1
  3. signalpilot_ai_internal/file_scanner_service.py +1252 -0
  4. signalpilot_ai_internal/handlers.py +262 -0
  5. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json +2 -2
  6. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig +1 -1
  7. signalpilot_ai_internal-0.6.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/188.1ace26ac1a5e246783bb.js +1 -0
  8. signalpilot_ai_internal-0.6.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.7d9a99d0566aa6743c69.js +1 -0
  9. signalpilot_ai_internal-0.6.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js +2 -0
  10. signalpilot_ai_internal-0.6.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.410a42566793b732952f.js +1 -0
  11. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/third-party-licenses.json +0 -6
  12. {signalpilot_ai_internal-0.5.1.dist-info → signalpilot_ai_internal-0.6.0.dist-info}/METADATA +3 -1
  13. signalpilot_ai_internal-0.6.0.dist-info/RECORD +46 -0
  14. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/104.04e170724f369fcbaf19.js +0 -2
  15. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/104.04e170724f369fcbaf19.js.LICENSE.txt +0 -24
  16. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/188.e781cc4c87f2dbf290ec.js +0 -1
  17. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/606.90aaaae46b73dc3c08fb.js +0 -1
  18. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.7ea0c8f6af45369912f3.js +0 -1
  19. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.5251a593584dd5d131d5.js +0 -2
  20. signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.59ffb91489066223094b.js +0 -1
  21. signalpilot_ai_internal-0.5.1.dist-info/RECORD +0 -48
  22. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/etc/jupyter/jupyter_server_config.d/signalpilot_ai.json +0 -0
  23. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/install.json +0 -0
  24. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/plugin.json +0 -0
  25. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.e2dadf63dc64d7b5f1ee.js +0 -0
  26. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.328403b5545f268b95c6.js +0 -0
  27. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.726e1da31a50868cb297.js +0 -0
  28. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.72484b768a04f89bd3dd.js +0 -0
  29. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.dbec4c2dc12e7b050dcc.js +0 -0
  30. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.fa432bdb7fb6b1c95ad6.js +0 -0
  31. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.37e271d7a80336daabe2.js +0 -0
  32. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.9b4f05a99f5003f82094.js +0 -0
  33. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.73c7a9290b7d35a8b9c1.js +0 -0
  34. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.b58fc0093d080b8ee61c.js +0 -0
  35. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js +0 -0
  36. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js.LICENSE.txt +0 -0
  37. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.9720593ee20b768da3ca.js +0 -0
  38. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.8e6edc9a965bdd578ca7.js +0 -0
  39. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/741.dc49867fafb03ea2ba4d.js +0 -0
  40. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/742.91e7b516c8699eea3373.js +0 -0
  41. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.3aa564fc148b37d1d719.js +0 -0
  42. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/888.34054db17bcf6e87ec95.js +0 -0
  43. /signalpilot_ai_internal-0.5.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.5251a593584dd5d131d5.js.LICENSE.txt → /signalpilot_ai_internal-0.6.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js.LICENSE.txt +0 -0
  44. {signalpilot_ai_internal-0.5.1.data → signalpilot_ai_internal-0.6.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/style.js +0 -0
  45. {signalpilot_ai_internal-0.5.1.dist-info → signalpilot_ai_internal-0.6.0.dist-info}/WHEEL +0 -0
  46. {signalpilot_ai_internal-0.5.1.dist-info → signalpilot_ai_internal-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.5.1'
4
+ __version__ = VERSION = '0.6.0'
@@ -3,6 +3,7 @@ Persistent caching service for SignalPilot AI.
3
3
  Handles OS-specific cache directory management and robust file operations.
4
4
  """
5
5
 
6
+ import hashlib
6
7
  import json
7
8
  import os
8
9
  import platform
@@ -12,7 +13,7 @@ import threading
12
13
  import time
13
14
  import uuid
14
15
  from pathlib import Path
15
- from typing import Any, Dict, Optional
16
+ from typing import Any, Dict, List, Optional
16
17
 
17
18
 
18
19
  class CacheDirectoryManager:
@@ -537,8 +538,150 @@ class PersistentCacheService:
537
538
  return info
538
539
 
539
540
 
541
+ class FileScanCacheManager:
542
+ """Dedicated cache manager for file scanning operations with individual file caching"""
543
+
544
+ def __init__(self):
545
+ self.cache_dir = CacheDirectoryManager.find_usable_cache_directory()
546
+ self.file_scans_dir = None
547
+ self.scanned_directories_file = None
548
+ self._lock = threading.RLock()
549
+
550
+ if self.cache_dir:
551
+ self.file_scans_dir = self.cache_dir / "file_scans"
552
+ self.scanned_directories_file = self.file_scans_dir / "scanned_directories.json"
553
+
554
+ # Initialize file scans directory
555
+ try:
556
+ self.file_scans_dir.mkdir(parents=True, exist_ok=True)
557
+ print(f"File scan cache directory initialized: {self.file_scans_dir}")
558
+ except Exception as e:
559
+ print(f"ERROR: Failed to create file scans directory: {e}")
560
+ self.file_scans_dir = None
561
+ self.scanned_directories_file = None
562
+ else:
563
+ print("WARNING: File scan cache manager running without persistent storage!")
564
+
565
+ def _get_file_cache_path(self, file_path: str) -> Path:
566
+ """Generate cache file path using MD5 hash of absolute file path"""
567
+ if not self.file_scans_dir:
568
+ raise ValueError("File scans directory not available")
569
+
570
+ # Create hash from absolute file path
571
+ file_hash = hashlib.md5(file_path.encode()).hexdigest()
572
+ return self.file_scans_dir / f"{file_hash}.json"
573
+
574
+ def is_available(self) -> bool:
575
+ """Check if file scan cache is available"""
576
+ return self.file_scans_dir is not None and self.file_scans_dir.exists()
577
+
578
+ def get_file_entry(self, file_path: str) -> Optional[Dict[str, Any]]:
579
+ """Read individual file cache entry"""
580
+ if not self.is_available():
581
+ return None
582
+
583
+ try:
584
+ cache_path = self._get_file_cache_path(file_path)
585
+ return RobustFileOperations.safe_read_json(cache_path, None)
586
+ except Exception as e:
587
+ print(f"Error reading file cache for {file_path}: {e}")
588
+ return None
589
+
590
+ def set_file_entry(self, file_path: str, entry: Dict[str, Any]) -> bool:
591
+ """Write individual file cache entry"""
592
+ if not self.is_available():
593
+ return False
594
+
595
+ try:
596
+ cache_path = self._get_file_cache_path(file_path)
597
+ return RobustFileOperations.safe_write_json(cache_path, entry)
598
+ except Exception as e:
599
+ print(f"Error writing file cache for {file_path}: {e}")
600
+ return False
601
+
602
+ def delete_file_entry(self, file_path: str) -> bool:
603
+ """Delete individual file cache entry"""
604
+ if not self.is_available():
605
+ return False
606
+
607
+ try:
608
+ cache_path = self._get_file_cache_path(file_path)
609
+ if cache_path.exists():
610
+ cache_path.unlink()
611
+ return True
612
+ return True # File doesn't exist, consider it deleted
613
+ except Exception as e:
614
+ print(f"Error deleting file cache for {file_path}: {e}")
615
+ return False
616
+
617
+ def get_scanned_directories(self) -> List[Dict[str, Any]]:
618
+ """Read scanned directories list"""
619
+ if not self.scanned_directories_file:
620
+ return []
621
+
622
+ try:
623
+ return RobustFileOperations.safe_read_json(self.scanned_directories_file, [])
624
+ except Exception as e:
625
+ print(f"Error reading scanned directories: {e}")
626
+ return []
627
+
628
+ def set_scanned_directories(self, directories: List[Dict[str, Any]]) -> bool:
629
+ """Write scanned directories list"""
630
+ if not self.scanned_directories_file:
631
+ return False
632
+
633
+ try:
634
+ return RobustFileOperations.safe_write_json(self.scanned_directories_file, directories)
635
+ except Exception as e:
636
+ print(f"Error writing scanned directories: {e}")
637
+ return False
638
+
639
+ def clear_all_file_entries(self) -> bool:
640
+ """Clear all cached file entries"""
641
+ if not self.is_available():
642
+ return False
643
+
644
+ try:
645
+ # Remove all .json files except scanned_directories.json
646
+ for cache_file in self.file_scans_dir.glob("*.json"):
647
+ if cache_file.name != "scanned_directories.json":
648
+ cache_file.unlink()
649
+ return True
650
+ except Exception as e:
651
+ print(f"Error clearing file entries: {e}")
652
+ return False
653
+
654
+ def get_cache_stats(self) -> Dict[str, Any]:
655
+ """Return cache statistics"""
656
+ stats = {
657
+ "available": self.is_available(),
658
+ "file_scans_directory": str(self.file_scans_dir) if self.file_scans_dir else None,
659
+ "total_file_entries": 0,
660
+ "total_cache_size": 0,
661
+ "scanned_directories_count": 0
662
+ }
663
+
664
+ if self.is_available():
665
+ try:
666
+ # Count file entries (excluding scanned_directories.json)
667
+ file_entries = list(self.file_scans_dir.glob("*.json"))
668
+ file_entries = [f for f in file_entries if f.name != "scanned_directories.json"]
669
+ stats["total_file_entries"] = len(file_entries)
670
+ stats["total_cache_size"] = sum(f.stat().st_size for f in file_entries if f.exists())
671
+
672
+ # Count scanned directories
673
+ directories = self.get_scanned_directories()
674
+ stats["scanned_directories_count"] = len(directories)
675
+
676
+ except Exception as e:
677
+ stats["error"] = str(e)
678
+
679
+ return stats
680
+
681
+
540
682
  # Global cache service instance
541
683
  _cache_service = None
684
+ _file_scan_cache_manager = None
542
685
 
543
686
 
544
687
  def get_cache_service() -> PersistentCacheService:
@@ -547,3 +690,11 @@ def get_cache_service() -> PersistentCacheService:
547
690
  if _cache_service is None:
548
691
  _cache_service = PersistentCacheService()
549
692
  return _cache_service
693
+
694
+
695
+ def get_file_scan_cache_manager() -> FileScanCacheManager:
696
+ """Get the global file scan cache manager instance"""
697
+ global _file_scan_cache_manager
698
+ if _file_scan_cache_manager is None:
699
+ _file_scan_cache_manager = FileScanCacheManager()
700
+ return _file_scan_cache_manager