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
147 lines
4.3 KiB
TypeScript
147 lines
4.3 KiB
TypeScript
/**
|
|
* 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}`));
|
|
}
|
|
}
|