Initial commit: Clean DSS implementation

Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
Digital Production Factory
2025-12-09 18:45:48 -03:00
commit 276ed71f31
884 changed files with 373737 additions and 0 deletions

View File

@@ -0,0 +1,264 @@
"""
Base Integration Classes
Provides circuit breaker pattern and base classes for external integrations.
"""
import time
import asyncio
from typing import Callable, Any, Optional, Dict
from dataclasses import dataclass
from datetime import datetime, timedelta
from enum import Enum
from ..config import mcp_config
from storage.database import get_connection
class CircuitState(Enum):
"""Circuit breaker states"""
CLOSED = "closed" # Normal operation
OPEN = "open" # Failing, reject requests
HALF_OPEN = "half_open" # Testing if service recovered
@dataclass
class CircuitBreakerStats:
"""Circuit breaker statistics"""
state: CircuitState
failure_count: int
success_count: int
last_failure_time: Optional[float]
last_success_time: Optional[float]
opened_at: Optional[float]
next_retry_time: Optional[float]
class CircuitBreakerOpen(Exception):
"""Exception raised when circuit breaker is open"""
pass
class CircuitBreaker:
"""
Circuit Breaker pattern implementation.
Protects external service calls from cascading failures.
Three states: CLOSED (normal), OPEN (failing), HALF_OPEN (testing).
"""
def __init__(
self,
integration_type: str,
failure_threshold: int = None,
timeout_seconds: int = None,
half_open_max_calls: int = 3
):
"""
Args:
integration_type: Type of integration (figma, jira, confluence, etc.)
failure_threshold: Number of failures before opening circuit
timeout_seconds: Seconds to wait before trying again
half_open_max_calls: Max successful calls in half-open before closing
"""
self.integration_type = integration_type
self.failure_threshold = failure_threshold or mcp_config.CIRCUIT_BREAKER_FAILURE_THRESHOLD
self.timeout_seconds = timeout_seconds or mcp_config.CIRCUIT_BREAKER_TIMEOUT_SECONDS
self.half_open_max_calls = half_open_max_calls
# In-memory state (could be moved to Redis for distributed setup)
self.state = CircuitState.CLOSED
self.failure_count = 0
self.success_count = 0
self.last_failure_time: Optional[float] = None
self.last_success_time: Optional[float] = None
self.opened_at: Optional[float] = None
async def call(self, func: Callable, *args, **kwargs) -> Any:
"""
Call a function through the circuit breaker.
Args:
func: Function to call (can be sync or async)
*args, **kwargs: Arguments to pass to func
Returns:
Function result
Raises:
CircuitBreakerOpen: If circuit is open
Exception: Original exception from func if it fails
"""
# Check circuit state
if self.state == CircuitState.OPEN:
# Check if timeout has elapsed
if time.time() - self.opened_at < self.timeout_seconds:
await self._record_failure("Circuit breaker is OPEN", db_only=True)
raise CircuitBreakerOpen(
f"{self.integration_type} service is temporarily unavailable. "
f"Retry after {self._seconds_until_retry():.0f}s"
)
else:
# Timeout elapsed, move to HALF_OPEN
self.state = CircuitState.HALF_OPEN
self.success_count = 0
# Execute function
try:
# Handle both sync and async functions
if asyncio.iscoroutinefunction(func):
result = await func(*args, **kwargs)
else:
result = func(*args, **kwargs)
# Success!
await self._record_success()
# If in HALF_OPEN, check if we can close the circuit
if self.state == CircuitState.HALF_OPEN:
if self.success_count >= self.half_open_max_calls:
self.state = CircuitState.CLOSED
self.failure_count = 0
return result
except Exception as e:
# Failure
await self._record_failure(str(e))
# Check if we should open the circuit
if self.failure_count >= self.failure_threshold:
self.state = CircuitState.OPEN
self.opened_at = time.time()
raise
async def _record_success(self):
"""Record successful call"""
self.success_count += 1
self.last_success_time = time.time()
# Update database
await self._update_health_db(is_healthy=True, error=None)
async def _record_failure(self, error_message: str, db_only: bool = False):
"""Record failed call"""
if not db_only:
self.failure_count += 1
self.last_failure_time = time.time()
# Update database
await self._update_health_db(is_healthy=False, error=error_message)
async def _update_health_db(self, is_healthy: bool, error: Optional[str]):
"""Update integration health in database"""
loop = asyncio.get_event_loop()
def update_db():
try:
with get_connection() as conn:
circuit_open_until = None
if self.state == CircuitState.OPEN and self.opened_at:
circuit_open_until = datetime.fromtimestamp(
self.opened_at + self.timeout_seconds
).isoformat()
if is_healthy:
conn.execute(
"""
UPDATE integration_health
SET is_healthy = 1,
failure_count = 0,
last_success_at = CURRENT_TIMESTAMP,
circuit_open_until = NULL,
updated_at = CURRENT_TIMESTAMP
WHERE integration_type = ?
""",
(self.integration_type,)
)
else:
conn.execute(
"""
UPDATE integration_health
SET is_healthy = 0,
failure_count = ?,
last_failure_at = CURRENT_TIMESTAMP,
circuit_open_until = ?,
updated_at = CURRENT_TIMESTAMP
WHERE integration_type = ?
""",
(self.failure_count, circuit_open_until, self.integration_type)
)
except Exception as e:
print(f"Error updating integration health: {e}")
await loop.run_in_executor(None, update_db)
def _seconds_until_retry(self) -> float:
"""Get seconds until circuit can be retried"""
if self.state != CircuitState.OPEN or not self.opened_at:
return 0
elapsed = time.time() - self.opened_at
remaining = self.timeout_seconds - elapsed
return max(0, remaining)
def get_stats(self) -> CircuitBreakerStats:
"""Get current circuit breaker statistics"""
next_retry_time = None
if self.state == CircuitState.OPEN and self.opened_at:
next_retry_time = self.opened_at + self.timeout_seconds
return CircuitBreakerStats(
state=self.state,
failure_count=self.failure_count,
success_count=self.success_count,
last_failure_time=self.last_failure_time,
last_success_time=self.last_success_time,
opened_at=self.opened_at,
next_retry_time=next_retry_time
)
class BaseIntegration:
"""Base class for all external integrations"""
def __init__(self, integration_type: str, config: Dict[str, Any]):
"""
Args:
integration_type: Type of integration (figma, jira, etc.)
config: Integration configuration (decrypted)
"""
self.integration_type = integration_type
self.config = config
self.circuit_breaker = CircuitBreaker(integration_type)
async def call_api(self, func: Callable, *args, **kwargs) -> Any:
"""
Call external API through circuit breaker.
Args:
func: API function to call
*args, **kwargs: Arguments to pass
Returns:
API response
Raises:
CircuitBreakerOpen: If circuit is open
Exception: Original API exception
"""
return await self.circuit_breaker.call(func, *args, **kwargs)
def get_health(self) -> Dict[str, Any]:
"""Get integration health status"""
stats = self.circuit_breaker.get_stats()
return {
"integration_type": self.integration_type,
"state": stats.state.value,
"is_healthy": stats.state == CircuitState.CLOSED,
"failure_count": stats.failure_count,
"success_count": stats.success_count,
"last_failure_time": stats.last_failure_time,
"last_success_time": stats.last_success_time,
"next_retry_time": stats.next_retry_time
}

