feat: Enterprise DSS architecture implementation
Some checks failed
DSS Project Analysis / dss-context-update (push) Has been cancelled
Some checks failed
DSS Project Analysis / dss-context-update (push) Has been cancelled
Complete implementation of enterprise design system validation: Phase 1 - @dss/rules npm package: - CLI with validate and init commands - 16 rules across 5 categories (colors, spacing, typography, components, a11y) - dss-ignore support (inline and next-line) - Break-glass [dss-skip] for emergency merges - CI workflow templates (Gitea, GitHub, GitLab) Phase 2 - Metrics dashboard: - FastAPI metrics API with SQLite storage - Portfolio-wide metrics aggregation - Project drill-down with file:line:column violations - Trend charts and history tracking Phase 3 - Local analysis cache: - LocalAnalysisCache for offline-capable validation - Mode detection (LOCAL/REMOTE/CI) - Stale cache warnings with recommendations Phase 4 - Project onboarding: - dss-init command for project setup - Creates ds.config.json, .dss/ folder structure - Updates .gitignore and package.json scripts - Optional CI workflow setup Architecture decisions: - No commit-back: CI uploads to dashboard, not git - Three-tier: Dashboard (read-only) → CI (authoritative) → Local (advisory) - Pull-based rules via npm for version control 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,11 @@ DSS Context Module
|
||||
|
||||
Singleton context manager for the DSS Plugin.
|
||||
Handles configuration loading, mode detection, and strategy instantiation.
|
||||
|
||||
Enterprise Architecture:
|
||||
- LOCAL: Uses LocalAnalysisCache for fast, offline-capable validation
|
||||
- REMOTE: Full analysis via API
|
||||
- CI: Authoritative enforcement, uploads metrics to dashboard
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -11,6 +16,7 @@ import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from .config import DSSConfig, DSSMode
|
||||
from .local_cache import LocalAnalysisCache, LocalCacheValidator, get_project_cache
|
||||
|
||||
# Logger setup
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -44,6 +50,8 @@ class DSSContext:
|
||||
self._capabilities: Dict[str, bool] = {}
|
||||
self._strategy_cache: Dict[str, Strategy] = {}
|
||||
self.session_id: Optional[str] = None
|
||||
self._local_cache: Optional[LocalAnalysisCache] = None
|
||||
self._cache_validator: Optional[LocalCacheValidator] = None
|
||||
|
||||
@classmethod
|
||||
async def get_instance(cls) -> "DSSContext":
|
||||
@@ -91,7 +99,11 @@ class DSSContext:
|
||||
f"DSSContext initialized. Mode: {self.active_mode.value}, Session: {self.session_id}"
|
||||
)
|
||||
|
||||
# 3. Cache Capabilities
|
||||
# 3. Initialize local cache for LOCAL mode
|
||||
if self.active_mode == DSSMode.LOCAL:
|
||||
self._init_local_cache()
|
||||
|
||||
# 4. Cache Capabilities
|
||||
self._cache_capabilities()
|
||||
|
||||
except Exception as e:
|
||||
@@ -100,6 +112,27 @@ class DSSContext:
|
||||
self.active_mode = DSSMode.REMOTE
|
||||
self._capabilities = {"limited": True}
|
||||
|
||||
def _init_local_cache(self) -> None:
|
||||
"""Initialize local cache for LOCAL mode."""
|
||||
try:
|
||||
project_path = self.config.project_path if self.config else None
|
||||
self._local_cache = get_project_cache(project_path)
|
||||
self._cache_validator = LocalCacheValidator(self._local_cache)
|
||||
|
||||
# Log cache status
|
||||
status = self._local_cache.get_cache_status()
|
||||
if status.get("exists"):
|
||||
if status.get("is_stale"):
|
||||
logger.warning(f"Local cache is stale: {status.get('recommendation')}")
|
||||
else:
|
||||
logger.info(f"Local cache ready. Rules version: {status.get('rules_version')}")
|
||||
else:
|
||||
logger.info("No local cache found. Run `npx dss-rules validate` to populate.")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to initialize local cache: {e}")
|
||||
self._local_cache = None
|
||||
self._cache_validator = None
|
||||
|
||||
def _cache_capabilities(self) -> None:
|
||||
"""Determines what the plugin can do based on the active mode."""
|
||||
# Base capabilities
|
||||
@@ -192,3 +225,88 @@ class DSSContext:
|
||||
# Cache and return
|
||||
self._strategy_cache[strategy_type] = strategy_instance
|
||||
return strategy_instance
|
||||
|
||||
# === Local Cache Access Methods ===
|
||||
|
||||
def get_local_cache(self) -> Optional[LocalAnalysisCache]:
|
||||
"""
|
||||
Get the local analysis cache instance.
|
||||
|
||||
Returns:
|
||||
LocalAnalysisCache instance or None if not in LOCAL mode.
|
||||
"""
|
||||
return self._local_cache
|
||||
|
||||
def get_cache_validator(self) -> Optional[LocalCacheValidator]:
|
||||
"""
|
||||
Get the local cache validator instance.
|
||||
|
||||
Returns:
|
||||
LocalCacheValidator instance or None if not in LOCAL mode.
|
||||
"""
|
||||
return self._cache_validator
|
||||
|
||||
def get_cache_status(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get current cache status.
|
||||
|
||||
Returns:
|
||||
Cache status dict with freshness info and recommendations.
|
||||
"""
|
||||
if self._local_cache is None:
|
||||
return {
|
||||
"available": False,
|
||||
"mode": self.active_mode.value,
|
||||
"message": f"Local cache not available in {self.active_mode.value} mode"
|
||||
}
|
||||
|
||||
status = self._local_cache.get_cache_status()
|
||||
status["available"] = True
|
||||
status["mode"] = self.active_mode.value
|
||||
return status
|
||||
|
||||
def validate_file_local(self, file_path: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Validate a file using local cache (LOCAL mode only).
|
||||
|
||||
Args:
|
||||
file_path: Path to file to validate.
|
||||
|
||||
Returns:
|
||||
Validation result dict.
|
||||
"""
|
||||
if self._cache_validator is None:
|
||||
return {
|
||||
"file": file_path,
|
||||
"error": "Local cache not available",
|
||||
"mode": self.active_mode.value
|
||||
}
|
||||
|
||||
return self._cache_validator.validate_file(file_path)
|
||||
|
||||
def get_validation_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get summary of validation state from local cache.
|
||||
|
||||
Returns:
|
||||
Summary dict with counts and status.
|
||||
"""
|
||||
if self._cache_validator is None:
|
||||
return {
|
||||
"error": "Local cache not available",
|
||||
"mode": self.active_mode.value
|
||||
}
|
||||
|
||||
return self._cache_validator.get_summary()
|
||||
|
||||
def get_mode_behavior(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get behavior configuration for current mode.
|
||||
|
||||
Returns:
|
||||
Dict with blocking, upload_metrics, use_cache flags.
|
||||
"""
|
||||
if self.config is None:
|
||||
return {"blocking": False, "upload_metrics": False, "use_cache": False}
|
||||
|
||||
return self.config.get_mode_behavior(self.active_mode)
|
||||
|
||||
Reference in New Issue
Block a user