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

103
cli/src/cli.ts Normal file
View File

@@ -0,0 +1,103 @@
#!/usr/bin/env node
/**
* 🧬 DSS CLI - Design System Server Organism Controller
*
* A portable companion for UI developers - think of it as the organism's
* command-line nervous system. Through these commands, you can:
*
* - 🧬 Awaken a new organism (init)
* - 💚 Check the organism's vital signs (status)
* - 🩸 Direct the sensory organs to perceive Figma (extract)
* - 🔄 Circulate extracted nutrients (sync)
* - ⚙️ Adjust the organism's behavior (config)
* - 🧠 Birth a conscious instance (start)
*
* Framework: DSS Organism Framework
*/
import { Command } from 'commander';
import chalk from 'chalk';
import { initCommand } from './commands/init.js';
import { startCommand } from './commands/start.js';
import { syncCommand } from './commands/sync.js';
import { extractCommand } from './commands/extract.js';
import { configCommand } from './commands/config.js';
import { statusCommand } from './commands/status.js';
import { stopCommand } from './commands/stop.js';
const program = new Command();
program
.name('dss')
.description('🧬 Design System Server - Organism Controller for UI Developers')
.version('0.1.0');
// Init command - setup DSS in a project
program
.command('init')
.description('🧬 ORGANISM GENESIS - Create a new design system organism in your project')
.option('-f, --figma-key <key>', 'Link to Figma genetic blueprint')
.option('-t, --figma-token <token>', 'Figma sensory organ connection token')
.action(initCommand);
// Start command - start the DSS server
program
.command('start')
.description('💚 ORGANISM AWAKENING - Bring the design system organism to life')
.option('-p, --port <port>', 'Neural pathway port', '3456')
.option('-d, --dev', 'Live consciousness mode with hot-reload')
.option('--no-open', 'Do not open sensory interface')
.action(startCommand);
// Sync command - sync tokens from Figma
program
.command('sync')
.description('🩸 NUTRIENT CIRCULATION - Distribute extracted tokens through the codebase')
.option('-f, --format <format>', 'Nutrient format: css, scss, json, ts', 'css')
.option('-o, --output <path>', 'Circulation destination')
.option('--file-key <key>', 'Figma file key (overrides config)')
.action(syncCommand);
// Extract command - extract components or tokens
program
.command('extract <type>')
.description('👁️ SENSORY PERCEPTION - Direct organism eyes to perceive Figma designs')
.option('-f, --format <format>', 'Perception output format', 'json')
.option('-o, --output <path>', 'Memory storage location')
.option('--file-key <key>', 'Figma file key')
.action(extractCommand);
// Config command - manage configuration
program
.command('config')
.description('⚙️ ENDOCRINE ADJUSTMENT - Configure organism behavior and preferences')
.option('--set <key=value>', 'Set organism hormone value')
.option('--get <key>', 'Read organism hormone value')
.option('--list', 'View all hormones')
.action(configCommand);
// Stop command - stop the server
program
.command('stop')
.description('😴 ORGANISM REST - Put the design system organism into sleep mode')
.action(stopCommand);
// Status command - check DSS status
program
.command('status')
.description('🏥 VITAL SIGNS CHECK - Monitor organism health and configuration')
.action(statusCommand);
// Parse arguments
program.parse();
// Show help if no command provided
if (!process.argv.slice(2).length) {
console.log(chalk.blue(`
╔═══════════════════════════════════════════════════════════════╗
${chalk.bold('DSS')} - Design System Server ║
║ UI Developer Companion ║
╚═══════════════════════════════════════════════════════════════╝
`));
program.outputHelp();
}

138
cli/src/commands/config.ts Normal file
View File