View File

@@ -0,0 +1,262 @@
"""
Confluence Integration for MCP
Provides Confluence API tools for documentation and knowledge base.
"""
from typing import Dict, Any, List, Optional
from atlassian import Confluence
from mcp import types
from .base import BaseIntegration
# Confluence MCP Tool Definitions
CONFLUENCE_TOOLS = [
types.Tool(
name="confluence_create_page",
description="Create a new Confluence page",
inputSchema={
"type": "object",
"properties": {
"space_key": {
"type": "string",
"description": "Confluence space key"
},
"title": {
"type": "string",
"description": "Page title"
},
"body": {
"type": "string",
"description": "Page content (HTML or wiki markup)"
},
"parent_id": {
"type": "string",
"description": "Optional parent page ID"
}
},
"required": ["space_key", "title", "body"]
}
),
types.Tool(
name="confluence_get_page",
description="Get Confluence page by ID or title",
inputSchema={
"type": "object",
"properties": {
"page_id": {
"type": "string",
"description": "Page ID (use this OR title)"
},
"space_key": {
"type": "string",
"description": "Space key (required if using title)"
},
"title": {
"type": "string",
"description": "Page title (use this OR page_id)"
},
"expand": {
"type": "string",
"description": "Comma-separated list of expansions (body.storage, version, etc.)",
"default": "body.storage,version"
}
}
}
),
types.Tool(
name="confluence_update_page",
description="Update an existing Confluence page",
inputSchema={
"type": "object",
"properties": {
"page_id": {
"type": "string",
"description": "Page ID to update"
},
"title": {
"type": "string",
"description": "New page title"
},
"body": {
"type": "string",
"description": "New page content"
}
},
"required": ["page_id", "title", "body"]
}
),
types.Tool(
name="confluence_search",
description="Search Confluence pages using CQL",
inputSchema={
"type": "object",
"properties": {
"cql": {
"type": "string",
"description": "CQL query (e.g., 'space=DSS AND type=page')"
},
"limit": {
"type": "integer",
"description": "Maximum number of results",
"default": 25
}
},
"required": ["cql"]
}
),
types.Tool(
name="confluence_get_space",
description="Get Confluence space details",
inputSchema={
"type": "object",
"properties": {
"space_key": {
"type": "string",
"description": "Space key"
}
},
"required": ["space_key"]
}
)
]
class ConfluenceIntegration(BaseIntegration):
"""Confluence API integration with circuit breaker"""
def __init__(self, config: Dict[str, Any]):
"""
Initialize Confluence integration.
Args:
config: Must contain 'url', 'username', 'api_token'
"""
super().__init__("confluence", config)
url = config.get("url")
username = config.get("username")
api_token = config.get("api_token")
if not all([url, username, api_token]):
raise ValueError("Confluence configuration incomplete: url, username, api_token required")
self.confluence = Confluence(
url=url,
username=username,
password=api_token,
cloud=True
)
async def create_page(
self,
space_key: str,
title: str,
body: str,
parent_id: Optional[str] = None
) -> Dict[str, Any]:
"""Create a new page"""
def _create():
return self.confluence.create_page(
space=space_key,
title=title,
body=body,
parent_id=parent_id,
representation="storage"
)
return await self.call_api(_create)
async def get_page(
self,
page_id: Optional[str] = None,
space_key: Optional[str] = None,
title: Optional[str] = None,
expand: str = "body.storage,version"
) -> Dict[str, Any]:
"""Get page by ID or title"""
def _get():
if page_id:
return self.confluence.get_page_by_id(
page_id=page_id,
expand=expand
)
elif space_key and title:
return self.confluence.get_page_by_title(
space=space_key,
title=title,
expand=expand
)
else:
raise ValueError("Must provide either page_id or (space_key + title)")
return await self.call_api(_get)
async def update_page(
self,
page_id: str,
title: str,
body: str
) -> Dict[str, Any]:
"""Update an existing page"""
def _update():
# Get current version
page = self.confluence.get_page_by_id(page_id, expand="version")
current_version = page["version"]["number"]
return self.confluence.update_page(
page_id=page_id,
title=title,
body=body,
parent_id=None,
type="page",
representation="storage",
minor_edit=False,
version_comment="Updated via DSS MCP",
version_number=current_version + 1
)
return await self.call_api(_update)
async def search(self, cql: str, limit: int = 25) -> Dict[str, Any]:
"""Search pages using CQL"""
def _search():
return self.confluence.cql(cql, limit=limit)
return await self.call_api(_search)
async def get_space(self, space_key: str) -> Dict[str, Any]:
"""Get space details"""
def _get():
return self.confluence.get_space(space_key)
return await self.call_api(_get)
class ConfluenceTools:
"""MCP tool executor for Confluence integration"""
def __init__(self, config: Dict[str, Any]):
self.confluence = ConfluenceIntegration(config)
async def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute Confluence tool"""
handlers = {
"confluence_create_page": self.confluence.create_page,
"confluence_get_page": self.confluence.get_page,
"confluence_update_page": self.confluence.update_page,
"confluence_search": self.confluence.search,
"confluence_get_space": self.confluence.get_space
}
handler = handlers.get(tool_name)
if not handler:
return {"error": f"Unknown Confluence tool: {tool_name}"}
try:
clean_args = {k: v for k, v in arguments.items() if not k.startswith("_")}
result = await handler(**clean_args)
return result
except Exception as e:
return {"error": str(e)}

View File

@@ -0,0 +1,260 @@
"""
Figma Integration for MCP
Provides Figma API tools through circuit breaker pattern.
"""
import httpx
from typing import Dict, Any, List, Optional
from mcp import types
from .base import BaseIntegration
from ..config import integration_config
# Figma MCP Tool Definitions
FIGMA_TOOLS = [
types.Tool(
name="figma_get_file",
description="Get Figma file metadata and structure",
inputSchema={
"type": "object",
"properties": {
"file_key": {
"type": "string",
"description": "Figma file key"
}
},
"required": ["file_key"]
}
),
types.Tool(
name="figma_get_styles",
description="Get design styles (colors, text, effects) from Figma file",
inputSchema={
"type": "object",
"properties": {
"file_key": {
"type": "string",
"description": "Figma file key"
}
},
"required": ["file_key"]
}
),
types.Tool(
name="figma_get_components",
description="Get component definitions from Figma file",
inputSchema={
"type": "object",
"properties": {
"file_key": {
"type": "string",
"description": "Figma file key"
}
},
"required": ["file_key"]
}
),
types.Tool(
name="figma_extract_tokens",
description="Extract design tokens (variables) from Figma file",
inputSchema={
"type": "object",
"properties": {
"file_key": {
"type": "string",
"description": "Figma file key"
}
},
"required": ["file_key"]
}
),
types.Tool(
name="figma_get_node",
description="Get specific node/component by ID from Figma file",
inputSchema={
"type": "object",
"properties": {
"file_key": {
"type": "string",
"description": "Figma file key"
},
"node_id": {
"type": "string",
"description": "Node ID to fetch"
}
},
"required": ["file_key", "node_id"]
}
)
]
class FigmaIntegration(BaseIntegration):
"""Figma API integration with circuit breaker"""
FIGMA_API_BASE = "https://api.figma.com/v1"
def __init__(self, config: Dict[str, Any]):
"""
Initialize Figma integration.
Args:
config: Must contain 'api_token' or use FIGMA_TOKEN from env
"""
super().__init__("figma", config)
self.api_token = config.get("api_token") or integration_config.FIGMA_TOKEN
if not self.api_token:
raise ValueError("Figma API token not configured")
self.headers = {
"X-Figma-Token": self.api_token
}
async def get_file(self, file_key: str) -> Dict[str, Any]:
"""
Get Figma file metadata and structure.
Args:
file_key: Figma file key
Returns:
File data
"""
async def _fetch():
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.FIGMA_API_BASE}/files/{file_key}",
headers=self.headers,
timeout=30.0
)
response.raise_for_status()
return response.json()
return await self.call_api(_fetch)
async def get_styles(self, file_key: str) -> Dict[str, Any]:
"""
Get all styles from Figma file.
Args:
file_key: Figma file key
Returns:
Styles data
"""
async def _fetch():
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.FIGMA_API_BASE}/files/{file_key}/styles",
headers=self.headers,
timeout=30.0
)
response.raise_for_status()
return response.json()
return await self.call_api(_fetch)
async def get_components(self, file_key: str) -> Dict[str, Any]:
"""
Get all components from Figma file.
Args:
file_key: Figma file key
Returns:
Components data
"""
async def _fetch():
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.FIGMA_API_BASE}/files/{file_key}/components",
headers=self.headers,
timeout=30.0
)
response.raise_for_status()
return response.json()
return await self.call_api(_fetch)
async def extract_tokens(self, file_key: str) -> Dict[str, Any]:
"""
Extract design tokens (variables) from Figma file.
Args:
file_key: Figma file key
Returns:
Variables/tokens data
"""
async def _fetch():
async with httpx.AsyncClient() as client:
# Get local variables
response = await client.get(
f"{self.FIGMA_API_BASE}/files/{file_key}/variables/local",
headers=self.headers,
timeout=30.0
)
response.raise_for_status()
return response.json()
return await self.call_api(_fetch)
async def get_node(self, file_key: str, node_id: str) -> Dict[str, Any]:
"""
Get specific node from Figma file.
Args:
file_key: Figma file key
node_id: Node ID
Returns:
Node data
"""
async def _fetch():
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.FIGMA_API_BASE}/files/{file_key}/nodes",
headers=self.headers,
params={"ids": node_id},
timeout=30.0
)
response.raise_for_status()
return response.json()
return await self.call_api(_fetch)
class FigmaTools:
"""MCP tool executor for Figma integration"""
def __init__(self, config: Dict[str, Any]):
"""
Args:
config: Figma configuration (with api_token)
"""
self.figma = FigmaIntegration(config)
async def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute Figma tool"""
handlers = {
"figma_get_file": self.figma.get_file,
"figma_get_styles": self.figma.get_styles,
"figma_get_components": self.figma.get_components,
"figma_extract_tokens": self.figma.extract_tokens,
"figma_get_node": self.figma.get_node
}
handler = handlers.get(tool_name)
if not handler:
return {"error": f"Unknown Figma tool: {tool_name}"}
try:
# Remove tool-specific prefix from arguments if needed
clean_args = {k: v for k, v in arguments.items() if not k.startswith("_")}
result = await handler(**clean_args)
return result
except Exception as e:
return {"error": str(e)}

