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:
311
admin-ui/js/services/tool-bridge.js
Normal file
311
admin-ui/js/services/tool-bridge.js
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* tool-bridge.js
|
||||
* Service to execute MCP tools from the UI
|
||||
* MVP1: Auto-injects context from ContextStore, removes hardcoded defaults
|
||||
*/
|
||||
|
||||
import contextStore from '../stores/context-store.js';
|
||||
|
||||
class ToolBridge {
|
||||
constructor() {
|
||||
this.apiBase = '/api';
|
||||
this.toolCache = new Map();
|
||||
this.context = null; // Deprecated - use contextStore instead
|
||||
}
|
||||
|
||||
/**
|
||||
* MVP1: Get execution context from ContextStore
|
||||
* NO DEFAULTS - throws if project not selected
|
||||
* @returns {object} Context with projectId, teamId, userId
|
||||
*/
|
||||
getContext() {
|
||||
const mcpContext = contextStore.getMCPContext();
|
||||
|
||||
// Validate required context
|
||||
if (!mcpContext.project_id) {
|
||||
throw new Error('No project selected. Please select a project from the header.');
|
||||
}
|
||||
|
||||
return {
|
||||
projectId: mcpContext.project_id,
|
||||
teamId: mcpContext.team_id,
|
||||
userId: mcpContext.user_id,
|
||||
capabilities: mcpContext.capabilities
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set execution context (DEPRECATED - use contextStore.setProject/setTeam instead)
|
||||
* @param {string} projectId - Project ID
|
||||
* @param {string} userId - User ID
|
||||
*/
|
||||
setContext(projectId, userId) {
|
||||
console.warn('[ToolBridge] setContext is deprecated. Use contextStore.setProject() instead');
|
||||
contextStore.setProject(projectId);
|
||||
this.context = { projectId, userId };
|
||||
}
|
||||
|
||||
/**
|
||||
* MVP1: Execute an MCP tool with auto-context injection
|
||||
* Implements interceptor pattern with standardized error handling
|
||||
* @param {string} toolName - MCP tool name (e.g., 'dss_extract_tokens')
|
||||
* @param {object} params - Tool parameters
|
||||
* @returns {Promise<any>} Tool execution result
|
||||
*/
|
||||
async executeTool(toolName, params = {}) {
|
||||
console.log(`[ToolBridge] Executing tool: ${toolName}`, params);
|
||||
|
||||
try {
|
||||
// Auto-inject context from ContextStore
|
||||
const context = this.getContext();
|
||||
|
||||
// Wrap parameters with auto-injected context
|
||||
const payload = {
|
||||
project_id: context.projectId,
|
||||
team_id: context.teamId,
|
||||
user_id: context.userId,
|
||||
arguments: params,
|
||||
_client_timestamp: Date.now() // For debugging
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.apiBase}/mcp/tools/${toolName}/execute`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
// Standardized error handling
|
||||
if (!response.ok) {
|
||||
// Handle specific HTTP status codes
|
||||
if (response.status === 502) {
|
||||
throw new Error('MCP Server Offline - Please check backend connection');
|
||||
}
|
||||
if (response.status === 404) {
|
||||
throw new Error(`Tool not found: ${toolName}`);
|
||||
}
|
||||
|
||||
const errorText = await response.text();
|
||||
let errorMessage;
|
||||
|
||||
try {
|
||||
const errorJson = JSON.parse(errorText);
|
||||
errorMessage = errorJson.message || errorJson.detail || `Tool execution failed: ${response.statusText}`;
|
||||
} catch (e) {
|
||||
errorMessage = `Tool execution failed: ${response.status} - ${errorText}`;
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log(`[ToolBridge] Tool ${toolName} completed:`, result);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`[ToolBridge] Tool ${toolName} failed:`, error);
|
||||
|
||||
// Re-throw with enhanced error message if it's a context error
|
||||
if (error.message.includes('No project selected')) {
|
||||
throw new Error(`${error.message}\n\nTool: ${toolName}`);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of available MCP tools
|
||||
* @returns {Promise<Array>} Array of tool definitions
|
||||
*/
|
||||
async getAvailableTools() {
|
||||
if (this.toolCache.has('all')) {
|
||||
return this.toolCache.get('all');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${this.apiBase}/mcp/tools`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch tools: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const tools = await response.json();
|
||||
this.toolCache.set('all', tools);
|
||||
return tools;
|
||||
} catch (error) {
|
||||
console.error('[ToolBridge] Failed to fetch available tools:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tool definition by name
|
||||
* @param {string} toolName - MCP tool name
|
||||
* @returns {Promise<object|null>} Tool definition
|
||||
*/
|
||||
async getToolDefinition(toolName) {
|
||||
const tools = await this.getAvailableTools();
|
||||
return tools.find(tool => tool.name === toolName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_extract_tokens tool
|
||||
*/
|
||||
async extractTokens(path, sources = ['css', 'scss', 'tailwind', 'json']) {
|
||||
return this.executeTool('dss_extract_tokens', { path, sources });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_generate_theme tool
|
||||
*/
|
||||
async generateTheme(format, tokens = null, themeName = 'default') {
|
||||
return this.executeTool('dss_generate_theme', {
|
||||
format,
|
||||
tokens,
|
||||
theme_name: themeName
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_sync_figma tool
|
||||
*/
|
||||
async syncFigma(fileKey) {
|
||||
return this.executeTool('dss_sync_figma', { file_key: fileKey });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_resolve_token tool
|
||||
*/
|
||||
async resolveToken(manifestPath, tokenPath, forceRefresh = false) {
|
||||
return this.executeTool('dss_resolve_token', {
|
||||
manifest_path: manifestPath,
|
||||
token_path: tokenPath,
|
||||
force_refresh: forceRefresh
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_get_resolved_context tool
|
||||
*/
|
||||
async getResolvedContext(manifestPath, debug = false, forceRefresh = false) {
|
||||
return this.executeTool('dss_get_resolved_context', {
|
||||
manifest_path: manifestPath,
|
||||
debug,
|
||||
force_refresh: forceRefresh
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute browser_get_logs tool
|
||||
*/
|
||||
async getBrowserLogs(level = 'all', limit = 100) {
|
||||
return this.executeTool('browser_get_logs', { level, limit });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute browser_get_errors tool
|
||||
*/
|
||||
async getBrowserErrors(limit = 50) {
|
||||
return this.executeTool('browser_get_errors', { limit });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute browser_accessibility_audit tool
|
||||
*/
|
||||
async runAccessibilityAudit(selector = null) {
|
||||
return this.executeTool('browser_accessibility_audit', { selector });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute browser_performance tool
|
||||
*/
|
||||
async getPerformanceMetrics() {
|
||||
return this.executeTool('browser_performance');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute devtools_screenshot tool
|
||||
*/
|
||||
async takeScreenshot(fullPage = false, selector = null) {
|
||||
return this.executeTool('devtools_screenshot', { full_page: fullPage, selector });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute devtools_query_dom tool
|
||||
*/
|
||||
async queryDOM(selector) {
|
||||
return this.executeTool('devtools_query_dom', { selector });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute devtools_network_requests tool
|
||||
*/
|
||||
async getNetworkRequests(filterUrl = null, limit = 50) {
|
||||
return this.executeTool('devtools_network_requests', {
|
||||
filter_url: filterUrl,
|
||||
limit
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_audit_components tool
|
||||
*/
|
||||
async auditComponents(path) {
|
||||
return this.executeTool('dss_audit_components', { path });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_find_quick_wins tool
|
||||
*/
|
||||
async findQuickWins(path) {
|
||||
return this.executeTool('dss_find_quick_wins', { path });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_get_status tool
|
||||
*/
|
||||
async getDSSStatus(format = 'json') {
|
||||
return this.executeTool('dss_get_status', { format });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute dss_list_themes tool
|
||||
*/
|
||||
async listThemes() {
|
||||
return this.executeTool('dss_list_themes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute browser_dom_snapshot tool
|
||||
*/
|
||||
async getDOMSnapshot() {
|
||||
return this.executeTool('browser_dom_snapshot');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute devtools_console_logs tool
|
||||
*/
|
||||
async getConsoleLogs(level = 'all', limit = 100, clear = false) {
|
||||
return this.executeTool('devtools_console_logs', { level, limit, clear });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token information from Context Compiler
|
||||
*/
|
||||
async getTokens(manifestPath) {
|
||||
return this.getResolvedContext(manifestPath, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear browser console logs
|
||||
*/
|
||||
async clearConsoleLogs() {
|
||||
return this.executeTool('devtools_console_logs', { clear: true, limit: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
const toolBridge = new ToolBridge();
|
||||
|
||||
export default toolBridge;
|
||||
Reference in New Issue
Block a user