@@ -0,0 +1,138 @@
/**
* DSS Config Command
*
* Manage DSS configuration.
*/
import chalk from 'chalk';
import {
getConfig,
loadProjectConfig,
saveProjectConfig,
setGlobalConfig,
getGlobalConfig,
listGlobalConfig,
hasProjectConfig,
} from '../lib/config.js';
interface ConfigOptions {
set?: string;
get?: string;
list?: boolean;
}
export async function configCommand(options: ConfigOptions): Promise<void> {
if (options.set) {
await setConfig(options.set);
} else if (options.get) {
await getConfigValue(options.get);
} else if (options.list) {
await listConfig();
} else {
await listConfig();
}
}
async function setConfig(keyValue: string): Promise<void> {
const [key, ...valueParts] = keyValue.split('=');
const value = valueParts.join('=');
if (!key || value === undefined) {
console.log(chalk.red(' Invalid format. Use: --set key=value'));
process.exit(1);
}
// Determine if this is a global or project config
const globalKeys = ['figmaToken', 'defaultPort', 'defaultFormat'];
const projectKeys = ['figmaFileKey', 'port', 'outputDir', 'tokenFormat', 'componentFramework'];
if (globalKeys.includes(key)) {
// Global config
const parsedValue = parseValue(value);
setGlobalConfig(key, parsedValue as string | number);
console.log(chalk.green(` Set global config: ${key}`));
console.log(chalk.dim(` Value: ${key === 'figmaToken' ? '***hidden***' : value}`));
} else if (projectKeys.includes(key)) {
// Project config
if (!hasProjectConfig()) {
console.log(chalk.yellow(' No project config found. Run: dss init'));
process.exit(1);
}
const config = loadProjectConfig();
(config as Record<string, unknown>)[key] = parseValue(value);
saveProjectConfig(config);
console.log(chalk.green(` Set project config: ${key}`));
console.log(chalk.dim(` Value: ${value}`));
} else {
console.log(chalk.yellow(` Unknown config key: ${key}`));
console.log('');
console.log(chalk.dim(' Global keys: figmaToken, defaultPort, defaultFormat'));
console.log(chalk.dim(' Project keys: figmaFileKey, port, outputDir, tokenFormat, componentFramework'));
}
}
async function getConfigValue(key: string): Promise<void> {
const config = getConfig();
const value = (config as Record<string, unknown>)[key];
if (value === undefined) {
// Try global config
const globalValue = getGlobalConfig(key);
if (globalValue !== undefined) {
console.log(chalk.dim(` ${key} (global):`), key === 'figmaToken' ? '***hidden***' : String(globalValue));
} else {
console.log(chalk.yellow(` Config key not found: ${key}`));
}
} else {
console.log(chalk.dim(` ${key}:`), key === 'figmaToken' ? '***hidden***' : String(value));
}
}
async function listConfig(): Promise<void> {
console.log('');
console.log(chalk.blue(' DSS Configuration'));
console.log(chalk.dim(' ─────────────────'));
console.log('');
// Project config
if (hasProjectConfig()) {
console.log(chalk.green(' Project Config:'));
const projectConfig = loadProjectConfig();
Object.entries(projectConfig).forEach(([key, value]) => {
console.log(chalk.dim(` ${key}:`), String(value));
});
} else {
console.log(chalk.yellow(' No project config (run: dss init)'));
}
console.log('');
// Global config
console.log(chalk.green(' Global Config:'));
const globalConf = listGlobalConfig();
Object.entries(globalConf).forEach(([key, value]) => {
const displayValue = key === 'figmaToken' ? '***hidden***' : String(value);
console.log(chalk.dim(` ${key}:`), displayValue);
});
console.log('');
// Merged config
console.log(chalk.green(' Effective Config:'));
const merged = getConfig();
Object.entries(merged).forEach(([key, value]) => {
const displayValue = key === 'figmaToken' ? (value ? '***configured***' : 'not set') : String(value);
console.log(chalk.dim(` ${key}:`), displayValue);
});
console.log('');
}
function parseValue(value: string): string | number | boolean {
if (value === 'true') return true;
if (value === 'false') return false;
if (!isNaN(Number(value))) return Number(value);
return value;
}

146
cli/src/commands/extract.ts Normal file
View File

