squidclaw 2.8.0 → 3.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.
@@ -77,7 +77,16 @@ export class ToolRouter {
77
77
  '- Section: ## New Section [section]',
78
78
  '',
79
79
  'Example:',
80
- '---TOOL:pptx_slides:AI Report|dark|## Introduction\n- AI is transforming industries\n- Revenue growing 40% YoY\n\n## Growth [chart:bar]\n- 2020: 50\n- 2021: 80\n- 2022: 120\n- 2023: 200\n\n## Key Stats [stats]\n- 🌍 195 — Countries using AI\n- 💰 $500B — Market size\n- 🚀 40% — Annual growth---');
80
+ 'Write content in markdown. Engine auto-detects slide types from content:',
81
+ '- ## Heading = new slide',
82
+ '- [stats] + lines like "- 💰 $500B — Market size" = stats cards slide',
83
+ '- | col | col | table rows = table slide',
84
+ '- [chart] + "- label: value" lines = chart slide (pie/bar/doughnut)',
85
+ '- [timeline] + "1. Title — desc" = timeline slide',
86
+ '- > quoted text = quote slide',
87
+ '- Bullet lists = bullets slide',
88
+ '',
89
+ 'EXAMPLE: ---TOOL:pptx_slides:AI Market Report|executive|## Key Metrics\n[stats]\n- 🌍 195 — Countries\n- 💰 $500B — Market Size\n- 🚀 40% — Annual Growth\n- 👥 2.5M — AI Engineers\n\n## Revenue by Sector\n[chart]\n- Healthcare: 85\n- Finance: 72\n- Retail: 45\n- Energy: 38\n\n## Growth Timeline\n[timeline]\n1. 2020 — Early adoption phase\n2. 2022 — Rapid enterprise rollout\n3. 2024 — AI-first companies emerge\n4. 2026 — Full integration era\n\n## Market Data\n| Region | Revenue | Growth |\n| North America | $180B | 35% |\n| Europe | $120B | 28% |\n| Asia | $150B | 42% |\n\n> The companies that embrace AI today will define the industries of tomorrow.---');
81
90
 
