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

2466
servers/visual-qa/package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

34
servers/visual-qa/package.json Executable file
View File

@@ -0,0 +1,34 @@
{
"name": "dss-worker",
"version": "0.1.0",
"description": "Design System Server (DSS) - Worker Node",
"main": "dist/index.js",
"type": "module",
"bin": {
"dss": "./dist/cli.js"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts",
"cli": "tsx src/cli.ts"
},
"dependencies": {
"@fastify/static": "^7.0.4",
"cors": "^2.8.5",
"fastify": "^4.24.3",
"figma-api": "^1.5.0",
"fs-extra": "^11.2.0",
"odiff-bin": "^3.0.1",
"playwright": "^1.40.0",
"style-dictionary": "^3.9.1",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/fs-extra": "^11.0.4",
"@types/node": "^20.19.25",
"tsx": "^4.21.0",
"typescript": "^5.3.2"
}
}

View File

@@ -0,0 +1,394 @@
#!/usr/bin/env node
/**
* Design System Server (DSS) - CLI Tool
*
* Commands:
* dss export [projectId] [--output file.json] Export project for backup
* dss import <file.json> Import project from backup
* dss backup [--output dir] Full backup of all data
* dss restore <backup.json> Restore from full backup
* dss health Check server health
*/
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const CONFIG = {
version: "0.1.0",
dataDir: path.resolve(__dirname, "../../../.dss"),
defaultBackupDir: path.resolve(__dirname, "../../../.dss/backups"),
serverUrl: process.env.DSS_URL || "http://localhost:3456",
};
// === UTILITIES ===
function timestamp(): string {
return new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
}
function log(msg: string, type: "info" | "success" | "error" | "warn" = "info"): void {
const colors = {
info: "\x1b[36m",
success: "\x1b[32m",
error: "\x1b[31m",
warn: "\x1b[33m",
};
const reset = "\x1b[0m";
const prefix = {
info: "",
success: "✓",
error: "✗",
warn: "⚠",
};
console.log(`${colors[type]}${prefix[type]}${reset} ${msg}`);
}
function printHelp(): void {
console.log(`
Design System Server (DSS) CLI v${CONFIG.version}
Usage: dss <command> [options]
Commands:
export [id] Export a project (or all if no id given)
--output, -o <file> Output file path (default: project-name.dss.json)
--stdout Output to stdout instead of file
import <file> Import a project from backup file
--force, -f Overwrite if project exists
backup Create full backup of all projects
--output, -o <dir> Output directory (default: .dss/backups/)
restore <file> Restore from a full backup
--force, -f Overwrite existing data
health Check server health status
--json Output as JSON
list List all projects
Examples:
dss export my-project-id -o ./backup.json
dss import ./backup.json
dss backup
dss restore ./dss-backup-2024.json
dss health
`);
}
// === DATA ACCESS ===
interface Project {
id: string;
name: string;
figmaFileKey?: string;
status: string;
tokens: unknown[];
components: unknown[];
styles: unknown[];
createdAt: string;
updatedAt: string;
}
interface DataFile {
projects: Project[];
teams: unknown[];
activities: unknown[];
}
function getDataPath(): string {
return path.join(CONFIG.dataDir, "data.json");
}
function loadData(): DataFile {
const dataPath = getDataPath();
if (!fs.existsSync(dataPath)) {
return { projects: [], teams: [], activities: [] };
}
return fs.readJsonSync(dataPath);
}
function saveData(data: DataFile): void {
fs.ensureDirSync(CONFIG.dataDir);
fs.writeJsonSync(getDataPath(), data, { spaces: 2 });
}
// === COMMANDS ===
async function cmdExport(args: string[]): Promise<void> {
const outputIdx = args.findIndex((a) => a === "-o" || a === "--output");
const outputFile = outputIdx >= 0 ? args[outputIdx + 1] : undefined;
const toStdout = args.includes("--stdout");
// Filter out -o and --output and their values to find projectId
const filteredArgs = args.filter((a, i) => {
if (a === "-o" || a === "--output") return false;
if (i > 0 && (args[i - 1] === "-o" || args[i - 1] === "--output")) return false;
if (a.startsWith("-")) return false;
return true;
});
// Join remaining args to support project names with spaces
const projectId = filteredArgs.length > 0 ? filteredArgs.join(" ") : undefined;
const data = loadData();
if (projectId) {
// Export single project
const project = data.projects.find((p) => p.id === projectId || p.name === projectId);
if (!project) {
log(`Project not found: ${projectId}`, "error");
process.exit(1);
}
const bundle = {
version: CONFIG.version,
exportedAt: new Date().toISOString(),
project,
};
if (toStdout) {
console.log(JSON.stringify(bundle, null, 2));
} else {
const filename = outputFile || `${project.name.replace(/\s+/g, "-").toLowerCase()}.dss.json`;
fs.writeJsonSync(filename, bundle, { spaces: 2 });
log(`Exported to ${filename}`, "success");
}
} else {
// Export all projects
const bundle = {
version: CONFIG.version,
exportedAt: new Date().toISOString(),
projects: data.projects,
teams: data.teams,
};
if (toStdout) {
console.log(JSON.stringify(bundle, null, 2));
} else {
const filename = outputFile || `dss-export-${timestamp()}.json`;
fs.writeJsonSync(filename, bundle, { spaces: 2 });
log(`Exported ${data.projects.length} projects to ${filename}`, "success");
}
}
}
async function cmdImport(args: string[]): Promise<void> {
const file = args.find((a) => !a.startsWith("-"));
const force = args.includes("-f") || args.includes("--force");
if (!file) {
log("Please specify a file to import", "error");
process.exit(1);
}
if (!fs.existsSync(file)) {
log(`File not found: ${file}`, "error");
process.exit(1);
}
const bundle = fs.readJsonSync(file);
const data = loadData();
if (bundle.project) {
// Single project import
const existing = data.projects.find((p) => p.name === bundle.project.name);
if (existing && !force) {
log(`Project "${bundle.project.name}" already exists. Use --force to overwrite.`, "warn");
process.exit(1);
}
if (existing) {
Object.assign(existing, bundle.project, { updatedAt: new Date().toISOString() });
log(`Updated existing project: ${bundle.project.name}`, "success");
} else {
const newProject = {
...bundle.project,
id: `proj-${Date.now()}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
data.projects.push(newProject);
log(`Imported project: ${bundle.project.name}`, "success");
}
} else if (bundle.projects) {
// Multi-project import
let imported = 0;
let updated = 0;
for (const project of bundle.projects) {
const existing = data.projects.find((p) => p.name === project.name);
if (existing) {
if (force) {
Object.assign(existing, project, { updatedAt: new Date().toISOString() });
updated++;
}
} else {
data.projects.push({
...project,
id: `proj-${Date.now()}-${imported}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
imported++;
}
}
log(`Imported ${imported} new projects, updated ${updated}`, "success");
}
saveData(data);
}
async function cmdBackup(args: string[]): Promise<void> {
const outputIdx = args.findIndex((a) => a === "-o" || a === "--output");
const outputDir = outputIdx >= 0 ? args[outputIdx + 1] : CONFIG.defaultBackupDir;
fs.ensureDirSync(outputDir);
const data = loadData();
const backup = {
version: CONFIG.version,
createdAt: new Date().toISOString(),
data,
};
const filename = path.join(outputDir, `dss-backup-${timestamp()}.json`);
fs.writeJsonSync(filename, backup, { spaces: 2 });
log(`Full backup created: ${filename}`, "success");
log(` Projects: ${data.projects.length}`, "info");
log(` Teams: ${data.teams.length}`, "info");
log(` Activities: ${data.activities.length}`, "info");
}
async function cmdRestore(args: string[]): Promise<void> {
const file = args.find((a) => !a.startsWith("-"));
const force = args.includes("-f") || args.includes("--force");
if (!file) {
log("Please specify a backup file to restore", "error");
process.exit(1);
}
if (!fs.existsSync(file)) {
log(`File not found: ${file}`, "error");
process.exit(1);
}
const existingData = loadData();
if (existingData.projects.length > 0 && !force) {
log("Data already exists. Use --force to overwrite.", "warn");
process.exit(1);
}
const backup = fs.readJsonSync(file);
if (!backup.data && !backup.projects) {
log("Invalid backup file format", "error");
process.exit(1);
}
const data = backup.data || { projects: backup.projects, teams: backup.teams || [], activities: [] };
saveData(data);
log(`Restored from backup: ${file}`, "success");
log(` Projects: ${data.projects.length}`, "info");
log(` Teams: ${data.teams.length}`, "info");
}
async function cmdHealth(args: string[]): Promise<void> {
const asJson = args.includes("--json");
try {
const response = await fetch(`${CONFIG.serverUrl}/health`);
const health = (await response.json()) as { status: string; version: string; uptime: number };
if (asJson) {
console.log(JSON.stringify(health, null, 2));
} else {
log(`Server Status: ${health.status}`, health.status === "ok" ? "success" : "error");
log(`Version: ${health.version}`, "info");
log(`Uptime: ${health.uptime}s`, "info");
}
} catch {
if (asJson) {
console.log(JSON.stringify({ status: "offline", error: "Could not connect to server" }));
} else {
log("Server is offline or unreachable", "error");
log(`Tried: ${CONFIG.serverUrl}/health`, "info");
}
process.exit(1);
}
}
async function cmdList(): Promise<void> {
const data = loadData();
if (data.projects.length === 0) {
log("No projects found", "info");
return;
}
console.log("\nProjects:");
console.log("─".repeat(60));
for (const project of data.projects) {
const tokens = project.tokens?.length || 0;
const components = project.components?.length || 0;
console.log(` ${project.id}`);
console.log(` Name: ${project.name}`);
console.log(` Status: ${project.status}`);
console.log(` Tokens: ${tokens}, Components: ${components}`);
console.log(` Updated: ${project.updatedAt}`);
console.log();
}
}
// === MAIN ===
async function main(): Promise<void> {
const args = process.argv.slice(2);
const command = args[0];
const cmdArgs = args.slice(1);
if (!command || command === "help" || command === "--help" || command === "-h") {
printHelp();
process.exit(0);
}
switch (command) {
case "export":
await cmdExport(cmdArgs);
break;
case "import":
await cmdImport(cmdArgs);
break;
case "backup":
await cmdBackup(cmdArgs);
break;
case "restore":
await cmdRestore(cmdArgs);
break;
case "health":
await cmdHealth(cmdArgs);
break;
case "list":
case "ls":
await cmdList();
break;
default:
log(`Unknown command: ${command}`, "error");
printHelp();
process.exit(1);
}
}
main().catch((err) => {
log(err.message, "error");
process.exit(1);
});