@@ -0,0 +1,146 @@
/**
* DSS Extract Command
*
* Extract tokens or components from Figma.
*/
import chalk from 'chalk';
import ora from 'ora';
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import { getConfig, getProjectRoot } from '../lib/config.js';
import { getApiClient } from '../lib/api.js';
import { isServerRunning } from '../lib/server.js';
interface ExtractOptions {
format: string;
output?: string;
fileKey?: string;
}
export async function extractCommand(
type: string,
options: ExtractOptions
): Promise<void> {
const validTypes = ['tokens', 'components', 'styles', 'all'];
if (!validTypes.includes(type)) {
console.log(chalk.red(` Invalid type: ${type}`));
console.log(chalk.dim(` Valid types: ${validTypes.join(', ')}`));
process.exit(1);
}
const config = getConfig();
const cwd = getProjectRoot();
// Check if server is running
if (!isServerRunning(cwd)) {
console.log(chalk.yellow(' DSS server is not running'));
console.log(chalk.dim(' Start it with: dss start'));
process.exit(1);
}
const fileKey = options.fileKey || config.figmaFileKey;
if (!fileKey) {
console.log(chalk.red(' No Figma file key configured'));
console.log(chalk.dim(' Set it with: dss config --set figmaFileKey=YOUR_KEY'));
process.exit(1);
}
const outputDir = options.output || join(cwd, '.dss', 'output');
if (!existsSync(outputDir)) {
mkdirSync(outputDir, { recursive: true });
}
const api = getApiClient({ port: config.port });
if (type === 'tokens' || type === 'all') {
await extractTokens(api, fileKey, options.format, outputDir);
}
if (type === 'components' || type === 'all') {
await extractComponents(api, fileKey, outputDir);
}
if (type === 'styles' || type === 'all') {
await extractStyles(api, fileKey, outputDir);
}
}
async function extractTokens(
api: ReturnType<typeof getApiClient>,
fileKey: string,
format: string,
outputDir: string
): Promise<void> {
const spinner = ora('Extracting tokens...').start();
try {
const result = await api.extractTokens(fileKey, format || 'json');
const filename = format === 'css' ? 'tokens.css' :
format === 'scss' ? '_tokens.scss' :
format === 'ts' ? 'tokens.ts' : 'tokens.json';
const outputPath = join(outputDir, filename);
writeFileSync(outputPath, result.formatted_output);
spinner.succeed(`Extracted ${result.tokens_count} tokens`);
console.log(chalk.dim(` Output: ${outputPath}`));
} catch (error) {
spinner.fail('Failed to extract tokens');
console.error(chalk.red(` ${(error as Error).message}`));
}
}
async function extractComponents(
api: ReturnType<typeof getApiClient>,
fileKey: string,
outputDir: string
): Promise<void> {
const spinner = ora('Extracting components...').start();
try {
const result = await api.extractComponents(fileKey);
const outputPath = join(outputDir, 'components.json');
writeFileSync(outputPath, JSON.stringify(result.components, null, 2));
spinner.succeed(`Extracted ${result.components_count} components`);
console.log(chalk.dim(` Output: ${outputPath}`));
// Show component summary
console.log('');
result.components.forEach(comp => {
console.log(chalk.dim(` - ${comp.name}`));
if (comp.variants?.length) {
console.log(chalk.dim(` Variants: ${comp.variants.join(', ')}`));
}
});
} catch (error) {
spinner.fail('Failed to extract components');
console.error(chalk.red(` ${(error as Error).message}`));
}
}
async function extractStyles(
api: ReturnType<typeof getApiClient>,
fileKey: string,
outputDir: string
): Promise<void> {
const spinner = ora('Extracting styles...').start();
try {
// Note: This would need a corresponding API endpoint
// For now, we'll extract tokens which include style information
const result = await api.extractTokens(fileKey, 'json');
const outputPath = join(outputDir, 'styles.json');
writeFileSync(outputPath, JSON.stringify(result.tokens, null, 2));
spinner.succeed(`Extracted styles`);
console.log(chalk.dim(` Output: ${outputPath}`));
} catch (error) {
spinner.fail('Failed to extract styles');
console.error(chalk.red(` ${(error as Error).message}`));
}
}

107
cli/src/commands/init.ts Normal file
View File

