ingresseflow-bridge 1.1.0 → 1.2.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.
package/dist/index.js CHANGED
@@ -179,10 +179,44 @@ server.tool('figjam_create_stickies', 'Cria múltiplos post-its de uma vez no Fi
179
179
  const result = await sendToPlugin('CREATE_STICKIES', { stickies });
180
180
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
181
181
  });
182
- server.tool('figjam_read_board', 'Lê todo o conteúdo do FigJam atual. Retorna nós com texto, posição e tipo.', {}, async () => {
183
- const result = await sendToPlugin('READ_BOARD', {});
182
+ server.tool('figjam_read_board', 'Lê o conteúdo do FigJam. Por padrão faz recursão dentro de sections/frames/groups. Retorna id, type, name, x, y, width, height, parentId, depth, text (se STICKY/TEXT/SHAPE_WITH_TEXT/CONNECTOR) e hasImage=true para nós com fill de imagem.', {
183
+ recursive: z.boolean().default(true).describe('Descer dentro de containers (section, frame, group)'),
184
+ maxDepth: z.number().default(10).describe('Profundidade máxima de recursão'),
185
+ filterTypes: z.array(z.string()).optional().describe('Filtra os nós retornados por tipo (ex.: ["STICKY","RECTANGLE","FRAME"]). A recursão continua mesmo em nós filtrados.'),
186
+ }, async ({ recursive, maxDepth, filterTypes }) => {
187
+ const result = await sendToPlugin('READ_BOARD', { recursive, maxDepth, filterTypes });
184
188
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
185
189
  });
190
+ server.tool('figjam_export_node', 'Exporta um nó (frame, image, section, qualquer SceneNode com exportAsync) como PNG/JPG/SVG/PDF e retorna a imagem renderizada para que Claude consiga visualizar prints/screenshots colados no canvas.', {
191
+ nodeId: z.string().describe('ID do nó a exportar'),
192
+ format: z.enum(['PNG', 'JPG', 'SVG', 'PDF']).default('PNG'),
193
+ scale: z.number().default(1).describe('Escala da exportação (1=original, 2=2x). Ignorado em SVG/PDF.'),
194
+ }, async ({ nodeId, format, scale }) => {
195
+ const result = await sendToPlugin('EXPORT_NODE', { nodeId, format, scale });
196
+ const mimeMap = {
197
+ PNG: 'image/png',
198
+ JPG: 'image/jpeg',
199
+ SVG: 'image/svg+xml',
200
+ PDF: 'application/pdf',
201
+ };
202
+ const mimeType = mimeMap[result.format] ?? 'image/png';
203
+ // Image formats Claude can render get image content; SVG/PDF fall back to text.
204
+ if (result.format === 'PNG' || result.format === 'JPG') {
205
+ return {
206
+ content: [
207
+ { type: 'image', data: result.base64, mimeType },
208
+ { type: 'text', text: JSON.stringify({
209
+ nodeId, format: result.format,
210
+ width: result.width, height: result.height,
211
+ byteLength: result.byteLength,
212
+ }) },
213
+ ],
214
+ };
215
+ }
216
+ return {
217
+ content: [{ type: 'text', text: JSON.stringify(result) }],
218
+ };
219
+ });
186
220
  server.tool('figjam_get_selection', 'Retorna os nós atualmente selecionados no Figma.', {}, async () => {
187
221
  const result = await sendToPlugin('GET_SELECTION', {});
188
222
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
@@ -297,7 +331,7 @@ server.tool('figjam_delete_nodes', 'Remove nós do canvas pelo ID.', {
297
331
  // Generic forwarder — lets new plugin operations be invoked without bridge updates.
298
332
  // Useful for evolving the plugin independently: any new op type added in code.ts
299
333
  // becomes immediately accessible via this tool.
300
- server.tool('figjam_execute', 'Encaminha uma operação arbitrária para o plugin (escape hatch para ops novas que ainda não têm tool dedicada). Tipos válidos atuais: PING, CREATE_STICKY, CREATE_STICKIES, CREATE_SECTION, CREATE_SHAPE, CREATE_SHAPES, CREATE_CONNECTOR, CREATE_CONNECTORS, CREATE_FLOW, SET_CONNECTOR_LABELS, MOVE_NODES, DELETE_NODES, READ_BOARD, GET_SELECTION.', {
334
+ server.tool('figjam_execute', 'Encaminha uma operação arbitrária para o plugin (escape hatch para ops novas que ainda não têm tool dedicada). Tipos válidos atuais: PING, CREATE_STICKY, CREATE_STICKIES, CREATE_SECTION, CREATE_SHAPE, CREATE_SHAPES, CREATE_CONNECTOR, CREATE_CONNECTORS, CREATE_FLOW, SET_CONNECTOR_LABELS, MOVE_NODES, DELETE_NODES, READ_BOARD, GET_SELECTION, EXPORT_NODE.', {
301
335
  type: z.string().describe('Nome da operação no plugin (ex.: CREATE_SHAPE)'),
302
336
  payload: z.record(z.unknown()).optional().describe('Payload da operação'),
303
337
  }, async ({ type, payload }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ingresseflow-bridge",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Bridge MCP server for IngresseFlow — connects Claude Code to FigJam via Figma Desktop plugin",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -216,14 +216,57 @@ server.tool(
216
216
 
217
217
  server.tool(
218
218
  'figjam_read_board',
219
- 'Lê todo o conteúdo do FigJam atual. Retorna nós com texto, posição e tipo.',
220
- {},
221
- async () => {
222
- const result = await sendToPlugin('READ_BOARD', {});
219
+ 'Lê o conteúdo do FigJam. Por padrão faz recursão dentro de sections/frames/groups. Retorna id, type, name, x, y, width, height, parentId, depth, text (se STICKY/TEXT/SHAPE_WITH_TEXT/CONNECTOR) e hasImage=true para nós com fill de imagem.',
220
+ {
221
+ recursive: z.boolean().default(true).describe('Descer dentro de containers (section, frame, group)'),
222
+ maxDepth: z.number().default(10).describe('Profundidade máxima de recursão'),
223
+ filterTypes: z.array(z.string()).optional().describe('Filtra os nós retornados por tipo (ex.: ["STICKY","RECTANGLE","FRAME"]). A recursão continua mesmo em nós filtrados.'),
224
+ },
225
+ async ({ recursive, maxDepth, filterTypes }) => {
226
+ const result = await sendToPlugin('READ_BOARD', { recursive, maxDepth, filterTypes });
223
227
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
224
228
  }
225
229
  );
226
230
 
231
+ server.tool(
232
+ 'figjam_export_node',
233
+ 'Exporta um nó (frame, image, section, qualquer SceneNode com exportAsync) como PNG/JPG/SVG/PDF e retorna a imagem renderizada para que Claude consiga visualizar prints/screenshots colados no canvas.',
234
+ {
235
+ nodeId: z.string().describe('ID do nó a exportar'),
236
+ format: z.enum(['PNG', 'JPG', 'SVG', 'PDF']).default('PNG'),
237
+ scale: z.number().default(1).describe('Escala da exportação (1=original, 2=2x). Ignorado em SVG/PDF.'),
238
+ },
239
+ async ({ nodeId, format, scale }) => {
240
+ const result = await sendToPlugin('EXPORT_NODE', { nodeId, format, scale }) as {
241
+ base64: string; format: string; width: number; height: number; byteLength: number;
242
+ };
243
+ const mimeMap: Record<string, string> = {
244
+ PNG: 'image/png',
245
+ JPG: 'image/jpeg',
246
+ SVG: 'image/svg+xml',
247
+ PDF: 'application/pdf',
248
+ };
249
+ const mimeType = mimeMap[result.format] ?? 'image/png';
250
+
251
+ // Image formats Claude can render get image content; SVG/PDF fall back to text.
252
+ if (result.format === 'PNG' || result.format === 'JPG') {
253
+ return {
254
+ content: [
255
+ { type: 'image', data: result.base64, mimeType },
256
+ { type: 'text', text: JSON.stringify({
257
+ nodeId, format: result.format,
258
+ width: result.width, height: result.height,
259
+ byteLength: result.byteLength,
260
+ }) },
261
+ ],
262
+ };
263
+ }
264
+ return {
265
+ content: [{ type: 'text', text: JSON.stringify(result) }],
266
+ };
267
+ }
268
+ );
269
+
227
270
  server.tool(
228
271
  'figjam_get_selection',
229
272
  'Retorna os nós atualmente selecionados no Figma.',
@@ -407,7 +450,7 @@ server.tool(
407
450
  // becomes immediately accessible via this tool.
408
451
  server.tool(
409
452
  'figjam_execute',
410
- 'Encaminha uma operação arbitrária para o plugin (escape hatch para ops novas que ainda não têm tool dedicada). Tipos válidos atuais: PING, CREATE_STICKY, CREATE_STICKIES, CREATE_SECTION, CREATE_SHAPE, CREATE_SHAPES, CREATE_CONNECTOR, CREATE_CONNECTORS, CREATE_FLOW, SET_CONNECTOR_LABELS, MOVE_NODES, DELETE_NODES, READ_BOARD, GET_SELECTION.',
453
+ 'Encaminha uma operação arbitrária para o plugin (escape hatch para ops novas que ainda não têm tool dedicada). Tipos válidos atuais: PING, CREATE_STICKY, CREATE_STICKIES, CREATE_SECTION, CREATE_SHAPE, CREATE_SHAPES, CREATE_CONNECTOR, CREATE_CONNECTORS, CREATE_FLOW, SET_CONNECTOR_LABELS, MOVE_NODES, DELETE_NODES, READ_BOARD, GET_SELECTION, EXPORT_NODE.',
411
454
  {
412
455
  type: z.string().describe('Nome da operação no plugin (ex.: CREATE_SHAPE)'),
413
456
  payload: z.record(z.unknown()).optional().describe('Payload da operação'),