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.
- package/lib/engine.js +6 -0
- package/lib/features/canvas.js +228 -0
- package/lib/middleware/commands.js +47 -0
- package/lib/tools/dashboard-pro.js +340 -0
- package/lib/tools/pptx-pro.js +686 -0
- package/lib/tools/router.js +75 -26
- package/package.json +1 -1
package/lib/tools/router.js
CHANGED
|
@@ -77,7 +77,16 @@ export class ToolRouter {
|
|
|
77
77
|
'- Section: ## New Section [section]',
|
|
78
78
|
'',
|
|
79
79
|
'Example:',
|
|
80
|
-
'
|
|
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 {
|
|
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,
|
|
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
|
-
|
|
393
|
+
content = parts.slice(2).join('|');
|
|
376
394
|
} else if (parts.length === 2) {
|
|
377
395
|
title = parts[0].trim();
|
|
378
|
-
|
|
379
|
-
theme = '
|
|
396
|
+
content = parts[1];
|
|
397
|
+
theme = 'executive';
|
|
380
398
|
} else {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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.
|
|
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');
|