@@ -0,0 +1,107 @@
/**
* DSS Init Command
*
* Initialize DSS in the current project.
*/
import chalk from 'chalk';
import ora from 'ora';
import { existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import {
getProjectRoot,
hasProjectConfig,
saveProjectConfig,
setGlobalConfig,
type DSSConfig,
} from '../lib/config.js';
interface InitOptions {
figmaKey?: string;
figmaToken?: string;
}
export async function initCommand(options: InitOptions): Promise<void> {
const spinner = ora('Initializing DSS...').start();
try {
const projectRoot = getProjectRoot();
const dssDir = join(projectRoot, '.dss');
// Check if already initialized
if (hasProjectConfig()) {
spinner.warn('DSS is already initialized in this project');
console.log(chalk.dim(` Config: ${join(dssDir, 'config.json')}`));
return;
}
// Create .dss directory
if (!existsSync(dssDir)) {
mkdirSync(dssDir, { recursive: true });
}
// Create output directory
const outputDir = join(dssDir, 'output');
if (!existsSync(outputDir)) {
mkdirSync(outputDir, { recursive: true });
}
// Build config
const config: DSSConfig = {
port: 3456,
outputDir: '.dss/output',
tokenFormat: 'css',
componentFramework: 'react',
};
if (options.figmaKey) {
config.figmaFileKey = options.figmaKey;
}
// Save Figma token globally (not in project config for security)
if (options.figmaToken) {
setGlobalConfig('figmaToken', options.figmaToken);
spinner.info('Figma token saved to global config');
}
// Save project config
saveProjectConfig(config);
spinner.succeed('DSS initialized successfully!');
console.log('');
console.log(chalk.green(' Created:'));
console.log(chalk.dim(` .dss/config.json`));
console.log(chalk.dim(` .dss/output/`));
console.log('');
// Next steps
console.log(chalk.blue(' Next steps:'));
if (!options.figmaToken) {
console.log(chalk.dim(' 1. Set your Figma token:'));
console.log(chalk.white(' dss config --set figmaToken=figd_xxxxx'));
}
if (!options.figmaKey) {
console.log(chalk.dim(` ${options.figmaToken ? '1' : '2'}. Set your Figma file key:`));
console.log(chalk.white(' dss config --set figmaFileKey=abc123'));
}
console.log(chalk.dim(` ${options.figmaToken && options.figmaKey ? '1' : '3'}. Start the server:`));
console.log(chalk.white(' dss start'));
console.log('');
// Add to .gitignore if exists
const gitignorePath = join(projectRoot, '.gitignore');
if (existsSync(gitignorePath)) {
const { readFileSync, appendFileSync } = await import('fs');
const gitignore = readFileSync(gitignorePath, 'utf-8');
if (!gitignore.includes('.dss/')) {
appendFileSync(gitignorePath, '\n# DSS\n.dss/\n');
console.log(chalk.dim(' Added .dss/ to .gitignore'));
}
}
} catch (error) {
spinner.fail('Failed to initialize DSS');
console.error(chalk.red(` ${(error as Error).message}`));
process.exit(1);
}
}

109
cli/src/commands/start.ts Normal file
View File

@@ -0,0 +1,109 @@
/**
* DSS Start Command
*
* Start the DSS server.
*/
import chalk from 'chalk';
import ora from 'ora';
import { exec } from 'child_process';
import { getConfig, getProjectRoot, hasProjectConfig } from '../lib/config.js';
import {
startServer,
isServerRunning,
getServerPid,
waitForServer,
stopServer,
} from '../lib/server.js';
interface StartOptions {
port: string;
dev: boolean;
open: boolean;
}
export async function startCommand(options: StartOptions): Promise<void> {
const port = parseInt(options.port, 10);
const cwd = getProjectRoot();
const config = getConfig();
// Check if already running
if (isServerRunning(cwd)) {
const pid = getServerPid(cwd);
console.log(chalk.yellow(` DSS is already running (PID: ${pid})`));
console.log(chalk.dim(` Dashboard: http://localhost:${port}`));
console.log('');
console.log(chalk.dim(' To restart: dss stop && dss start'));
return;
}
const spinner = ora('Starting DSS server...').start();
try {
// Start server
const serverProcess = await startServer({
port,
dev: options.dev,
cwd,
});
if (options.dev) {
spinner.succeed('DSS running in development mode');
console.log(chalk.dim(' Press Ctrl+C to stop'));
console.log('');
// In dev mode, we're attached to the process
serverProcess.on('exit', (code) => {
console.log(chalk.dim(`\n Server exited with code ${code}`));
process.exit(code || 0);
});
// Handle Ctrl+C
process.on('SIGINT', () => {
console.log(chalk.dim('\n Stopping server...'));
serverProcess.kill('SIGTERM');
});
} else {
// Wait for server to be ready
spinner.text = 'Waiting for server to be ready...';
const ready = await waitForServer(port, 15000);
if (!ready) {
spinner.fail('Server failed to start');
console.error(chalk.red(' Check logs: .dss/dss.log'));
await stopServer(cwd);
process.exit(1);
}
spinner.succeed(`DSS started (PID: ${serverProcess.pid})`);
console.log('');
console.log(chalk.green(' Dashboard:'), chalk.blue(`http://localhost:${port}`));
console.log(chalk.green(' API: '), chalk.blue(`http://localhost:${port}/api`));
console.log(chalk.green(' Docs: '), chalk.blue(`http://localhost:${port}/docs`));
console.log('');
console.log(chalk.dim(' Logs: .dss/dss.log'));
console.log(chalk.dim(' Stop: dss stop'));
console.log('');
// Show Figma status
if (config.figmaFileKey) {
console.log(chalk.dim(` Figma file: ${config.figmaFileKey}`));
} else {
console.log(chalk.yellow(' No Figma file configured'));
console.log(chalk.dim(' Run: dss config --set figmaFileKey=YOUR_KEY'));
}
// Open browser if requested
if (options.open) {
const url = `http://localhost:${port}`;
const openCmd = process.platform === 'darwin' ? 'open' :
process.platform === 'win32' ? 'start' : 'xdg-open';
exec(`${openCmd} ${url}`);
}
}
} catch (error) {
spinner.fail('Failed to start DSS');
console.error(chalk.red(` ${(error as Error).message}`));
process.exit(1);
}
}

View File

@@ -0,0 +1,96 @@
/**
* 🏥 DSS Status Command - Organism Vital Signs
*
* Check DSS design system organism's vital signs, consciousness state,
* and sensory organ configuration.
*/
import chalk from 'chalk';
import { getConfig, getProjectRoot, hasProjectConfig } from '../lib/config.js';
import { isServerRunning, getServerPid } from '../lib/server.js';
import { getApiClient } from '../lib/api.js';
export async function statusCommand(): Promise<void> {
const cwd = getProjectRoot();
const config = getConfig();
console.log('');
console.log(chalk.cyan(' 🏥 ORGANISM VITAL SIGNS'));
console.log(chalk.dim(' ────────────────────────'));
console.log('');
// Organism status
if (hasProjectConfig()) {
console.log(chalk.green(' 🧬 Organism:'), chalk.dim('Born and conscious'));
console.log(chalk.dim(` Home: ${cwd}`));
} else {
console.log(chalk.yellow(' 🧬 Organism:'), chalk.dim('Not yet born'));
console.log(chalk.dim(' Genesis: dss init'));
}
console.log('');
// Consciousness status (server)
const running = isServerRunning(cwd);
const pid = getServerPid(cwd);
const port = config.port || 3456;
if (running) {
console.log(chalk.green(' 💚 Consciousness:'), chalk.dim(`Awake (PID: ${pid})`));
console.log(chalk.dim(` Neural port: http://localhost:${port}`));
// Try to get health info
try {
const api = getApiClient({ port });
const health = await api.health();
console.log(chalk.dim(` Awareness: ${health.figma_mode}`));
} catch {
console.log(chalk.yellow(' ⚠️ Unable to read consciousness'));
}
} else {
console.log(chalk.yellow(' 💚 Consciousness:'), chalk.dim('Sleeping'));
console.log(chalk.dim(' Awaken: dss start'));
}
console.log('');
// Sensory organs (Figma)
if (config.figmaToken) {
console.log(chalk.green(' 👁️ Sensory Eyes:'), chalk.dim('Configured'));
// Test connection if server is running
if (running) {
try {
const api = getApiClient({ port });
const test = await api.testFigmaConnection();
if (test.success) {
console.log(chalk.green(' Perception:'), chalk.dim(`Clear (${test.user})`));
} else {
console.log(chalk.red(' Perception:'), chalk.dim(test.error || 'Blinded'));
}
} catch {
console.log(chalk.yellow(' Perception:'), chalk.dim('Cannot test'));
}
}
} else {
console.log(chalk.yellow(' 👁️ Sensory Eyes:'), chalk.dim('Not configured'));
console.log(chalk.dim(' Configure: dss config --set figmaToken=figd_xxxxx'));
}
if (config.figmaFileKey) {
console.log(chalk.green(' 📋 Genetic Blueprint:'), chalk.dim(config.figmaFileKey));
} else {
console.log(chalk.yellow(' Figma File:'), chalk.dim('Not configured'));
console.log(chalk.dim(' Set: dss config --set figmaFileKey=abc123'));
}
console.log('');
// Output config
console.log(chalk.dim(' Output:'));
console.log(chalk.dim(` Format: ${config.tokenFormat || 'css'}`));
console.log(chalk.dim(` Framework: ${config.componentFramework || 'react'}`));
console.log(chalk.dim(` Directory: ${config.outputDir || '.dss/output'}`));
console.log('');
}

25
cli/src/commands/stop.ts Normal file
View File

@@ -0,0 +1,25 @@
/**
* DSS Stop Command
*
* Stop the DSS server.
*/
import chalk from 'chalk';
import { getProjectRoot } from '../lib/config.js';
import { isServerRunning, stopServer, getServerPid } from '../lib/server.js';
export async function stopCommand(): Promise<void> {
const cwd = getProjectRoot();
if (!isServerRunning(cwd)) {
console.log(chalk.yellow(' DSS is not running'));
return;
}
const pid = getServerPid(cwd);
console.log(chalk.dim(` Stopping DSS (PID: ${pid})...`));
await stopServer(cwd);
console.log(chalk.green(' DSS stopped'));
}

102
cli/src/commands/sync.ts Normal file
View File

@@ -0,0 +1,102 @@
/**
* DSS Sync Command
*
* Sync design tokens from Figma to local files.
*/
import chalk from 'chalk';
import ora from 'ora';
import { writeFileSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
import { getConfig, getProjectRoot } from '../lib/config.js';
import { getApiClient } from '../lib/api.js';
import { isServerRunning } from '../lib/server.js';
interface SyncOptions {
format: string;
output?: string;
fileKey?: string;
}
export async function syncCommand(options: SyncOptions): Promise<void> {
const config = getConfig();
const cwd = getProjectRoot();
// Check if server is running
if (!isServerRunning(cwd)) {
console.log(chalk.yellow(' DSS server is not running'));
console.log(chalk.dim(' Start it with: dss start'));
console.log('');
console.log(chalk.dim(' Or sync directly via API if running remotely'));
process.exit(1);
}
const fileKey = options.fileKey || config.figmaFileKey;
if (!fileKey) {
console.log(chalk.red(' No Figma file key configured'));
console.log(chalk.dim(' Set it with: dss config --set figmaFileKey=YOUR_KEY'));
process.exit(1);
}
const format = options.format || config.tokenFormat || 'css';
const outputPath = options.output || getDefaultOutputPath(format, cwd);
const spinner = ora(`Syncing tokens from Figma (${format})...`).start();
try {
const api = getApiClient({ port: config.port });
// Extract tokens
spinner.text = 'Extracting tokens from Figma...';
const result = await api.extractTokens(fileKey, format);
if (!result.success) {
throw new Error('Token extraction failed');
}
// Write output file
spinner.text = `Writing ${result.tokens_count} tokens to ${outputPath}...`;
const dir = dirname(outputPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
writeFileSync(outputPath, result.formatted_output);
spinner.succeed(`Synced ${result.tokens_count} tokens`);
console.log('');
console.log(chalk.green(' Output:'), chalk.dim(outputPath));
console.log('');
// Show token summary
const categories = result.tokens.reduce((acc, t) => {
acc[t.category] = (acc[t.category] || 0) + 1;
return acc;
}, {} as Record<string, number>);
console.log(chalk.dim(' Token breakdown:'));
Object.entries(categories).forEach(([cat, count]) => {
console.log(chalk.dim(` ${cat}: ${count}`));
});
console.log('');
} catch (error) {
spinner.fail('Sync failed');
console.error(chalk.red(` ${(error as Error).message}`));
process.exit(1);
}
}
function getDefaultOutputPath(format: string, cwd: string): string {
const extensions: Record<string, string> = {
css: 'tokens.css',
scss: '_tokens.scss',
json: 'tokens.json',
ts: 'tokens.ts',
js: 'tokens.js',
};
const filename = extensions[format] || 'tokens.css';
return join(cwd, '.dss', 'output', filename);
}

15
cli/src/index.ts Normal file
View File

@@ -0,0 +1,15 @@
/**
* DSS - Design System Server
*
* Programmatic API for DSS.
*/
export { DSSApiClient, getApiClient, type ApiOptions } from './lib/api.js';
export { getConfig, getProjectRoot, hasProjectConfig, type DSSConfig } from './lib/config.js';
export {
startServer,
stopServer,
isServerRunning,
getServerPid,
waitForServer,
} from './lib/server.js';

144
cli/src/lib/api.ts Normal file
View File

@@ -0,0 +1,144 @@
/**
* DSS API Client
*
* Communicates with the DSS server.
*/
import { getConfig } from './config.js';
export interface ApiOptions {
port?: number;
baseUrl?: string;
}
export class DSSApiClient {
private baseUrl: string;
constructor(options: ApiOptions = {}) {
const config = getConfig();
const port = options.port || config.port || 3456;
this.baseUrl = options.baseUrl || `http://localhost:${port}/api`;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${this.baseUrl}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: response.statusText })) as { message?: string };
throw new Error(errorData.message || `Request failed: ${response.status}`);
}
const text = await response.text();
return text ? JSON.parse(text) as T : {} as T;
}
async health(): Promise<{ status: string; figma_mode: string }> {
// Health endpoint is at root, not under /api
const url = this.baseUrl.replace('/api', '') + '/health';
const response = await fetch(url);
return response.json() as Promise<{ status: string; figma_mode: string }>;
}
async getConfig(): Promise<Record<string, unknown>> {
return this.request('/config');
}
async setFigmaToken(token: string): Promise<void> {
await this.request('/config', {
method: 'PUT',
body: JSON.stringify({ figma_token: token }),
});
}
async testFigmaConnection(): Promise<{ success: boolean; user?: string; error?: string }> {
return this.request('/config/figma/test', { method: 'POST' });
}
async extractTokens(fileKey: string, format: string = 'css'): Promise<{
success: boolean;
tokens_count: number;
tokens: Array<{ name: string; value: string; type: string; category: string }>;
formatted_output: string;
output_path: string;
}> {
return this.request('/figma/extract-variables', {
method: 'POST',
body: JSON.stringify({ file_key: fileKey, format }),
});
}
async extractComponents(fileKey: string): Promise<{
success: boolean;
components_count: number;
components: Array<{ name: string; key: string; description: string; variants: string[] }>;
output_path: string;
}> {
return this.request('/figma/extract-components', {
method: 'POST',
body: JSON.stringify({ file_key: fileKey }),
});
}
async syncTokens(fileKey: string, targetPath: string, format: string = 'css'): Promise<{
success: boolean;
tokens_synced: number;
output_file: string;
}> {
return this.request('/figma/sync-tokens', {
method: 'POST',
body: JSON.stringify({ file_key: fileKey, target_path: targetPath, format }),
});
}
async generateCode(fileKey: string, componentName: string, framework: string = 'react'): Promise<{
success: boolean;
component: string;
framework: string;
code: string;
}> {
return this.request('/figma/generate-code', {
method: 'POST',
body: JSON.stringify({ file_key: fileKey, component_name: componentName, framework }),
});
}
async getProjects(): Promise<Array<{
id: string;
name: string;
figma_file_key: string;
status: string;
}>> {
return this.request('/projects');
}
async createProject(data: {
name: string;
description?: string;
figma_file_key?: string;
}): Promise<{ id: string; name: string }> {
return this.request('/projects', {
method: 'POST',
body: JSON.stringify(data),
});
}
}
// Singleton instance
let apiClient: DSSApiClient | null = null;
export function getApiClient(options?: ApiOptions): DSSApiClient {
if (!apiClient || options) {
apiClient = new DSSApiClient(options);
}
return apiClient;
}