672
servers/visual-qa/src/index.ts Executable file
View File

@@ -0,0 +1,672 @@
/**
* Design System Server (DSS) - Worker Node
*
* A fast, deterministic API server for design system management.
*
* Features:
* - Smart port detection (auto-finds available port)
* - Project import/export for git-friendly backups
* - Deterministic responses (no random behavior)
* - Fast startup with minimal blocking
*/
import Fastify from "fastify";
import fastifyStatic from "@fastify/static";
import { Api } from "figma-api";
import { compare } from "odiff-bin";
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
import { createServer } from "net";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// === CONFIGURATION ===
const CONFIG = {
name: "dss-worker",
version: "0.1.0",
defaultPort: 3456,
portRange: { min: 3456, max: 3466 },
dataDir: path.resolve(__dirname, "../../../.dss"),
adminUiPath: path.resolve(__dirname, "../../../admin-ui"),
};
// === PORT DETECTION ===
async function isPortAvailable(port: number): Promise<boolean> {
return new Promise((resolve) => {
const server = createServer();
server.once("error", () => resolve(false));
server.once("listening", () => {
server.close();
resolve(true);
});
server.listen(port, "0.0.0.0");
});
}
async function findAvailablePort(): Promise<number> {
// Check if PORT env is set - use it directly (fail if unavailable)
if (process.env.PORT) {
const envPort = parseInt(process.env.PORT);
if (await isPortAvailable(envPort)) {
return envPort;
}
console.error(`[DSS] Port ${envPort} (from PORT env) is not available`);
process.exit(1);
}
// Auto-detect available port in range
for (let port = CONFIG.portRange.min; port <= CONFIG.portRange.max; port++) {
if (await isPortAvailable(port)) {
return port;
}
}
console.error(`[DSS] No available ports in range ${CONFIG.portRange.min}-${CONFIG.portRange.max}`);
process.exit(1);
}
// === DATA TYPES ===
interface Project {
id: string;
name: string;
figmaFileKey?: string;
status: "active" | "syncing" | "error" | "pending";
lastSync?: string;
tokens: Token[];
components: Component[];
styles: Style[];
createdAt: string;
updatedAt: string;
}
interface Token {
name: string;
value: string;
type: "color" | "spacing" | "typography" | "shadow" | "border" | "other";
category: string;
description?: string;
}
interface Component {
key: string;
name: string;
description?: string;
variants?: string[];
properties?: Record<string, unknown>;
}
interface Style {
key: string;
name: string;
type: "TEXT" | "FILL" | "EFFECT" | "GRID";
properties: Record<string, unknown>;
}
interface Team {
id: string;
name: string;
description?: string;
members: string[];
projects: string[];
createdAt: string;
}
interface Activity {
id: string;
type: string;
message: string;
status: "success" | "warning" | "error" | "info";
timestamp: string;
projectId?: string;
}
interface ExportBundle {
version: string;
exportedAt: string;
project: Project;
teams?: Team[];
}
// === DATA STORE ===
class DataStore {
private projects: Map<string, Project> = new Map();
private teams: Map<string, Team> = new Map();
private activities: Activity[] = [];
private dataFile: string;
constructor() {
this.dataFile = path.join(CONFIG.dataDir, "data.json");
this.loadFromDisk();
}
private loadFromDisk(): void {
try {
if (fs.existsSync(this.dataFile)) {
const data = fs.readJsonSync(this.dataFile);
if (data.projects) {
for (const p of data.projects) {
this.projects.set(p.id, p);
}
}
if (data.teams) {
for (const t of data.teams) {
this.teams.set(t.id, t);
}
}
if (data.activities) {
this.activities = data.activities.slice(0, 100);
}
}
} catch {
// Start fresh if data is corrupted
console.log("[DSS] Starting with empty data store");
}
}
private saveToDisk(): void {
try {
fs.ensureDirSync(CONFIG.dataDir);
fs.writeJsonSync(
this.dataFile,
{
projects: Array.from(this.projects.values()),
teams: Array.from(this.teams.values()),
activities: this.activities.slice(0, 100),
},
{ spaces: 2 }
);
} catch (e) {
console.error("[DSS] Failed to save data:", e);
}
}
// Projects
getProjects(): Project[] {
return Array.from(this.projects.values());
}
getProject(id: string): Project | undefined {
return this.projects.get(id);
}
createProject(data: Partial<Project>): Project {
const id = `proj-${Date.now()}`;
const project: Project = {
id,
name: data.name || "Untitled Project",
figmaFileKey: data.figmaFileKey,
status: "pending",
tokens: data.tokens || [],
components: data.components || [],
styles: data.styles || [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
this.projects.set(id, project);
this.addActivity("create", `Created project: ${project.name}`, "success", id);
this.saveToDisk();
return project;
}
updateProject(id: string, data: Partial<Project>): Project | null {
const project = this.projects.get(id);
if (!project) return null;
const updated = { ...project, ...data, updatedAt: new Date().toISOString() };
this.projects.set(id, updated);
this.saveToDisk();
return updated;
}
deleteProject(id: string): boolean {
const project = this.projects.get(id);
if (!project) return false;
this.projects.delete(id);
this.addActivity("delete", `Deleted project: ${project.name}`, "info");
this.saveToDisk();
return true;
}
// Import/Export
exportProject(id: string): ExportBundle | null {
const project = this.projects.get(id);
if (!project) return null;
return {
version: CONFIG.version,
exportedAt: new Date().toISOString(),
project,
};
}
importProject(bundle: ExportBundle): Project {
const project = {
...bundle.project,
id: `proj-${Date.now()}`, // New ID to avoid conflicts
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
this.projects.set(project.id, project);
this.addActivity("import", `Imported project: ${project.name}`, "success", project.id);
this.saveToDisk();
return project;
}
// Teams
getTeams(): Team[] {
return Array.from(this.teams.values());
}
getTeam(id: string): Team | undefined {
return this.teams.get(id);
}
createTeam(data: Partial<Team>): Team {
const id = `team-${Date.now()}`;
const team: Team = {
id,
name: data.name || "New Team",
description: data.description,
members: data.members || [],
projects: data.projects || [],
createdAt: new Date().toISOString(),
};
this.teams.set(id, team);
this.saveToDisk();
return team;
}
// Activity
addActivity(type: string, message: string, status: Activity["status"], projectId?: string): void {
this.activities.unshift({
id: `act-${Date.now()}`,
type,
message,
status,
timestamp: new Date().toISOString(),
projectId,
});
if (this.activities.length > 100) {
this.activities = this.activities.slice(0, 100);
}
// Don't save on every activity - batch writes
}
getActivities(limit = 20): Activity[] {
return this.activities.slice(0, limit);
}
}
// === SERVER SETUP ===
const fastify = Fastify({
logger: {
level: process.env.LOG_LEVEL || "info",
},
});
const store = new DataStore();
// Static files
fastify.register(fastifyStatic, {
root: CONFIG.adminUiPath,
prefix: "/admin-ui/",
});
// CORS
fastify.addHook("onRequest", (request, reply, done) => {
reply.header("Access-Control-Allow-Origin", "*");
reply.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
reply.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (request.method === "OPTIONS") {
reply.status(204).send();
return;
}
done();
});
// === ROUTES ===
// Health
fastify.get("/health", async () => ({
status: "ok",
name: CONFIG.name,
version: CONFIG.version,
uptime: Math.floor(process.uptime()),
timestamp: new Date().toISOString(),
}));
// Root redirect
fastify.get("/", async (_, reply) => {
reply.redirect("/admin-ui/index.html");
});
fastify.get("/admin", async (_, reply) => {
reply.redirect("/admin-ui/index.html");
});
// === PROJECTS ===
fastify.get("/api/projects", async () => store.getProjects());
fastify.get<{ Params: { id: string } }>("/api/projects/:id", async (request, reply) => {
const project = store.getProject(request.params.id);
if (!project) return reply.status(404).send({ error: "Project not found" });
return project;
});
fastify.post("/api/projects", async (request) => {
return store.createProject(request.body as Partial<Project>);
});
fastify.put<{ Params: { id: string } }>("/api/projects/:id", async (request, reply) => {
const project = store.updateProject(request.params.id, request.body as Partial<Project>);
if (!project) return reply.status(404).send({ error: "Project not found" });
return project;
});
fastify.delete<{ Params: { id: string } }>("/api/projects/:id", async (request, reply) => {
if (!store.deleteProject(request.params.id)) {
return reply.status(404).send({ error: "Project not found" });
}
return { success: true };
});
// === IMPORT/EXPORT ===
fastify.get<{ Params: { id: string } }>("/api/projects/:id/export", async (request, reply) => {
const bundle = store.exportProject(request.params.id);
if (!bundle) return reply.status(404).send({ error: "Project not found" });
reply.header("Content-Type", "application/json");
reply.header("Content-Disposition", `attachment; filename="${bundle.project.name.replace(/\s+/g, "-")}.dss.json"`);
return bundle;
});
fastify.post("/api/projects/import", async (request, reply) => {
const bundle = request.body as ExportBundle;
if (!bundle.version || !bundle.project) {
return reply.status(400).send({ error: "Invalid export bundle" });
}
const project = store.importProject(bundle);
return { success: true, project };
});
// Export all projects (full backup)
fastify.get("/api/export", async (_, reply) => {
const projects = store.getProjects();
const teams = store.getTeams();
const backup = {
version: CONFIG.version,
exportedAt: new Date().toISOString(),
projects,
teams,
};
reply.header("Content-Type", "application/json");
reply.header("Content-Disposition", `attachment; filename="dss-backup-${Date.now()}.json"`);
return backup;
});
// === DISCOVERY ===
fastify.get("/api/discovery", async () => {
const projects = store.getProjects();
const totalTokens = projects.reduce((sum, p) => sum + (p.tokens?.length || 0), 0);
const totalComponents = projects.reduce((sum, p) => sum + (p.components?.length || 0), 0);
return {
project: {
types: ["design-system"],
frameworks: ["web-components", "css"],
},
files: {
total: projects.length,
tokens: totalTokens,
components: totalComponents,
},
health: {
score: projects.length > 0 ? 85 : 50,
grade: projects.length > 0 ? "B+" : "C",
},
};
});
fastify.get("/api/discovery/stats", async () => {
const projects = store.getProjects();
return {
projects: { total: projects.length, active: projects.filter((p) => p.status === "active").length },
tokens: { total: projects.reduce((sum, p) => sum + (p.tokens?.length || 0), 0) },
components: { total: projects.reduce((sum, p) => sum + (p.components?.length || 0), 0) },
};
});
fastify.get("/api/discovery/activity", async () => {
return { items: store.getActivities() };
});
// === TOKENS & COMPONENTS ===
fastify.get("/api/tokens", async () => {
const projects = store.getProjects();
return projects.flatMap((p) => p.tokens || []);
});
fastify.get("/api/components", async () => {
const projects = store.getProjects();
return projects.flatMap((p) => p.components || []);
});
// === TEAMS ===
fastify.get("/api/teams", async () => store.getTeams());
fastify.get<{ Params: { id: string } }>("/api/teams/:id", async (request, reply) => {
const team = store.getTeam(request.params.id);
if (!team) return reply.status(404).send({ error: "Team not found" });
return team;
});
fastify.post("/api/teams", async (request) => {
return store.createTeam(request.body as Partial<Team>);
});
// === FIGMA INTEGRATION ===
fastify.post("/api/figma/extract-variables", async (request) => {
const { fileKey, format = "css" } = request.body as { fileKey: string; format?: string };
const project = store.getProjects().find((p) => p.figmaFileKey === fileKey);
// Return existing tokens or mock data
const tokens: Token[] = project?.tokens?.length
? project.tokens
: [
{ name: "primary", value: "oklch(0.7 0.15 250)", type: "color", category: "colors" },
{ name: "secondary", value: "oklch(0.6 0.05 260)", type: "color", category: "colors" },
{ name: "background", value: "oklch(0.15 0.02 260)", type: "color", category: "colors" },
{ name: "foreground", value: "oklch(0.95 0.01 260)", type: "color", category: "colors" },
];
store.addActivity("extract", `Extracted ${tokens.length} tokens`, "success");
return { success: true, fileKey, format, tokens, count: tokens.length };
});
fastify.post("/api/figma/extract-components", async (request) => {
const { fileKey } = request.body as { fileKey: string };
const project = store.getProjects().find((p) => p.figmaFileKey === fileKey);
const components: Component[] = project?.components?.length
? project.components
: [
{ key: "btn-1", name: "Button", description: "Interactive button", variants: ["primary", "secondary"] },
{ key: "card-1", name: "Card", description: "Content container", variants: ["default", "bordered"] },
];
store.addActivity("extract", `Extracted ${components.length} components`, "success");
return { success: true, fileKey, components, count: components.length };
});
fastify.post("/api/figma/sync-tokens", async (request) => {
const { fileKey, targetPath } = request.body as { fileKey: string; targetPath: string };
const project = store.getProjects().find((p) => p.figmaFileKey === fileKey);
const tokenCount = project?.tokens?.length || 0;
store.addActivity("sync", `Synced ${tokenCount} tokens to ${targetPath}`, "success");
return { success: true, tokens_synced: tokenCount, target_path: targetPath };
});
fastify.post("/api/figma/visual-diff", async (request) => {
const { fileKey } = request.body as { fileKey: string };
// Deterministic response - no random
return {
success: true,
changes_detected: false,
summary: { total_components: 4, unchanged: 4, changed: 0 },
changes: [],
};
});
fastify.post("/api/figma/validate", async () => {
return {
success: true,
valid: true,
summary: { total: 4, valid: 4, errors: 0, warnings: 0 },
issues: [],
};
});
fastify.post("/api/figma/generate-code", async (request) => {
const { componentName, framework = "webcomponent" } = request.body as {
fileKey: string;
componentName: string;
framework?: string;
};
let code = "";
const nameLower = componentName.toLowerCase();
if (framework === "webcomponent") {
code = `class Ds${componentName} extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() { this.render(); }
render() {
this.shadowRoot.innerHTML = \`<style>:host { display: inline-flex; }</style><slot></slot>\`;
}
}
customElements.define('ds-${nameLower}', Ds${componentName});`;
} else if (framework === "react") {
code = `export const ${componentName} = ({ children, variant = 'default', ...props }) => (
<div className={\`ds-${nameLower} ds-${nameLower}--\${variant}\`} {...props}>{children}</div>
);`;
} else if (framework === "vue") {
code = `<template><div :class="['ds-${nameLower}', \`ds-${nameLower}--\${variant}\`]"><slot /></div></template>
<script setup>
defineProps({ variant: { type: String, default: 'default' } });
</script>`;
}
return { success: true, component: componentName, framework, code };
});
// Real Figma API
fastify.post("/ingest/figma", async (request, reply) => {
const { fileKey, token } = request.body as { fileKey: string; token?: string };
if (token) {
try {
const api = new Api({ personalAccessToken: token });
const file = await api.getFile(fileKey);
return { success: true, name: file.name, nodes: file.document.children.length };
} catch (e: unknown) {
const message = e instanceof Error ? e.message : "Unknown error";
return reply.status(500).send({ error: message });
}
}
return { success: true, name: "Mock Figma File", nodes: 0, mode: "mock" };
});
// Visual diff with ODiff
fastify.post("/visual-diff", async (request, reply) => {
const { baselinePath, currentPath, diffPath } = request.body as {
baselinePath: string;
currentPath: string;
diffPath: string;
};
try {
const result = await compare(baselinePath, currentPath, diffPath, {
threshold: 0.1,
failOnLayoutDiff: true,
});
if (result.match) {
return { match: true, reason: "exact-match", diffPercentage: 0 };
}
const reason = "reason" in result ? result.reason : "unknown";
const diffPercentage = "diffPercentage" in result ? result.diffPercentage : 0;
return { match: false, reason, diffPercentage };
} catch (e: unknown) {
const message = e instanceof Error ? e.message : "Unknown error";
return reply.status(500).send({ error: message });
}
});
// Activity
fastify.get("/api/activity", async (request) => {
const query = request.query as { limit?: string };
const limit = parseInt(query.limit || "20");
return store.getActivities(limit);
});
// === START ===
async function start() {
const port = await findAvailablePort();
try {
await fastify.listen({ port, host: "0.0.0.0" });
const pad = (s: string | number, len: number) => String(s).padEnd(len);
console.log(`
╔═══════════════════════════════════════════════════════════════╗
║ Design System Server (DSS) v${pad(CONFIG.version, 28)}
╠═══════════════════════════════════════════════════════════════╣
║ Server: http://localhost:${pad(port, 30)}
║ Admin UI: http://localhost:${port}/admin-ui/${pad("", 21)}
╠═══════════════════════════════════════════════════════════════╣
║ Endpoints: ║
║ GET /api/projects List projects ║
║ GET /api/projects/:id/export Export project (backup) ║
║ POST /api/projects/import Import project ║
║ GET /api/export Full backup ║
║ GET /api/tokens List all tokens ║
║ GET /api/components List all components ║
║ POST /api/figma/* Figma operations ║
╚═══════════════════════════════════════════════════════════════╝
`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}
start();

19
servers/visual-qa/tsconfig.json Executable file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}