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:
309
admin-ui/js/core/error-handler.js
Normal file
309
admin-ui/js/core/error-handler.js
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* DSS Error Handler - Immune System Antibodies
|
||||
*
|
||||
* The DSS Organism's immune system uses these antibodies to detect and report threats.
|
||||
* Converts technical errors into human-friendly, actionable treatment plans.
|
||||
* Integrates with the messaging system for structured error reporting.
|
||||
*
|
||||
* Biological Framework: These error messages use organism metaphors to make
|
||||
* issues intuitive. See docs/DSS_ORGANISM_GUIDE.md for the full framework.
|
||||
*
|
||||
* @module error-handler
|
||||
*/
|
||||
|
||||
import { notifyError, ErrorCode } from './messaging.js';
|
||||
|
||||
/**
|
||||
* Error message templates with organism metaphors
|
||||
*
|
||||
* These messages use biological language from the DSS Organism Framework.
|
||||
* Each error is framed as a symptom the immune system detected, with
|
||||
* a diagnosis and treatment plan.
|
||||
*/
|
||||
const errorMessages = {
|
||||
// Figma API Errors - Sensory System Issues
|
||||
figma_403: {
|
||||
title: '🛡️ IMMUNE ALERT: Sensory Input Blocked',
|
||||
message: 'The DSS sensory organs cannot perceive the Figma file. Your access credentials lack permission.',
|
||||
actions: [
|
||||
'Verify your Figma authentication token in Settings (nervous system communication)',
|
||||
'Confirm you have access to this file in Figma (sensory perception)',
|
||||
'Check if the file still exists (organism awareness)',
|
||||
],
|
||||
code: ErrorCode.FIGMA_API_ERROR,
|
||||
},
|
||||
figma_404: {
|
||||
title: '🛡️ IMMUNE ALERT: Sensory Target Lost',
|
||||
message: 'The Figma file the DSS sensory organs were trying to perceive doesn\'t exist or is inaccessible.',
|
||||
actions: [
|
||||
'Double-check your Figma file key in Settings (sensory focus)',
|
||||
'Verify the file hasn\'t been deleted in Figma',
|
||||
'Confirm you have access to the file in Figma (sensory perception)',
|
||||
],
|
||||
code: ErrorCode.FIGMA_API_ERROR,
|
||||
},
|
||||
figma_401: {
|
||||
title: '🔌 NERVOUS SYSTEM ALERT: Authentication Expired',
|
||||
message: 'The DSS nervous system\'s authentication with Figma has failed. Your sensory input token is invalid or expired.',
|
||||
actions: [
|
||||
'Refresh your Figma authentication token in Settings (nervous system repair)',
|
||||
'Get a fresh token from figma.com/settings (Account → Personal Access Tokens)',
|
||||
'Ensure you copied the full token without truncation',
|
||||
],
|
||||
code: ErrorCode.FIGMA_CONNECTION_FAILED,
|
||||
},
|
||||
figma_429: {
|
||||
title: '⚡ METABOLISM ALERT: Sensory Overload',
|
||||
message: 'The DSS is sensing too quickly. Figma\'s rate limits have been triggered.',
|
||||
actions: [
|
||||
'Let the organism rest for 1-2 minutes before sensing again',
|
||||
'Reduce how frequently the sensory system extracts data',
|
||||
],
|
||||
code: ErrorCode.FIGMA_API_ERROR,
|
||||
},
|
||||
figma_500: {
|
||||
title: '🔌 EXTERNAL SYSTEM ALERT: Figma Organism Stressed',
|
||||
message: 'Figma\'s servers are experiencing stress. This is external to DSS.',
|
||||
actions: [
|
||||
'Wait while the external organism recovers',
|
||||
'Check Figma health: status.figma.com',
|
||||
],
|
||||
code: ErrorCode.FIGMA_API_ERROR,
|
||||
},
|
||||
figma_demo: {
|
||||
title: '🛡️ IMMUNE ALERT: Invalid Sensory Configuration',
|
||||
message: 'The sensory organs are configured to look at "demo" which doesn\'t exist in Figma.',
|
||||
actions: [
|
||||
'Update Settings with your real Figma file key (configure sensory input)',
|
||||
'Find your file key in the Figma URL: figma.com/file/[FILE_KEY]/...',
|
||||
'Use the Figma file selector in Settings',
|
||||
],
|
||||
code: ErrorCode.FIGMA_INVALID_KEY,
|
||||
},
|
||||
|
||||
// API Connection Errors - Nervous System / Heart Issues
|
||||
api_network: {
|
||||
title: '❤️ CRITICAL: Heart Not Responding',
|
||||
message: 'The DSS nervous system cannot reach the heart (server). The organism is not responding.',
|
||||
actions: [
|
||||
'Verify the heart is beating: curl http://localhost:3456/health',
|
||||
'Restart the heart: cd tools/api && python3 -m uvicorn server:app --port 3456',
|
||||
'Check your network connection to the organism',
|
||||
],
|
||||
code: ErrorCode.SYSTEM_NETWORK,
|
||||
},
|
||||
api_timeout: {
|
||||
title: '⚡ METABOLISM ALERT: Organism Overloaded',
|
||||
message: 'The DSS organism took too long to respond. The heart may be stressed or metabolism sluggish.',
|
||||
actions: [
|
||||
'Let the organism rest and try again shortly',
|
||||
'Check the heart\'s logs for signs of stress: tail -f /tmp/dss-demo.log',
|
||||
'Reduce metabolic load (try processing smaller batches)',
|
||||
],
|
||||
code: ErrorCode.API_TIMEOUT,
|
||||
},
|
||||
api_500: {
|
||||
title: '🧠 BRAIN ALERT: Critical Processing Error',
|
||||
message: 'The DSS brain encountered a fatal error while processing your request.',
|
||||
actions: [
|
||||
'Examine the brain\'s thoughts in the logs: tail -f /tmp/dss-demo.log',
|
||||
'Retry the operation to see if it recovers',
|
||||
'Report the issue if the organism keeps failing',
|
||||
],
|
||||
code: ErrorCode.API_SERVER_ERROR,
|
||||
},
|
||||
|
||||
// Validation Errors - Immune System / Genetics
|
||||
validation_missing_field: {
|
||||
title: '🛡️ IMMUNE ALERT: DNA Incomplete',
|
||||
message: 'The genetic code (configuration) is missing essential information. The organism cannot proceed.',
|
||||
actions: [
|
||||
'Fill in all fields marked as required (complete the genetic code)',
|
||||
'Ensure each input field contains valid information',
|
||||
],
|
||||
code: ErrorCode.VALIDATION_MISSING_FIELD,
|
||||
},
|
||||
validation_invalid_format: {
|
||||
title: '🛡️ IMMUNE ALERT: Genetic Mutation Detected',
|
||||
message: 'One or more genetic sequences (configuration values) have an invalid format.',
|
||||
actions: [
|
||||
'Verify URLs start with http:// or https:// (correct genetic sequence)',
|
||||
'Check email addresses follow standard format (valid genetic code)',
|
||||
'Ensure file keys contain only letters, numbers, and hyphens (genetic pattern match)',
|
||||
],
|
||||
code: ErrorCode.VALIDATION_INVALID_FORMAT,
|
||||
},
|
||||
|
||||
// Generic fallback
|
||||
unknown: {
|
||||
title: '🧬 ORGANISM ALERT: Unexplained Symptom',
|
||||
message: 'The DSS organism experienced an unexpected problem. The root cause is unclear.',
|
||||
actions: [
|
||||
'Try the operation again (organism may self-heal)',
|
||||
'Refresh if the issue persists (restart vitals)',
|
||||
'Check browser console for clues about the organism\'s condition',
|
||||
],
|
||||
code: ErrorCode.SYSTEM_UNEXPECTED,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse error and return user-friendly message
|
||||
* @param {Error} error - The error to parse
|
||||
* @param {Object} context - Additional context (operation, endpoint, etc.)
|
||||
* @returns {Object} Parsed error with user-friendly message
|
||||
*/
|
||||
export function parseError(error, context = {}) {
|
||||
const errorStr = error.message || String(error);
|
||||
|
||||
// Figma API Errors
|
||||
if (context.service === 'figma' || errorStr.includes('figma.com')) {
|
||||
// Demo file key
|
||||
if (context.fileKey === 'demo' || errorStr.includes('/demo/')) {
|
||||
return errorMessages.figma_demo;
|
||||
}
|
||||
|
||||
// HTTP status codes
|
||||
if (errorStr.includes('403')) {
|
||||
return errorMessages.figma_403;
|
||||
}
|
||||
if (errorStr.includes('404')) {
|
||||
return errorMessages.figma_404;
|
||||
}
|
||||
if (errorStr.includes('401')) {
|
||||
return errorMessages.figma_401;
|
||||
}
|
||||
if (errorStr.includes('429')) {
|
||||
return errorMessages.figma_429;
|
||||
}
|
||||
if (errorStr.includes('500') || errorStr.includes('502') || errorStr.includes('503')) {
|
||||
return errorMessages.figma_500;
|
||||
}
|
||||
}
|
||||
|
||||
// Network Errors
|
||||
if (errorStr.includes('NetworkError') || errorStr.includes('Failed to fetch')) {
|
||||
return errorMessages.api_network;
|
||||
}
|
||||
|
||||
// Timeout Errors
|
||||
if (errorStr.includes('timeout') || errorStr.includes('Timeout')) {
|
||||
return errorMessages.api_timeout;
|
||||
}
|
||||
|
||||
// API Server Errors
|
||||
if (errorStr.includes('500') || errorStr.includes('Internal Server Error')) {
|
||||
return errorMessages.api_500;
|
||||
}
|
||||
|
||||
// Validation Errors
|
||||
if (errorStr.includes('required') || errorStr.includes('missing')) {
|
||||
return errorMessages.validation_missing_field;
|
||||
}
|
||||
if (errorStr.includes('invalid') || errorStr.includes('format')) {
|
||||
return errorMessages.validation_invalid_format;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return errorMessages.unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format user-friendly error message
|
||||
* @param {Object} parsedError - Parsed error from parseError()
|
||||
* @returns {string} Formatted message
|
||||
*/
|
||||
export function formatErrorMessage(parsedError) {
|
||||
let message = `${parsedError.title}\n\n${parsedError.message}`;
|
||||
|
||||
if (parsedError.actions && parsedError.actions.length > 0) {
|
||||
message += '\n\nWhat to do:\n';
|
||||
parsedError.actions.forEach((action, index) => {
|
||||
message += `${index + 1}. ${action}\n`;
|
||||
});
|
||||
}
|
||||
|
||||
return message.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error and notify user with friendly message
|
||||
* @param {Error} error - The error to handle
|
||||
* @param {Object} context - Additional context
|
||||
* @param {string} context.operation - What operation failed (e.g., "extract tokens")
|
||||
* @param {string} context.service - Which service (e.g., "figma")
|
||||
* @param {string} context.fileKey - Figma file key if applicable
|
||||
*/
|
||||
export function handleError(error, context = {}) {
|
||||
const parsed = parseError(error, context);
|
||||
|
||||
// Create user-friendly message
|
||||
let userMessage = parsed.title;
|
||||
|
||||
if (parsed.actions && parsed.actions.length > 0) {
|
||||
userMessage += '. ' + parsed.actions[0]; // Show first action in notification
|
||||
}
|
||||
|
||||
// Notify user with structured error
|
||||
notifyError(userMessage, parsed.code, {
|
||||
operation: context.operation,
|
||||
service: context.service,
|
||||
originalError: error.message,
|
||||
actions: parsed.actions,
|
||||
});
|
||||
|
||||
// Log full details to console for debugging
|
||||
console.group(`🔴 ${parsed.title}`);
|
||||
console.log('Message:', parsed.message);
|
||||
if (parsed.actions) {
|
||||
console.log('Actions:', parsed.actions);
|
||||
}
|
||||
console.log('Context:', context);
|
||||
console.log('Original Error:', error);
|
||||
console.groupEnd();
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try-catch wrapper with automatic error handling
|
||||
* @param {Function} fn - Async function to execute
|
||||
* @param {Object} context - Error context
|
||||
* @returns {Promise<*>} Result of function or null on error
|
||||
*/
|
||||
export async function tryWithErrorHandling(fn, context = {}) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (error) {
|
||||
handleError(error, context);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user-friendly HTTP status message using organism metaphors
|
||||
* @param {number} status - HTTP status code
|
||||
* @returns {string} User-friendly message with biological context
|
||||
*/
|
||||
export function getStatusMessage(status) {
|
||||
const messages = {
|
||||
400: '🛡️ Genetic Code Invalid - the DNA sequence doesn\'t compile',
|
||||
401: '🔐 Authentication Failed - the nervous system can\'t verify identity',
|
||||
403: '🚫 Access Forbidden - immune system rejected this organism',
|
||||
404: '👻 Target Lost - sensory organs can\'t perceive the resource',
|
||||
429: '⚡ Metabolism Overloaded - organism sensing too quickly',
|
||||
500: '🧠 Brain Error - critical neural processing failure',
|
||||
502: '💀 Organism Unresponsive - the heart has stopped beating',
|
||||
503: '🏥 Organism In Recovery - temporarily unable to metabolize requests',
|
||||
};
|
||||
|
||||
return messages[status] || `🔴 Unknown Organism State - HTTP ${status}`;
|
||||
}
|
||||
|
||||
export default {
|
||||
parseError,
|
||||
formatErrorMessage,
|
||||
handleError,
|
||||
tryWithErrorHandling,
|
||||
getStatusMessage,
|
||||
};
|
||||
Reference in New Issue
Block a user