95
cli/src/lib/config.ts Normal file
View File

@@ -0,0 +1,95 @@
/**
* DSS Configuration Manager
*
* Manages local and project configuration.
*/
import Conf from 'conf';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
// Global user config (stored in home directory)
const globalConfig = new Conf({
projectName: 'dss',
schema: {
figmaToken: { type: 'string' },
defaultPort: { type: 'number', default: 3456 },
defaultFormat: { type: 'string', default: 'css' },
},
});
// Project-level config file
const PROJECT_CONFIG_FILE = '.dss/config.json';
export interface DSSConfig {
figmaFileKey?: string;
figmaToken?: string;
port?: number;
outputDir?: string;
tokenFormat?: 'css' | 'scss' | 'json' | 'ts';
componentFramework?: 'react' | 'vue' | 'svelte' | 'webcomponent';
}
export function getProjectRoot(): string {
return process.cwd();
}
export function getProjectConfigPath(): string {
return join(getProjectRoot(), PROJECT_CONFIG_FILE);
}
export function hasProjectConfig(): boolean {
return existsSync(getProjectConfigPath());
}
export function loadProjectConfig(): DSSConfig {
const configPath = getProjectConfigPath();
if (!existsSync(configPath)) {
return {};
}
try {
const content = readFileSync(configPath, 'utf-8');
return JSON.parse(content);
} catch (error) {
console.warn('Failed to parse project config:', error);
return {};
}
}
export function saveProjectConfig(config: DSSConfig): void {
const configPath = getProjectConfigPath();
const dir = join(getProjectRoot(), '.dss');
// Ensure .dss directory exists
if (!existsSync(dir)) {
const { mkdirSync } = require('fs');
mkdirSync(dir, { recursive: true });
}
writeFileSync(configPath, JSON.stringify(config, null, 2));
}
export function getConfig(): DSSConfig {
const project = loadProjectConfig();
return {
figmaToken: project.figmaToken || globalConfig.get('figmaToken') as string | undefined,
figmaFileKey: project.figmaFileKey,
port: project.port || globalConfig.get('defaultPort') as number,
outputDir: project.outputDir || '.dss/output',
tokenFormat: project.tokenFormat || (globalConfig.get('defaultFormat') as DSSConfig['tokenFormat']),
componentFramework: project.componentFramework || 'react',
};
}
export function setGlobalConfig(key: string, value: string | number): void {
globalConfig.set(key, value);
}
export function getGlobalConfig(key: string): unknown {
return globalConfig.get(key);
}
export function listGlobalConfig(): Record<string, unknown> {
return globalConfig.store;
}

