/** * Exporte l'affiche Penpot en PNG */ import http from 'http'; import fs from 'fs'; const MCP = { host: '192.168.1.150', port: 9002 }; let sessionId = null; let msgId = 1; function postMCP(body) { return new Promise((resolve, reject) => { const payload = JSON.stringify(body); const headers = { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload), 'Accept': 'application/json, text/event-stream', }; if (sessionId) headers['mcp-session-id'] = sessionId; const req = http.request({ ...MCP, path: '/mcp', method: 'POST', headers }, res => { if (res.headers['mcp-session-id']) sessionId = res.headers['mcp-session-id']; let data = ''; res.setEncoding('utf8'); res.on('data', c => data += c); res.on('end', () => { const ct = res.headers['content-type'] || ''; if (ct.includes('text/event-stream')) { let result = null, error = null; for (const line of data.split('\n')) { if (line.startsWith('data:')) { const raw = line.slice(5).trim(); if (!raw || raw === '[DONE]') continue; try { const j = JSON.parse(raw); if (j.result !== undefined) result = j.result; if (j.error) error = j.error; } catch {} } } if (error) reject(new Error(JSON.stringify(error))); else resolve(result); } else { try { const j = JSON.parse(data); if (j.error) reject(new Error(JSON.stringify(j.error))); else resolve(j.result ?? j); } catch { resolve(data || null); } } }); }); req.on('error', reject); req.write(payload); req.end(); }); } async function initMCP() { await postMCP({ jsonrpc: '2.0', id: msgId++, method: 'initialize', params: { protocolVersion: '2025-03-26', capabilities: {}, clientInfo: { name: 'nox', version: '1.0' } } }); await postMCP({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} }).catch(() => {}); console.log('✅ Session:', sessionId); } async function callTool(name, args = {}) { const result = await postMCP({ jsonrpc: '2.0', id: msgId++, method: 'tools/call', params: { name, arguments: args } }); if (!result) return null; if (result.content) { // Cherche le contenu JSON ou texte for (const c of result.content) { if (c.type === 'image') return c; // image directe try { return JSON.parse(c.text); } catch {} } return result.content.map(c => c.text).join('\n'); } return result; } await initMCP(); // Trouver le fichier créé const profile = await callTool('get_profile', {}); const projectId = profile?.defaultProjectId; const filesResult = await callTool('list_files', { projectId }); console.log('Files:', JSON.stringify(filesResult).slice(0, 400)); // Trouver l'affiche let fileId = null, fileName = null; if (Array.isArray(filesResult)) { const f = filesResult.find(f => f.name?.includes('SOLDES')); fileId = f?.id; fileName = f?.name; } else { const match = JSON.stringify(filesResult).match(/"id":"([0-9a-f-]+)"[^}]*"name":"[^"]*SOLDES/); if (match) fileId = match[1]; } console.log('Affiche fileId:', fileId, fileName); if (!fileId) { console.error('Fichier non trouvé'); process.exit(1); } // Lister les pages const pages = await callTool('list_pages', { fileId }); console.log('Pages:', JSON.stringify(pages).slice(0, 200)); let pageId = null; if (Array.isArray(pages)) pageId = pages[0]?.id; else { const m = JSON.stringify(pages).match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g); pageId = m?.find(u => u !== fileId); } console.log('PageId:', pageId); // Lister les shapes pour trouver le frame const shapes = await callTool('get_page_shapes', { fileId, pageId }); console.log('Shapes:', JSON.stringify(shapes).slice(0, 400)); // Trouver le frame principal let frameId = null; if (Array.isArray(shapes)) { const frame = shapes.find(s => s.name === 'Affiche SOLDES' || s.type === 'frame'); frameId = frame?.id; } else { const m = JSON.stringify(shapes).match(/"id":"([0-9a-f-]+)"/g); frameId = m?.[0]?.match(/"id":"([0-9a-f-]+)"/)?.[1]; } console.log('FrameId:', frameId); // Export en PNG console.log('\n📸 Export PNG...'); const exportResult = await callTool('export_shape', { fileId, pageId, shapeId: frameId, format: 'png', scale: 2, }); console.log('Export result type:', typeof exportResult, JSON.stringify(exportResult).slice(0, 300)); // Sauvegarder si base64 if (exportResult?.imageData || exportResult?.data) { const b64 = exportResult.imageData || exportResult.data; const buf = Buffer.from(b64, 'base64'); fs.writeFileSync('/home/node/.openclaw/workspace/affiche-soldes.png', buf); console.log('✅ Sauvegardé: affiche-soldes.png', buf.length, 'bytes'); } else if (exportResult?.url) { console.log('URL export:', exportResult.url); } else { console.log('Format inattendu:', JSON.stringify(exportResult).slice(0, 500)); }