82
91
  tools.push('', '### Spawn Sub-Agent Session',
83
92
  '---TOOL:session_spawn:task description---',
@@ -169,6 +178,18 @@ export class ToolRouter {
169
178
  '---TOOL:handoff:reason---',
170
179
  'Transfer the conversation to a human agent. Use when you cannot help further.');
171
180
 
181
+ tools.push('', '### Render Dashboard PRO (sends as image!)',
182
+ '---TOOL:dashboard:Title|theme|markdown content---',
183
+ 'Render a beautiful dashboard as image. Themes: dark, light, saudi, ocean, neon.',
184
+ 'Use same markdown format as presentations. Engine auto-detects: [stats], [chart], [table], [progress], [donut].',
185
+ 'EXAMPLE: ---TOOL:dashboard:Sales Dashboard|dark|## KPIs\n[stats]\n- 💰 $2.4M — Revenue (+12%)\n- 👥 1,234 — Customers (+8%)\n- 📈 78% — Conversion\n\n## Revenue by Product\n[chart]\n- Enterprise: 850\n- Pro: 420\n- Starter: 180\n\n## Targets\n[progress]\n- Q1 Revenue: 85%\n- New Customers: 72%\n- NPS Score: 91%---',
186
+ '', '### Render Chart (sends as image!)',
187
+ '---TOOL:canvas_chart:title|type|label:value,label:value---',
188
+ 'Render a chart (bar, pie, doughnut) as image. Separate items with commas.',
189
+ '', '### Render Custom HTML (sends as image!)',
190
+ '---TOOL:canvas_html:html content---',
191
+ 'Render any HTML as an image. Built-in dark theme CSS with cards, grids, stats, tables.');
192
+
172
193
  tools.push('', '### Pair Device',
173
194
  '---TOOL:node_pair:device name---',
174
195
  'Generate a pairing code for a new device (phone, PC, server).',
@@ -359,45 +380,32 @@ export class ToolRouter {
359
380
  }
360
381
  case 'pptx':
361
382
  case 'pptx_slides':
383
+ case 'pptx_pro':
362
384
  case 'powerpoint':
363
385
  case 'presentation': {
364
386
  try {
365
- const { PptxGenerator } = await import('./pptx.js');
366
- const gen = new PptxGenerator();
367
-
368
- // Parse: title|theme|content or just content
387
+ const { generatePresentation } = await import('./pptx-pro.js');
369
388
  const parts = toolArg.split('|');
370
- let title, theme, slideContent;
371
-
389
+ let title, theme, content;
372
390
  if (parts.length >= 3) {
373
391
  title = parts[0].trim();
374
392
  theme = parts[1].trim();
375
- slideContent = parts.slice(2).join('|');
393
+ content = parts.slice(2).join('|');
376
394
  } else if (parts.length === 2) {
377
395
  title = parts[0].trim();
378
- slideContent = parts[1];
379
- theme = 'corporate';
396
+ content = parts[1];
397
+ theme = 'executive';
380
398
  } else {
381
- // Try to extract title from first ## heading
382
- const firstH2 = toolArg.match(/^##\s+(.+)/m);
383
- title = firstH2 ? firstH2[1] : 'Presentation';
384
- slideContent = toolArg;
385
- theme = 'corporate';
399
+ const firstH = toolArg.match(/^#\s+(.+)/m);
400
+ title = firstH ? firstH[1] : 'Presentation';
401
+ content = toolArg;
402
+ theme = 'executive';
386
403
  }
387
-
388
- const slides = PptxGenerator.parseContent(slideContent);
389
- if (slides.length === 0) {
390
- toolResult = 'No slides found. Use ## headings and - bullet points.';
391
- break;
392
- }
393
-
394
- const result = await gen.create(title, slides, { theme });
395
-
396
- // Return file path for sending
404
+ const result = await generatePresentation({ title, theme, content });
397
405
  return {
398
406
  toolUsed: true,
399
407
  toolName: 'pptx',
400
- toolResult: 'PowerPoint created: ' + result.filename + ' (' + result.slideCount + ' slides)',
408
+ toolResult: 'PowerPoint created: ' + result.filename + ' (' + result.slides + ' slides, types: ' + result.types.join(', ') + ')',
401
409
  filePath: result.filepath,
402
410
  fileName: result.filename,
403
411
  cleanResponse
@@ -697,6 +705,47 @@ export class ToolRouter {
697
705
  }
698
706
  break;
699
707
  }
708
+ case 'canvas_dashboard':
709
+ case 'dashboard': {
710
+ try {
711
+ const { renderDashboard } = await import('./dashboard-pro.js');
712
+ const result = await renderDashboard(toolArg);
713
+ if (result.buffer) {
714
+ return { toolUsed: true, toolName: 'dashboard', toolResult: 'Dashboard rendered', imageBase64: result.buffer.toString('base64'), mimeType: 'image/png', cleanResponse };
715
+ } else {
716
+ return { toolUsed: true, toolName: 'dashboard', toolResult: 'Dashboard created', filePath: result.filepath, fileName: result.filename, cleanResponse };
717
+ }
718
+ } catch (err) { toolResult = 'Dashboard failed: ' + err.message; }
719
+ break;
720
+ }
721
+ case 'canvas_chart': {
722
+ if (!this._engine?.canvas) { toolResult = 'Canvas not available'; break; }
723
+ try {
724
+ const parts = toolArg.split('|');
725
+ const title = parts[0]?.trim() || 'Chart';
726
+ const type = parts[1]?.trim() || 'bar';
727
+ const items = [];
728
+ if (parts[2]) {
729
+ parts[2].split(',').forEach(c => {
730
+ const [label, value] = c.trim().split(':');
731
+ if (value) items.push({ label: label || '', value: parseInt(value) || 0 });
732
+ });
733
+ }
734
+ const result = await this._engine.canvas.renderChart({ title, type, items });
735
+ return { toolUsed: true, toolName: 'canvas', toolResult: 'Chart rendered', imageBase64: result.buffer.toString('base64'), mimeType: 'image/png', cleanResponse };
736
+ } catch (err) { toolResult = 'Canvas failed: ' + err.message; }
737
+ break;
738
+ }
739
+ case 'canvas_html':
740
+ case 'canvas_render':
741
+ case 'canvas': {
742
+ if (!this._engine?.canvas) { toolResult = 'Canvas not available'; break; }
743
+ try {
744
+ const result = await this._engine.canvas.renderHtml(toolArg);
745
+ return { toolUsed: true, toolName: 'canvas', toolResult: 'Rendered', imageBase64: result.buffer.toString('base64'), mimeType: 'image/png', cleanResponse };
746
+ } catch (err) { toolResult = 'Canvas failed: ' + err.message; }
747
+ break;
748
+ }
700
749
  case 'node_pair': {
701
750
  if (!this._engine?.nodeManager) { toolResult = 'Nodes not available'; break; }
702
751
  const token = this._engine.nodeManager.generatePairToken(agentId, toolArg || 'Device');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squidclaw",
3
- "version": "2.8.0",
3
+ "version": "3.1.0",
4
4
  "description": "🦑 AI agent platform — human-like agents for WhatsApp, Telegram & more",
5
5
  "main": "lib/engine.js",
6
6
  "bin": {