197
cli/src/lib/server.ts Normal file
View File

@@ -0,0 +1,197 @@
/**
* DSS Server Manager
*
* Manages the Python server subprocess.
*/
import { spawn, ChildProcess } from 'child_process';
import { existsSync, writeFileSync, readFileSync, unlinkSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
interface ServerOptions {
port: number;
dev: boolean;
cwd: string;
}
let serverProcess: ChildProcess | null = null;
export function getPythonPath(): string {
// Check for bundled Python venv in npm package (dist/lib -> ../../python/venv)
const bundledPython = join(__dirname, '../../python/venv/bin/python3');
if (existsSync(bundledPython)) {
return bundledPython;
}
// Development path (src/lib -> ../../python/venv)
const devPython = join(__dirname, '../../../python/venv/bin/python3');
if (existsSync(devPython)) {
return devPython;
}
return 'python3';
}
export function getServerPath(): string {
// Check for bundled server or use from package
const bundledServer = join(__dirname, '../../python/api/server.py');
if (existsSync(bundledServer)) {
return dirname(bundledServer);
}
// Fall back to relative path from CLI (cli/dist/lib -> ../../../../tools/api)
const devServer = join(__dirname, '../../../../tools/api');
if (existsSync(join(devServer, 'server.py'))) {
return devServer;
}
// Also check development src path (cli/src/lib -> ../../../../tools/api)
const srcServer = join(__dirname, '../../../tools/api');
if (existsSync(join(srcServer, 'server.py'))) {
return srcServer;
}
throw new Error('Could not find DSS server. Run from the design-system-swarm directory or install the full package.');
}
export function getPidFile(cwd: string): string {
return join(cwd, '.dss', 'dss.pid');
}
export function getLogFile(cwd: string): string {
return join(cwd, '.dss', 'dss.log');
}
export function isServerRunning(cwd: string): boolean {
const pidFile = getPidFile(cwd);
if (!existsSync(pidFile)) {
return false;
}
try {
const pid = parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);
// Check if process exists
process.kill(pid, 0);
return true;
} catch {
// Process doesn't exist, clean up stale PID file
try {
unlinkSync(pidFile);
} catch {
// Ignore
}
return false;
}
}
export function getServerPid(cwd: string): number | null {
const pidFile = getPidFile(cwd);
if (!existsSync(pidFile)) {
return null;
}
try {
return parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);
} catch {
return null;
}
}
export async function startServer(options: ServerOptions): Promise<ChildProcess> {
const { port, dev, cwd } = options;
if (isServerRunning(cwd)) {
throw new Error(`Server is already running (PID: ${getServerPid(cwd)})`);
}
const pythonPath = getPythonPath();
const serverDir = getServerPath();
// Build command args
const args = [
'-m', 'uvicorn',
'server:app',
'--host', '0.0.0.0',
'--port', String(port),
];
if (dev) {
args.push('--reload');
}
// Set environment
const env = {
...process.env,
PYTHONPATH: join(serverDir, '..'),
PORT: String(port),
};
// Spawn server process
serverProcess = spawn(pythonPath, args, {
cwd: serverDir,
env,
stdio: dev ? 'inherit' : ['ignore', 'pipe', 'pipe'],
detached: !dev,
});
if (!dev && serverProcess.pid) {
// Write PID file
const dssDir = join(cwd, '.dss');
if (!existsSync(dssDir)) {
const { mkdirSync } = await import('fs');
mkdirSync(dssDir, { recursive: true });
}
writeFileSync(getPidFile(cwd), String(serverProcess.pid));
// Write logs
const logStream = await import('fs').then(fs =>
fs.createWriteStream(getLogFile(cwd), { flags: 'a' })
);
serverProcess.stdout?.pipe(logStream);
serverProcess.stderr?.pipe(logStream);
// Detach from parent
serverProcess.unref();
}
return serverProcess;
}
export async function stopServer(cwd: string): Promise<boolean> {
const pid = getServerPid(cwd);
if (!pid) {
return false;
}
try {
process.kill(pid, 'SIGTERM');
unlinkSync(getPidFile(cwd));
return true;
} catch {
return false;
}
}
export async function waitForServer(port: number, timeout = 10000): Promise<boolean> {
const start = Date.now();
const url = `http://localhost:${port}/health`;
while (Date.now() - start < timeout) {
try {
const response = await fetch(url);
if (response.ok) {
return true;
}
} catch {
// Server not ready yet
}
await new Promise(resolve => setTimeout(resolve, 200));
}
return false;
}