@promptui-lib/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { run } from '../dist/index.js';
4
+
5
+ run().catch((error) => {
6
+ console.error('[PromptUI] Error:', error.message);
7
+ process.exit(1);
8
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generate Command
3
+ * Gera componente a partir de um node do Figma ou arquivo JSON local
4
+ */
5
+ import type { ComponentLayer, FrameworkType } from '@promptui-lib/core';
6
+ export interface IGenerateOptions {
7
+ force?: boolean;
8
+ output?: string;
9
+ layer?: ComponentLayer;
10
+ framework?: FrameworkType;
11
+ preview?: boolean;
12
+ noMeta?: boolean;
13
+ }
14
+ export declare function generateCommand(input: string, options: IGenerateOptions): Promise<void>;
15
+ /**
16
+ * Gera todos os componentes marcados com # no arquivo Figma
17
+ */
18
+ export declare function generateAllCommand(options: IGenerateOptions): Promise<void>;
19
+ //# sourceMappingURL=generate.cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/generate.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAc,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAapF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA0ED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAqJf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFjF"}
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Generate Command
3
+ * Gera componente a partir de um node do Figma ou arquivo JSON local
4
+ */
5
+ import { readFile } from 'node:fs/promises';
6
+ import { createHash } from 'node:crypto';
7
+ import { createFigmaClient } from '@promptui-lib/figma-parser';
8
+ import { parseNode } from '@promptui-lib/figma-parser';
9
+ import { writeComponent, generateCode, generateMuiComponent, generateTailwindComponent, generateBootstrapComponent, FRAMEWORKS, } from '@promptui-lib/codegen';
10
+ import { loadConfig, resolveConfig, validateConfig } from '@promptui-lib/mcp-agent';
11
+ /**
12
+ * Detecta se o input é um arquivo JSON local ou nodeId do Figma
13
+ */
14
+ function isLocalFile(input) {
15
+ return input.endsWith('.json') || input.startsWith('./') || input.startsWith('/');
16
+ }
17
+ /**
18
+ * Carrega node de arquivo JSON local
19
+ */
20
+ async function loadNodeFromFile(filePath) {
21
+ const content = await readFile(filePath, 'utf-8');
22
+ const node = JSON.parse(content);
23
+ if (!node.id || !node.name || !node.type) {
24
+ throw new Error('Invalid Figma node JSON: missing id, name or type');
25
+ }
26
+ return node;
27
+ }
28
+ /**
29
+ * Gera metadados do componente
30
+ */
31
+ function generateMeta(node, ast, source, files) {
32
+ const content = JSON.stringify({ node, ast, source, files });
33
+ const checksum = createHash('sha256').update(content).digest('hex');
34
+ return {
35
+ generator: 'promptui-figma-codegen',
36
+ version: '1.0.0',
37
+ generatedAt: new Date().toISOString(),
38
+ source: {
39
+ nodeId: node.id,
40
+ nodeName: node.name,
41
+ fileId: source.fileId,
42
+ fromFile: source.fromFile,
43
+ },
44
+ output: {
45
+ componentName: ast.name,
46
+ fileName: ast.fileName,
47
+ layer: ast.layer,
48
+ files,
49
+ },
50
+ checksum: `sha256:${checksum}`,
51
+ };
52
+ }
53
+ export async function generateCommand(input, options) {
54
+ const isFile = isLocalFile(input);
55
+ console.log(`[PromptUI] Generating component from ${isFile ? 'file' : 'Figma node'}: ${input}`);
56
+ // Carrega config
57
+ const config = await loadConfig();
58
+ const resolved = resolveConfig(config);
59
+ let node;
60
+ let sourceInfo = {};
61
+ try {
62
+ if (isFile) {
63
+ // Carrega de arquivo JSON local
64
+ node = await loadNodeFromFile(input);
65
+ sourceInfo.fromFile = input;
66
+ console.log(`[PromptUI] Loaded from file: ${node.name} (${node.type})`);
67
+ }
68
+ else {
69
+ // Valida config para API
70
+ const errors = validateConfig(resolved);
71
+ if (errors.length > 0) {
72
+ console.error('[PromptUI] Configuration errors:');
73
+ for (const error of errors) {
74
+ console.error(` - ${error}`);
75
+ }
76
+ process.exit(1);
77
+ }
78
+ // Busca node do Figma
79
+ const client = createFigmaClient({ token: resolved.figmaToken });
80
+ const fetchedNode = await client.getNode(resolved.figmaFileId, input);
81
+ if (!fetchedNode) {
82
+ console.error(`[PromptUI] Node not found: ${input}`);
83
+ process.exit(1);
84
+ }
85
+ node = fetchedNode;
86
+ sourceInfo.fileId = resolved.figmaFileId;
87
+ console.log(`[PromptUI] Fetched from Figma: ${node.name} (${node.type})`);
88
+ }
89
+ // Parseia
90
+ const ast = parseNode(node, { forceLayer: options.layer });
91
+ const framework = options.framework ?? 'react';
92
+ const frameworkInfo = FRAMEWORKS[framework];
93
+ console.log(`[PromptUI] Parsed: ${ast.name} (${ast.layer})`);
94
+ console.log(`[PromptUI] Framework: ${frameworkInfo?.displayName ?? framework}`);
95
+ // Gera código baseado no framework
96
+ const generateForFramework = () => {
97
+ switch (framework) {
98
+ case 'mui':
99
+ return {
100
+ tsx: generateMuiComponent(ast),
101
+ scss: '', // MUI usa sx props inline
102
+ index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
103
+ };
104
+ case 'tailwind':
105
+ return {
106
+ tsx: generateTailwindComponent(ast),
107
+ scss: '', // Tailwind usa classes inline
108
+ index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
109
+ };
110
+ case 'bootstrap':
111
+ return {
112
+ tsx: generateBootstrapComponent(ast),
113
+ scss: '', // Bootstrap usa classes inline
114
+ index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
115
+ };
116
+ case 'react':
117
+ default:
118
+ return generateCode(ast);
119
+ }
120
+ };
121
+ // Preview mode
122
+ if (options.preview) {
123
+ const code = generateForFramework();
124
+ console.log('\n--- TSX ---');
125
+ console.log(code.tsx);
126
+ if (code.scss) {
127
+ console.log('\n--- SCSS ---');
128
+ console.log(code.scss);
129
+ }
130
+ console.log('\n--- index.ts ---');
131
+ console.log(code.index);
132
+ if (!options.noMeta) {
133
+ const meta = generateMeta(node, ast, sourceInfo, [
134
+ `${ast.fileName}.tsx`,
135
+ `${ast.fileName}.scss`,
136
+ 'index.ts',
137
+ 'meta.json',
138
+ ]);
139
+ console.log('\n--- meta.json ---');
140
+ console.log(JSON.stringify(meta, null, 2));
141
+ }
142
+ return;
143
+ }
144
+ // Escreve arquivos
145
+ const basePath = options.output ?? resolved.outputBasePath;
146
+ const result = await writeComponent(ast, {
147
+ basePath,
148
+ forceOverwrite: options.force,
149
+ });
150
+ if (!result.success) {
151
+ console.error('[PromptUI] Failed to write files:');
152
+ for (const error of result.errors ?? []) {
153
+ console.error(` - ${error}`);
154
+ }
155
+ process.exit(1);
156
+ }
157
+ // Gera meta.json
158
+ if (!options.noMeta) {
159
+ const { writeFile } = await import('node:fs/promises');
160
+ const { join, dirname } = await import('node:path');
161
+ const metaPath = join(dirname(result.files.tsx), 'meta.json');
162
+ const meta = generateMeta(node, ast, sourceInfo, [
163
+ `${ast.fileName}.tsx`,
164
+ `${ast.fileName}.scss`,
165
+ 'index.ts',
166
+ 'meta.json',
167
+ ]);
168
+ await writeFile(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
169
+ console.log('[PromptUI] Generated files:');
170
+ console.log(` - ${result.files.tsx}`);
171
+ console.log(` - ${result.files.scss}`);
172
+ console.log(` - ${result.files.index}`);
173
+ console.log(` - ${metaPath}`);
174
+ }
175
+ else {
176
+ console.log('[PromptUI] Generated files:');
177
+ console.log(` - ${result.files.tsx}`);
178
+ console.log(` - ${result.files.scss}`);
179
+ console.log(` - ${result.files.index}`);
180
+ }
181
+ }
182
+ catch (error) {
183
+ const message = error instanceof Error ? error.message : 'Unknown error';
184
+ console.error(`[PromptUI] Error: ${message}`);
185
+ process.exit(1);
186
+ }
187
+ }
188
+ /**
189
+ * Gera todos os componentes marcados com # no arquivo Figma
190
+ */
191
+ export async function generateAllCommand(options) {
192
+ console.log('[PromptUI] Generating all exportable components...');
193
+ // Carrega config
194
+ const config = await loadConfig();
195
+ const resolved = resolveConfig(config);
196
+ // Valida
197
+ const errors = validateConfig(resolved);
198
+ if (errors.length > 0) {
199
+ console.error('[PromptUI] Configuration errors:');
200
+ for (const error of errors) {
201
+ console.error(` - ${error}`);
202
+ }
203
+ process.exit(1);
204
+ }
205
+ try {
206
+ const client = createFigmaClient({ token: resolved.figmaToken });
207
+ const file = await client.getFile(resolved.figmaFileId);
208
+ // Encontra todos os nodes exportáveis (começam com #)
209
+ const exportableNodes = [];
210
+ function findExportable(node) {
211
+ if (node.name.startsWith('#')) {
212
+ exportableNodes.push(node);
213
+ }
214
+ if (node.children) {
215
+ for (const child of node.children) {
216
+ findExportable(child);
217
+ }
218
+ }
219
+ }
220
+ if (file.document) {
221
+ findExportable(file.document);
222
+ }
223
+ console.log(`[PromptUI] Found ${exportableNodes.length} exportable components`);
224
+ if (exportableNodes.length === 0) {
225
+ console.log('[PromptUI] No components found. Mark frames with # prefix to export.');
226
+ return;
227
+ }
228
+ let successCount = 0;
229
+ let errorCount = 0;
230
+ for (const node of exportableNodes) {
231
+ try {
232
+ const ast = parseNode(node, { forceLayer: options.layer });
233
+ const basePath = options.output ?? resolved.outputBasePath;
234
+ const result = await writeComponent(ast, {
235
+ basePath,
236
+ forceOverwrite: options.force,
237
+ });
238
+ if (result.success) {
239
+ console.log(` ✅ ${ast.name} (${ast.layer})`);
240
+ successCount++;
241
+ }
242
+ else {
243
+ console.log(` ❌ ${node.name}: ${result.errors?.join(', ')}`);
244
+ errorCount++;
245
+ }
246
+ }
247
+ catch (error) {
248
+ const message = error instanceof Error ? error.message : 'Unknown error';
249
+ console.log(` ❌ ${node.name}: ${message}`);
250
+ errorCount++;
251
+ }
252
+ }
253
+ console.log('');
254
+ console.log(`[PromptUI] Done: ${successCount} success, ${errorCount} errors`);
255
+ }
256
+ catch (error) {
257
+ const message = error instanceof Error ? error.message : 'Unknown error';
258
+ console.error(`[PromptUI] Error: ${message}`);
259
+ process.exit(1);
260
+ }
261
+ }
@@ -0,0 +1,8 @@
1
+ export { generateCommand, generateAllCommand } from './generate.cmd.js';
2
+ export type { IGenerateOptions } from './generate.cmd.js';
3
+ export { initCommand } from './init.cmd.js';
4
+ export { syncTokensCommand } from './sync.cmd.js';
5
+ export type { ISyncOptions } from './sync.cmd.js';
6
+ export { mcpCommand, studioCommand, listAgents } from './mcp.cmd.js';
7
+ export type { IMcpOptions } from './mcp.cmd.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { generateCommand, generateAllCommand } from './generate.cmd.js';
2
+ export { initCommand } from './init.cmd.js';
3
+ export { syncTokensCommand } from './sync.cmd.js';
4
+ export { mcpCommand, studioCommand, listAgents } from './mcp.cmd.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Init Command
3
+ * Cria arquivo de configuração inicial
4
+ */
5
+ export declare function initCommand(): Promise<void>;
6
+ //# sourceMappingURL=init.cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/init.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA8BjD"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Init Command
3
+ * Cria arquivo de configuração inicial
4
+ */
5
+ import { writeFile, access } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+ const DEFAULT_CONFIG = {
8
+ figma: {
9
+ token: 'YOUR_FIGMA_TOKEN',
10
+ fileId: 'YOUR_FILE_ID',
11
+ },
12
+ output: {
13
+ basePath: 'src/components',
14
+ styleFormat: 'scss',
15
+ },
16
+ };
17
+ export async function initCommand() {
18
+ const configPath = join(process.cwd(), 'promptui.config.json');
19
+ // Verifica se já existe
20
+ try {
21
+ await access(configPath);
22
+ console.log('[PromptUI] Config file already exists: promptui.config.json');
23
+ console.log('[PromptUI] Delete it first if you want to reinitialize.');
24
+ return;
25
+ }
26
+ catch {
27
+ // Arquivo não existe, podemos criar
28
+ }
29
+ // Escreve config
30
+ const content = JSON.stringify(DEFAULT_CONFIG, null, 2);
31
+ await writeFile(configPath, content, 'utf-8');
32
+ console.log('[PromptUI] Created: promptui.config.json');
33
+ console.log('');
34
+ console.log('Next steps:');
35
+ console.log(' 1. Get your Figma Personal Access Token:');
36
+ console.log(' https://www.figma.com/developers/api#access-tokens');
37
+ console.log('');
38
+ console.log(' 2. Get your Figma File ID from the URL:');
39
+ console.log(' https://www.figma.com/file/<FILE_ID>/...');
40
+ console.log('');
41
+ console.log(' 3. Update promptui.config.json with your values');
42
+ console.log('');
43
+ console.log(' 4. Start the agent:');
44
+ console.log(' npx promptui agent');
45
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * MCP Command
3
+ * Executa agentes MCP do PromptUI
4
+ */
5
+ export interface IMcpOptions {
6
+ input?: string;
7
+ output?: string;
8
+ preview?: boolean;
9
+ }
10
+ /**
11
+ * Lista agentes disponíveis
12
+ */
13
+ export declare function listAgents(): void;
14
+ /**
15
+ * Executa um agente MCP
16
+ */
17
+ export declare function mcpCommand(agentKey: string, input: string, options: IMcpOptions): Promise<void>;
18
+ /**
19
+ * Inicia o PromptUI Studio (interface interativa)
20
+ */
21
+ export declare function studioCommand(): Promise<void>;
22
+ //# sourceMappingURL=mcp.cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAUD;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAyBD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAoDf;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAsBnD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * MCP Command
3
+ * Executa agentes MCP do PromptUI
4
+ */
5
+ import { readFile } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+ const AVAILABLE_AGENTS = {
8
+ 'figma-codegen': {
9
+ name: 'promptui-figma-codegen',
10
+ description: 'Gera componentes React a partir de JSON do Figma (100% determinístico)',
11
+ promptFile: '.claude/agents/promptui-figma-codegen.md',
12
+ },
13
+ };
14
+ /**
15
+ * Lista agentes disponíveis
16
+ */
17
+ export function listAgents() {
18
+ console.log('[PromptUI] Available MCP Agents:\n');
19
+ for (const [key, agent] of Object.entries(AVAILABLE_AGENTS)) {
20
+ console.log(` ${key}`);
21
+ console.log(` ${agent.description}`);
22
+ console.log(` Usage: npx promptui mcp ${key} <input>`);
23
+ console.log('');
24
+ }
25
+ }
26
+ /**
27
+ * Carrega o prompt de um agente
28
+ */
29
+ async function loadAgentPrompt(agentKey) {
30
+ const agent = AVAILABLE_AGENTS[agentKey];
31
+ if (!agent) {
32
+ throw new Error(`Unknown agent: ${agentKey}. Use 'npx promptui mcp' to list available agents.`);
33
+ }
34
+ const promptPath = join(process.cwd(), agent.promptFile);
35
+ try {
36
+ return await readFile(promptPath, 'utf-8');
37
+ }
38
+ catch {
39
+ // Se não encontrar no projeto, tenta no pacote
40
+ throw new Error(`Agent prompt not found: ${promptPath}\n` +
41
+ `Make sure the PromptUI agents are configured in your project.`);
42
+ }
43
+ }
44
+ /**
45
+ * Executa um agente MCP
46
+ */
47
+ export async function mcpCommand(agentKey, input, options) {
48
+ if (!agentKey) {
49
+ listAgents();
50
+ return;
51
+ }
52
+ console.log(`[PromptUI] Running MCP agent: ${agentKey}`);
53
+ try {
54
+ // Carrega o prompt do agente
55
+ const prompt = await loadAgentPrompt(agentKey);
56
+ console.log(`[PromptUI] Agent loaded: ${AVAILABLE_AGENTS[agentKey]?.name}`);
57
+ // Para o agente figma-codegen, precisamos do input
58
+ if (agentKey === 'figma-codegen') {
59
+ if (!input) {
60
+ console.error('[PromptUI] Error: Missing input (nodeId or JSON file path)');
61
+ console.log('Usage: npx promptui mcp figma-codegen <nodeId | file.json>');
62
+ process.exit(1);
63
+ }
64
+ // Aqui seria a integração com o MCP SDK
65
+ // Por enquanto, mostra as instruções
66
+ console.log('');
67
+ console.log('[PromptUI] MCP Agent Instructions:');
68
+ console.log('');
69
+ console.log('To use this agent with Claude:');
70
+ console.log('');
71
+ console.log('1. Start the MCP server:');
72
+ console.log(' npx promptui agent');
73
+ console.log('');
74
+ console.log('2. Connect via MCP client or use the HTTP API:');
75
+ console.log(' curl -X POST http://localhost:17890/generate \\');
76
+ console.log(' -H "Content-Type: application/json" \\');
77
+ console.log(` -d '{"nodeId": "${input}"}'`);
78
+ console.log('');
79
+ console.log('3. Or use the generate command directly:');
80
+ console.log(` npx promptui generate ${input}`);
81
+ console.log('');
82
+ if (options.preview) {
83
+ console.log('--- Agent Prompt Preview ---');
84
+ console.log(prompt.substring(0, 2000) + '...');
85
+ console.log('--- End Preview ---');
86
+ }
87
+ }
88
+ }
89
+ catch (error) {
90
+ const message = error instanceof Error ? error.message : 'Unknown error';
91
+ console.error(`[PromptUI] Error: ${message}`);
92
+ process.exit(1);
93
+ }
94
+ }
95
+ /**
96
+ * Inicia o PromptUI Studio (interface interativa)
97
+ */
98
+ export async function studioCommand() {
99
+ console.log('[PromptUI] Starting PromptUI Studio...');
100
+ console.log('');
101
+ console.log('╔════════════════════════════════════════════════════════╗');
102
+ console.log('║ PromptUI Studio (Preview) ║');
103
+ console.log('╠════════════════════════════════════════════════════════╣');
104
+ console.log('║ ║');
105
+ console.log('║ This feature is coming soon! ║');
106
+ console.log('║ ║');
107
+ console.log('║ PromptUI Studio will provide: ║');
108
+ console.log('║ - Interactive component generation ║');
109
+ console.log('║ - Visual preview of generated components ║');
110
+ console.log('║ - Token management and sync ║');
111
+ console.log('║ - Claude AI integration for suggestions ║');
112
+ console.log('║ ║');
113
+ console.log('║ For now, use the CLI commands: ║');
114
+ console.log('║ - npx promptui generate <nodeId> ║');
115
+ console.log('║ - npx promptui generate all ║');
116
+ console.log('║ - npx promptui sync tokens ║');
117
+ console.log('║ ║');
118
+ console.log('╚════════════════════════════════════════════════════════╝');
119
+ console.log('');
120
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Sync Command
3
+ * Sincroniza tokens do Figma para o projeto local
4
+ */
5
+ export interface ISyncOptions {
6
+ output?: string;
7
+ }
8
+ export declare function syncTokensCommand(options: ISyncOptions): Promise<void>;
9
+ //# sourceMappingURL=sync.cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/sync.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA+JD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmH5E"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Sync Command
3
+ * Sincroniza tokens do Figma para o projeto local
4
+ */
5
+ import { writeFile, mkdir } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+ import { createFigmaClient } from '@promptui-lib/figma-parser';
8
+ import { loadConfig, resolveConfig, validateConfig } from '@promptui-lib/mcp-agent';
9
+ /**
10
+ * Converte cor RGB (0-1) para hex
11
+ */
12
+ function rgbToHex(color) {
13
+ const r = Math.round(color.r * 255).toString(16).padStart(2, '0');
14
+ const g = Math.round(color.g * 255).toString(16).padStart(2, '0');
15
+ const b = Math.round(color.b * 255).toString(16).padStart(2, '0');
16
+ return `#${r}${g}${b}`;
17
+ }
18
+ /**
19
+ * Converte nome do estilo para nome de variável SCSS
20
+ */
21
+ function styleNameToVariable(name) {
22
+ return name
23
+ .toLowerCase()
24
+ .replace(/[^a-z0-9]+/g, '-')
25
+ .replace(/^-|-$/g, '');
26
+ }
27
+ /**
28
+ * Gera arquivo SCSS de cores
29
+ */
30
+ function generateColorsScss(colors) {
31
+ const lines = [
32
+ '// PromptUI - Color Tokens',
33
+ '// Auto-generated from Figma styles',
34
+ '// Do not edit manually',
35
+ '',
36
+ ];
37
+ for (const color of colors) {
38
+ const varName = `$color-${styleNameToVariable(color.name)}`;
39
+ lines.push(`${varName}: ${color.value};`);
40
+ }
41
+ return lines.join('\n');
42
+ }
43
+ /**
44
+ * Gera arquivo SCSS de tipografia
45
+ */
46
+ function generateTypographyScss(textStyles) {
47
+ const lines = [
48
+ '// PromptUI - Typography Tokens',
49
+ '// Auto-generated from Figma styles',
50
+ '// Do not edit manually',
51
+ '',
52
+ ];
53
+ // Agrupa por categoria
54
+ const fontFamilies = new Set();
55
+ const fontSizes = new Map();
56
+ const fontWeights = new Set();
57
+ for (const style of textStyles) {
58
+ fontFamilies.add(style.fontFamily);
59
+ fontSizes.set(style.fontSize, style.name);
60
+ fontWeights.add(style.fontWeight);
61
+ }
62
+ // Font families
63
+ lines.push('// Font Families');
64
+ let familyIndex = 1;
65
+ for (const family of fontFamilies) {
66
+ lines.push(`$font-family-${familyIndex}: "${family}", sans-serif;`);
67
+ familyIndex++;
68
+ }
69
+ lines.push('');
70
+ // Font sizes
71
+ lines.push('// Font Sizes');
72
+ const sortedSizes = Array.from(fontSizes.entries()).sort((a, b) => a[0] - b[0]);
73
+ for (const [size, name] of sortedSizes) {
74
+ const varName = `$font-size-${styleNameToVariable(name)}`;
75
+ lines.push(`${varName}: ${size}px;`);
76
+ }
77
+ lines.push('');
78
+ // Font weights
79
+ lines.push('// Font Weights');
80
+ const weightNames = {
81
+ 100: 'thin',
82
+ 200: 'extralight',
83
+ 300: 'light',
84
+ 400: 'regular',
85
+ 500: 'medium',
86
+ 600: 'semibold',
87
+ 700: 'bold',
88
+ 800: 'extrabold',
89
+ 900: 'black',
90
+ };
91
+ const sortedWeights = Array.from(fontWeights).sort((a, b) => a - b);
92
+ for (const weight of sortedWeights) {
93
+ const name = weightNames[weight] ?? `w${weight}`;
94
+ lines.push(`$font-weight-${name}: ${weight};`);
95
+ }
96
+ return lines.join('\n');
97
+ }
98
+ /**
99
+ * Gera arquivo SCSS de efeitos (shadows)
100
+ */
101
+ function generateEffectsScss(effects) {
102
+ const lines = [
103
+ '// PromptUI - Effect Tokens',
104
+ '// Auto-generated from Figma styles',
105
+ '// Do not edit manually',
106
+ '',
107
+ '// Shadows',
108
+ ];
109
+ for (const effect of effects) {
110
+ if (effect.type === 'DROP_SHADOW' && effect.color) {
111
+ const varName = `$shadow-${styleNameToVariable(effect.name)}`;
112
+ const x = effect.offset?.x ?? 0;
113
+ const y = effect.offset?.y ?? 0;
114
+ const blur = effect.radius ?? 0;
115
+ const color = `rgba(${Math.round(effect.color.r * 255)}, ${Math.round(effect.color.g * 255)}, ${Math.round(effect.color.b * 255)}, ${effect.color.a.toFixed(2)})`;
116
+ lines.push(`${varName}: ${x}px ${y}px ${blur}px ${color};`);
117
+ }
118
+ }
119
+ return lines.join('\n');
120
+ }
121
+ export async function syncTokensCommand(options) {
122
+ console.log('[PromptUI] Syncing tokens from Figma...');
123
+ // Carrega config
124
+ const config = await loadConfig();
125
+ const resolved = resolveConfig(config);
126
+ // Valida
127
+ const errors = validateConfig(resolved);
128
+ if (errors.length > 0) {
129
+ console.error('[PromptUI] Configuration errors:');
130
+ for (const error of errors) {
131
+ console.error(` - ${error}`);
132
+ }
133
+ process.exit(1);
134
+ }
135
+ try {
136
+ const client = createFigmaClient({ token: resolved.figmaToken });
137
+ console.log('[PromptUI] Fetching styles from Figma...');
138
+ const stylesRecord = await client.getStyles(resolved.figmaFileId);
139
+ if (!stylesRecord || Object.keys(stylesRecord).length === 0) {
140
+ console.log('[PromptUI] No styles found in the Figma file.');
141
+ return;
142
+ }
143
+ const stylesArray = Object.values(stylesRecord);
144
+ console.log(`[PromptUI] Found ${stylesArray.length} styles`);
145
+ // Separa por tipo
146
+ const colorStyles = [];
147
+ const textStyles = [];
148
+ const effectStyles = [];
149
+ for (const style of stylesArray) {
150
+ // Aqui precisaríamos buscar os detalhes de cada style
151
+ // Por enquanto, apenas categoriza
152
+ if (style.styleType === 'FILL') {
153
+ // Placeholder - precisaria buscar o node para ter a cor
154
+ colorStyles.push({
155
+ name: style.name,
156
+ value: '#000000', // Placeholder
157
+ });
158
+ }
159
+ else if (style.styleType === 'TEXT') {
160
+ textStyles.push({
161
+ name: style.name,
162
+ fontFamily: 'Inter',
163
+ fontSize: 16,
164
+ fontWeight: 400,
165
+ });
166
+ }
167
+ else if (style.styleType === 'EFFECT') {
168
+ effectStyles.push({
169
+ name: style.name,
170
+ type: 'DROP_SHADOW',
171
+ });
172
+ }
173
+ }
174
+ // Cria diretório de output
175
+ const outputDir = options.output ?? join(process.cwd(), 'src/styles/tokens');
176
+ await mkdir(outputDir, { recursive: true });
177
+ // Gera arquivos
178
+ if (colorStyles.length > 0) {
179
+ const colorsPath = join(outputDir, '_colors.scss');
180
+ await writeFile(colorsPath, generateColorsScss(colorStyles), 'utf-8');
181
+ console.log(` ✅ Colors: ${colorsPath}`);
182
+ }
183
+ if (textStyles.length > 0) {
184
+ const typographyPath = join(outputDir, '_typography.scss');
185
+ await writeFile(typographyPath, generateTypographyScss(textStyles), 'utf-8');
186
+ console.log(` ✅ Typography: ${typographyPath}`);
187
+ }
188
+ if (effectStyles.length > 0) {
189
+ const effectsPath = join(outputDir, '_effects.scss');
190
+ await writeFile(effectsPath, generateEffectsScss(effectStyles), 'utf-8');
191
+ console.log(` ✅ Effects: ${effectsPath}`);
192
+ }
193
+ // Gera index
194
+ const indexPath = join(outputDir, '_index.scss');
195
+ const indexContent = [
196
+ '// PromptUI - Design Tokens',
197
+ '// Auto-generated from Figma',
198
+ '',
199
+ "@forward 'colors';",
200
+ "@forward 'typography';",
201
+ "@forward 'effects';",
202
+ '',
203
+ ].join('\n');
204
+ await writeFile(indexPath, indexContent, 'utf-8');
205
+ console.log(` ✅ Index: ${indexPath}`);
206
+ console.log('');
207
+ console.log('[PromptUI] Tokens synced successfully!');
208
+ }
209
+ catch (error) {
210
+ const message = error instanceof Error ? error.message : 'Unknown error';
211
+ console.error(`[PromptUI] Error: ${message}`);
212
+ process.exit(1);
213
+ }
214
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @promptui-lib/cli
3
+ * CLI for PromptUI - Figma to React code generator
4
+ */
5
+ export declare function run(args?: string[]): Promise<void>;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgEH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAkH/E"}
package/dist/index.js ADDED
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @promptui-lib/cli
3
+ * CLI for PromptUI - Figma to React code generator
4
+ */
5
+ import { parseArgs } from 'node:util';
6
+ import { startAgent } from '@promptui-lib/mcp-agent';
7
+ import { generateCommand, generateAllCommand } from './commands/generate.cmd.js';
8
+ import { initCommand } from './commands/init.cmd.js';
9
+ import { syncTokensCommand } from './commands/sync.cmd.js';
10
+ import { mcpCommand, studioCommand, listAgents } from './commands/mcp.cmd.js';
11
+ const HELP_TEXT = `
12
+ PromptUI - Figma to React Code Generator
13
+
14
+ Usage:
15
+ promptui <command> [options]
16
+
17
+ Commands:
18
+ init Initialize configuration file
19
+ agent Start the MCP agent server
20
+ generate Generate all #marked components (React + SCSS)
21
+ generate mui Generate all #marked components (Material UI)
22
+ generate tailwind Generate all #marked components (Tailwind CSS)
23
+ generate bootstrap Generate all #marked components (Bootstrap)
24
+ generate <nodeId> Generate specific node by ID
25
+ generate <file.json> Generate from local JSON file
26
+ sync tokens Sync design tokens from Figma
27
+ mcp <agent> [input] Run MCP agent (use 'mcp' alone to list agents)
28
+ studio Start PromptUI Studio (interactive mode)
29
+
30
+ Options:
31
+ --help, -h Show this help message
32
+ --version, -v Show version
33
+ --force, -f Force overwrite existing files
34
+ --output, -o Output directory
35
+ --layer, -l Force layer (atoms|molecules|organisms)
36
+ --preview, -p Preview output without writing files
37
+ --no-meta Skip generating meta.json
38
+
39
+ Frameworks:
40
+ react React + SCSS with BEM methodology (default)
41
+ mui Material UI with sx props and MUI components
42
+ tailwind Tailwind CSS utility classes
43
+ bootstrap Bootstrap CSS classes
44
+
45
+ Examples:
46
+ promptui init # Create promptui.config.json
47
+ promptui agent # Start agent on port 17890
48
+ promptui generate # Generate all (React + SCSS)
49
+ promptui generate mui # Generate all (Material UI)
50
+ promptui generate tailwind # Generate all (Tailwind CSS)
51
+ promptui generate bootstrap # Generate all (Bootstrap)
52
+ promptui generate 123:456 # Generate specific node
53
+ promptui generate ./button.json # Generate from local JSON
54
+ promptui generate ./button.json -p # Preview without writing
55
+ promptui sync tokens # Sync tokens from Figma
56
+
57
+ Environment Variables:
58
+ FIGMA_TOKEN Figma personal access token
59
+ FIGMA_FILE_ID Default Figma file ID
60
+ PROMPTUI_PORT Agent port (default: 17890)
61
+ PROMPTUI_OUTPUT_PATH Output path (default: src/components)
62
+ `;
63
+ const VERSION = '0.1.0';
64
+ export async function run(args = process.argv.slice(2)) {
65
+ const { values, positionals } = parseArgs({
66
+ args,
67
+ options: {
68
+ help: { type: 'boolean', short: 'h' },
69
+ version: { type: 'boolean', short: 'v' },
70
+ force: { type: 'boolean', short: 'f' },
71
+ output: { type: 'string', short: 'o' },
72
+ layer: { type: 'string', short: 'l' },
73
+ framework: { type: 'string', short: 'F' },
74
+ preview: { type: 'boolean', short: 'p' },
75
+ 'no-meta': { type: 'boolean' },
76
+ },
77
+ allowPositionals: true,
78
+ });
79
+ // Version (check first, before help)
80
+ if (values.version) {
81
+ console.log(`promptui v${VERSION}`);
82
+ return;
83
+ }
84
+ // Help
85
+ if (values.help || positionals.length === 0) {
86
+ console.log(HELP_TEXT);
87
+ return;
88
+ }
89
+ const command = positionals[0];
90
+ switch (command) {
91
+ // promptui init
92
+ case 'init':
93
+ await initCommand();
94
+ break;
95
+ // promptui agent
96
+ case 'agent':
97
+ await startAgent();
98
+ break;
99
+ // promptui generate [framework|nodeId|file.json]
100
+ case 'generate': {
101
+ const input = positionals[1];
102
+ const FRAMEWORKS = ['react', 'mui', 'tailwind', 'bootstrap'];
103
+ // Detecta se o input é um framework
104
+ const isFramework = input && FRAMEWORKS.includes(input);
105
+ // Se não tem input ou é um framework, gera todos os componentes
106
+ const generateAll = !input || isFramework;
107
+ // Define o framework (do input ou do flag)
108
+ const framework = isFramework
109
+ ? input
110
+ : values.framework;
111
+ const generateOptions = {
112
+ force: values.force,
113
+ output: values.output,
114
+ layer: values.layer,
115
+ framework,
116
+ preview: values.preview,
117
+ noMeta: values['no-meta'],
118
+ };
119
+ if (generateAll) {
120
+ await generateAllCommand(generateOptions);
121
+ }
122
+ else {
123
+ await generateCommand(input, generateOptions);
124
+ }
125
+ break;
126
+ }
127
+ // promptui sync <subcommand>
128
+ case 'sync': {
129
+ const subcommand = positionals[1];
130
+ if (subcommand === 'tokens') {
131
+ await syncTokensCommand({ output: values.output });
132
+ }
133
+ else {
134
+ console.error(`Unknown sync subcommand: ${subcommand}`);
135
+ console.log('Available: sync tokens');
136
+ process.exit(1);
137
+ }
138
+ break;
139
+ }
140
+ // promptui mcp [agent] [input]
141
+ case 'mcp': {
142
+ const agentKey = positionals[1];
143
+ const input = positionals[2];
144
+ if (!agentKey) {
145
+ listAgents();
146
+ }
147
+ else {
148
+ await mcpCommand(agentKey, input, {
149
+ output: values.output,
150
+ preview: values.preview,
151
+ });
152
+ }
153
+ break;
154
+ }
155
+ // promptui studio
156
+ case 'studio':
157
+ await studioCommand();
158
+ break;
159
+ default:
160
+ console.error(`Unknown command: ${command}`);
161
+ console.log(HELP_TEXT);
162
+ process.exit(1);
163
+ }
164
+ }
165
+ // Execute CLI when run directly
166
+ run().catch((error) => {
167
+ console.error('[PromptUI] Fatal error:', error.message);
168
+ process.exit(1);
169
+ });
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@promptui-lib/cli",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "CLI for PromptUI - Figma to React code generator",
6
+ "license": "UNLICENSED",
7
+ "author": {
8
+ "name": "Desiree Menezes",
9
+ "url": "https://github.com/desireemenezes"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/desireemenezes/promptUI.git",
14
+ "directory": "packages/cli"
15
+ },
16
+ "homepage": "https://github.com/desireemenezes/promptUI#readme",
17
+ "keywords": [
18
+ "figma",
19
+ "react",
20
+ "codegen",
21
+ "design-to-code",
22
+ "component-generator",
23
+ "scss",
24
+ "mui",
25
+ "tailwind",
26
+ "bootstrap"
27
+ ],
28
+ "type": "module",
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "bin": {
32
+ "promptui": "./bin/promptui.js"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js"
41
+ }
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "bin"
46
+ ],
47
+ "dependencies": {
48
+ "@promptui-lib/core": "0.1.0",
49
+ "@promptui-lib/figma-parser": "0.1.0",
50
+ "@promptui-lib/codegen": "0.1.0",
51
+ "@promptui-lib/mcp-agent": "0.1.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.0.0",
55
+ "typescript": "^5.3.0",
56
+ "rimraf": "^5.0.0"
57
+ },
58
+ "scripts": {
59
+ "build": "tsc",
60
+ "dev": "tsc --watch",
61
+ "clean": "rimraf dist"
62
+ }
63
+ }