View File

@@ -0,0 +1,215 @@
"""
Jira Integration for MCP
Provides Jira API tools for issue tracking and project management.
"""
from typing import Dict, Any, List, Optional
from atlassian import Jira
from mcp import types
from .base import BaseIntegration
# Jira MCP Tool Definitions
JIRA_TOOLS = [
types.Tool(
name="jira_create_issue",
description="Create a new Jira issue",
inputSchema={
"type": "object",
"properties": {
"project_key": {
"type": "string",
"description": "Jira project key (e.g., 'DSS')"
},
"summary": {
"type": "string",
"description": "Issue summary/title"
},
"description": {
"type": "string",
"description": "Issue description"
},
"issue_type": {
"type": "string",
"description": "Issue type (Story, Task, Bug, etc.)",
"default": "Task"
}
},
"required": ["project_key", "summary"]
}
),
types.Tool(
name="jira_get_issue",
description="Get Jira issue details by key",
inputSchema={
"type": "object",
"properties": {
"issue_key": {
"type": "string",
"description": "Issue key (e.g., 'DSS-123')"
}
},
"required": ["issue_key"]
}
),
types.Tool(
name="jira_search_issues",
description="Search Jira issues using JQL",
inputSchema={
"type": "object",
"properties": {
"jql": {
"type": "string",
"description": "JQL query (e.g., 'project=DSS AND status=Open')"
},
"max_results": {
"type": "integer",
"description": "Maximum number of results",
"default": 50
}
},
"required": ["jql"]
}
),
types.Tool(
name="jira_update_issue",
description="Update a Jira issue",
inputSchema={
"type": "object",
"properties": {
"issue_key": {
"type": "string",
"description": "Issue key to update"
},
"fields": {
"type": "object",
"description": "Fields to update (summary, description, status, etc.)"
}
},
"required": ["issue_key", "fields"]
}
),
types.Tool(
name="jira_add_comment",
description="Add a comment to a Jira issue",
inputSchema={
"type": "object",
"properties": {
"issue_key": {
"type": "string",
"description": "Issue key"
},
"comment": {
"type": "string",
"description": "Comment text"
}
},
"required": ["issue_key", "comment"]
}
)
]
class JiraIntegration(BaseIntegration):
"""Jira API integration with circuit breaker"""
def __init__(self, config: Dict[str, Any]):
"""
Initialize Jira integration.
Args:
config: Must contain 'url', 'username', 'api_token'
"""
super().__init__("jira", config)
url = config.get("url")
username = config.get("username")
api_token = config.get("api_token")
if not all([url, username, api_token]):
raise ValueError("Jira configuration incomplete: url, username, api_token required")
self.jira = Jira(
url=url,
username=username,
password=api_token,
cloud=True
)
async def create_issue(
self,
project_key: str,
summary: str,
description: str = "",
issue_type: str = "Task"
) -> Dict[str, Any]:
"""Create a new Jira issue"""
def _create():
fields = {
"project": {"key": project_key},
"summary": summary,
"description": description,
"issuetype": {"name": issue_type}
}
return self.jira.create_issue(fields)
return await self.call_api(_create)
async def get_issue(self, issue_key: str) -> Dict[str, Any]:
"""Get issue details"""
def _get():
return self.jira.get_issue(issue_key)
return await self.call_api(_get)
async def search_issues(self, jql: str, max_results: int = 50) -> Dict[str, Any]:
"""Search issues with JQL"""
def _search():
return self.jira.jql(jql, limit=max_results)
return await self.call_api(_search)
async def update_issue(self, issue_key: str, fields: Dict[str, Any]) -> Dict[str, Any]:
"""Update issue fields"""
def _update():
self.jira.update_issue_field(issue_key, fields)
return {"status": "updated", "issue_key": issue_key}
return await self.call_api(_update)
async def add_comment(self, issue_key: str, comment: str) -> Dict[str, Any]:
"""Add comment to issue"""
def _comment():
return self.jira.issue_add_comment(issue_key, comment)
return await self.call_api(_comment)
class JiraTools:
"""MCP tool executor for Jira integration"""
def __init__(self, config: Dict[str, Any]):
self.jira = JiraIntegration(config)
async def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute Jira tool"""
handlers = {
"jira_create_issue": self.jira.create_issue,
"jira_get_issue": self.jira.get_issue,
"jira_search_issues": self.jira.search_issues,
"jira_update_issue": self.jira.update_issue,
"jira_add_comment": self.jira.add_comment
}
handler = handlers.get(tool_name)
if not handler:
return {"error": f"Unknown Jira tool: {tool_name}"}
try:
clean_args = {k: v for k, v in arguments.items() if not k.startswith("_")}
result = await handler(**clean_args)
return result
except Exception as e:
return {"error": str(e)}