feat: Enterprise DSS architecture implementation
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:
DSS
2025-12-11 09:41:36 -03:00
parent ab8769933d
commit 9dbd56271e
27 changed files with 3888 additions and 398 deletions

View File

@@ -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)