@pinepaper.studio/mcp-server 1.5.3 → 1.5.4
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/README.md +6 -4
- package/dist/agent/types.d.ts +16 -16
- package/dist/browser/url-target.d.ts +26 -0
- package/dist/browser/url-target.d.ts.map +1 -0
- package/dist/browser/url-target.js +50 -0
- package/dist/browser/url-target.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -2
- package/dist/index.js.map +1 -1
- package/dist/ontology/hints.d.ts +71 -0
- package/dist/ontology/hints.d.ts.map +1 -0
- package/dist/ontology/hints.js +189 -0
- package/dist/ontology/hints.js.map +1 -0
- package/dist/ontology/vocabulary.d.ts.map +1 -1
- package/dist/ontology/vocabulary.js +34 -0
- package/dist/ontology/vocabulary.js.map +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +146 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/tools/compact-descriptions.d.ts +3 -0
- package/dist/tools/compact-descriptions.d.ts.map +1 -1
- package/dist/tools/compact-descriptions.js +17 -8
- package/dist/tools/compact-descriptions.js.map +1 -1
- package/dist/tools/definitions.d.ts +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +1090 -1639
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers/camera.d.ts +19 -0
- package/dist/tools/handlers/camera.d.ts.map +1 -0
- package/dist/tools/handlers/camera.js +94 -0
- package/dist/tools/handlers/camera.js.map +1 -0
- package/dist/tools/handlers/export.d.ts +12 -0
- package/dist/tools/handlers/export.d.ts.map +1 -0
- package/dist/tools/handlers/export.js +30 -0
- package/dist/tools/handlers/export.js.map +1 -0
- package/dist/tools/handlers/font.d.ts +12 -0
- package/dist/tools/handlers/font.d.ts.map +1 -0
- package/dist/tools/handlers/font.js +135 -0
- package/dist/tools/handlers/font.js.map +1 -0
- package/dist/tools/handlers/maps.d.ts +19 -0
- package/dist/tools/handlers/maps.d.ts.map +1 -0
- package/dist/tools/handlers/maps.js +184 -0
- package/dist/tools/handlers/maps.js.map +1 -0
- package/dist/tools/handlers/ontology.d.ts +20 -0
- package/dist/tools/handlers/ontology.d.ts.map +1 -0
- package/dist/tools/handlers/ontology.js +185 -0
- package/dist/tools/handlers/ontology.js.map +1 -0
- package/dist/tools/handlers/tool-guide.d.ts +14 -0
- package/dist/tools/handlers/tool-guide.d.ts.map +1 -0
- package/dist/tools/handlers/tool-guide.js +52 -0
- package/dist/tools/handlers/tool-guide.js.map +1 -0
- package/dist/tools/handlers.d.ts +18 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +205 -603
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/minimal-descriptions.d.ts +4 -0
- package/dist/tools/minimal-descriptions.d.ts.map +1 -1
- package/dist/tools/minimal-descriptions.js +45 -54
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +36 -45
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +36 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +823 -35
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +1116 -444
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +290 -18
- package/dist/types/schemas.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/handlers.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Supports browser execution via Puppeteer.
|
|
7
7
|
*/
|
|
8
8
|
import { codeGenerator } from '../types/code-generator.js';
|
|
9
|
-
import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, AddRelationInputSchema, RemoveRelationInputSchema, QueryRelationsInputSchema, AnimateItemInputSchema, KeyframeAnimateInputSchema, ExecuteGeneratorInputSchema, ApplyEffectInputSchema, GetItemsInputSchema, PlayTimelineInputSchema, SetBackgroundColorInputSchema, SetCanvasSizeInputSchema,
|
|
9
|
+
import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, AddRelationInputSchema, RemoveRelationInputSchema, QueryRelationsInputSchema, AnimateItemInputSchema, KeyframeAnimateInputSchema, ExecuteGeneratorInputSchema, ApplyEffectInputSchema, GetItemsInputSchema, PlayTimelineInputSchema, SetBackgroundColorInputSchema, SetCanvasSizeInputSchema, ImportSVGInputSchema, ImportMermaidInputSchema, AddFilterInputSchema, CreateGlossySphereInputSchema, CreateDiagonalStripesInputSchema, BatchCreateInputSchema, BatchModifyInputSchema, CreateGridInputSchema, CreateSceneInputSchema, GetPerformanceMetricsInputSchema, DiagnosticReportInputSchema, SearchAssetsInputSchema, ImportAssetInputSchema, P5DrawInputSchema,
|
|
10
10
|
// Diagram schemas
|
|
11
11
|
CreateDiagramShapeInputSchema, ConnectInputSchema, ConnectPortsInputSchema, AddPortsInputSchema, AutoLayoutInputSchema, GetDiagramShapesInputSchema, UpdateConnectorInputSchema, RemoveConnectorInputSchema, DiagramModeInputSchema,
|
|
12
12
|
// Agent flow mode schemas
|
|
@@ -17,10 +17,6 @@ AddTriggerInputSchema, RemoveTriggerInputSchema, QueryTriggersInputSchema,
|
|
|
17
17
|
CreateQuizInputSchema, GetQuizStateInputSchema, ResetQuizInputSchema,
|
|
18
18
|
// Letter collage schemas
|
|
19
19
|
CreateLetterCollageInputSchema, AnimateLetterCollageInputSchema,
|
|
20
|
-
// Map schemas
|
|
21
|
-
LoadMapInputSchema, HighlightRegionsInputSchema, UnhighlightRegionsInputSchema, ApplyDataColorsInputSchema, AddMarkerInputSchema, AddMapLabelsInputSchema, PanMapInputSchema, ZoomMapInputSchema, ImportCustomMapInputSchema, GetRegionAtPointInputSchema,
|
|
22
|
-
// Map animation/CSV schemas
|
|
23
|
-
AnimateMapRegionsInputSchema, AnimateMapWaveInputSchema, StopMapAnimationsInputSchema, ExportMapRegionCSVInputSchema, ImportMapRegionCSVInputSchema, SelectMapRegionsInputSchema, DeselectMapRegionsInputSchema,
|
|
24
20
|
// Custom relation/code schemas
|
|
25
21
|
RegisterCustomRelationInputSchema, ExecuteCustomCodeInputSchema,
|
|
26
22
|
// Mask schemas
|
|
@@ -29,22 +25,39 @@ ApplyAnimatedMaskInputSchema, ApplyCustomMaskInputSchema, RemoveMaskInputSchema,
|
|
|
29
25
|
ApplyTemplateInputSchema,
|
|
30
26
|
// Image import schemas
|
|
31
27
|
ImportImageInputSchema,
|
|
32
|
-
// Tool guide schema
|
|
33
|
-
ToolGuideInputSchema,
|
|
34
|
-
// Ontology schemas
|
|
35
|
-
AnalyzeDesignInputSchema, ValidateDesignInputSchema, QueryOntologyInputSchema,
|
|
36
28
|
// Scene management schemas
|
|
37
29
|
ManageScenesInputSchema, ScenePlaybackInputSchema,
|
|
38
30
|
// New consolidated tool schemas
|
|
39
|
-
SelectionInputSchema, TransformInputSchema, HistoryInputSchema, ImageFilterInputSchema, LassoInputSchema, CutoutStyleInputSchema, PrecompInputSchema, ViewInputSchema, BackgroundInputSchema, QueryInputSchema, ErrorCodes, } from '../types/schemas.js';
|
|
31
|
+
SelectionInputSchema, TransformInputSchema, HistoryInputSchema, ImageFilterInputSchema, LassoInputSchema, CutoutStyleInputSchema, PrecompInputSchema, ViewInputSchema, BackgroundInputSchema, QueryInputSchema, DeformInputSchema, SpriteSheetInputSchema, StorageInputSchema, InteractionInputSchema, ExportWidgetInputSchema, ExportWidgetHtmlInputSchema, CreateChartInputSchema, MagicInputSchema, PhysicsInputSchema, MeasurementInputSchema, ErrorCodes, } from '../types/schemas.js';
|
|
40
32
|
import { ZodError } from 'zod';
|
|
41
33
|
import { writeFile, mkdir } from 'node:fs/promises';
|
|
42
34
|
import { tmpdir } from 'node:os';
|
|
43
35
|
import { join } from 'node:path';
|
|
44
36
|
import { getBrowserController, resetBrowserController, } from '../browser/puppeteer-controller.js';
|
|
37
|
+
import { sameStudioTarget, validateStudioUrl } from '../browser/url-target.js';
|
|
45
38
|
import { getPerformanceTracker } from '../metrics/index.js';
|
|
46
39
|
import { formatErrorContext, captureCanvasState } from '../execution/index.js';
|
|
47
40
|
import { getSessionManager } from '../agent/session-manager.js';
|
|
41
|
+
import { vocabularyHintForPath, validateBatchVocabulary, detectBatchPropertyTypos } from '../ontology/hints.js';
|
|
42
|
+
import { cameraHandlers } from './handlers/camera.js';
|
|
43
|
+
import { fontHandlers } from './handlers/font.js';
|
|
44
|
+
import { toolGuideHandlers } from './handlers/tool-guide.js';
|
|
45
|
+
import { mapHandlers } from './handlers/maps.js';
|
|
46
|
+
import { ontologyHandlers } from './handlers/ontology.js';
|
|
47
|
+
import { exportHandlers } from './handlers/export.js';
|
|
48
|
+
/**
|
|
49
|
+
* Registry of per-domain handler maps. Tools listed here short-circuit the
|
|
50
|
+
* main switch at dispatch time (see handleToolCallInner). New domains are
|
|
51
|
+
* folded in incrementally as they are migrated out of the monolithic switch.
|
|
52
|
+
*/
|
|
53
|
+
const DOMAIN_HANDLERS = [
|
|
54
|
+
cameraHandlers,
|
|
55
|
+
fontHandlers,
|
|
56
|
+
toolGuideHandlers,
|
|
57
|
+
mapHandlers,
|
|
58
|
+
ontologyHandlers,
|
|
59
|
+
exportHandlers,
|
|
60
|
+
];
|
|
48
61
|
/**
|
|
49
62
|
* Get screenshot mode from environment variable.
|
|
50
63
|
* Defaults to 'on_request' for optimal performance.
|
|
@@ -146,7 +159,7 @@ function screenshotResult(screenshot) {
|
|
|
146
159
|
],
|
|
147
160
|
};
|
|
148
161
|
}
|
|
149
|
-
function errorResult(code, message, details, context) {
|
|
162
|
+
export function errorResult(code, message, details, context) {
|
|
150
163
|
// Build error object
|
|
151
164
|
const errorObj = {
|
|
152
165
|
success: false,
|
|
@@ -173,10 +186,18 @@ function handleValidationError(error, i18n) {
|
|
|
173
186
|
const message = i18n
|
|
174
187
|
? i18n.getError('validationError', { message: 'Invalid input parameters' })
|
|
175
188
|
: 'Invalid input parameters';
|
|
176
|
-
|
|
177
|
-
path
|
|
178
|
-
message: e.message
|
|
179
|
-
|
|
189
|
+
const details = error.errors.map((e) => {
|
|
190
|
+
const path = e.path.join('.');
|
|
191
|
+
const detail = { path, message: e.message };
|
|
192
|
+
if (e.code === 'invalid_enum_value') {
|
|
193
|
+
const received = e.received;
|
|
194
|
+
const hint = vocabularyHintForPath(path, received);
|
|
195
|
+
if (hint)
|
|
196
|
+
detail.vocabulary = hint;
|
|
197
|
+
}
|
|
198
|
+
return detail;
|
|
199
|
+
});
|
|
200
|
+
return errorResult(ErrorCodes.VALIDATION_ERROR, message, details);
|
|
180
201
|
}
|
|
181
202
|
/**
|
|
182
203
|
* Execute code in browser if connected, otherwise return generated code.
|
|
@@ -192,7 +213,7 @@ function handleValidationError(error, i18n) {
|
|
|
192
213
|
*
|
|
193
214
|
* Default is 'on_request' for optimal performance per best practices.
|
|
194
215
|
*/
|
|
195
|
-
async function executeOrGenerate(code, description, options, toolName) {
|
|
216
|
+
export async function executeOrGenerate(code, description, options, toolName) {
|
|
196
217
|
const { executeInBrowser, browserController, screenshotMode, executionMode } = options;
|
|
197
218
|
const effectiveExecutionMode = executionMode ?? getExecutionMode();
|
|
198
219
|
const effectiveScreenshotMode = screenshotMode ?? getScreenshotMode();
|
|
@@ -369,7 +390,7 @@ ${code}
|
|
|
369
390
|
// =============================================================================
|
|
370
391
|
// I18N HELPER FUNCTIONS
|
|
371
392
|
// =============================================================================
|
|
372
|
-
function getLocalizedSuccessMessage(i18n, key, params) {
|
|
393
|
+
export function getLocalizedSuccessMessage(i18n, key, params) {
|
|
373
394
|
if (!i18n) {
|
|
374
395
|
// Fallback to English template
|
|
375
396
|
return Object.entries(params).reduce((msg, [k, v]) => msg.replace(`{{${k}}}`, String(v)), key);
|
|
@@ -453,6 +474,14 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
453
474
|
async function handleToolCallInner(toolName, args, options, tracker, baseTimerId) {
|
|
454
475
|
const { i18n } = options;
|
|
455
476
|
try {
|
|
477
|
+
// Domain-module dispatch: tools migrated to per-domain handler files
|
|
478
|
+
// short-circuit before the main switch. See DOMAIN_HANDLERS for the
|
|
479
|
+
// current registry.
|
|
480
|
+
for (const domainMap of DOMAIN_HANDLERS) {
|
|
481
|
+
const handler = domainMap[toolName];
|
|
482
|
+
if (handler)
|
|
483
|
+
return await handler(args, options);
|
|
484
|
+
}
|
|
456
485
|
switch (toolName) {
|
|
457
486
|
// -----------------------------------------------------------------------
|
|
458
487
|
// ITEM TOOLS
|
|
@@ -493,7 +522,7 @@ async function handleToolCallInner(toolName, args, options, tracker, baseTimerId
|
|
|
493
522
|
const animProps = ['animationType', 'animationSpeed', 'keyframes', 'animation'];
|
|
494
523
|
const passedAnimProps = animProps.filter(p => p in (input.properties || {}));
|
|
495
524
|
if (passedAnimProps.length > 0) {
|
|
496
|
-
return errorResult(
|
|
525
|
+
return errorResult(ErrorCodes.INVALID_PROPERTIES, `Animation properties (${passedAnimProps.join(', ')}) cannot be set via pinepaper_modify_item — they will be silently ignored. ` +
|
|
497
526
|
`Use pinepaper_animate for loop animations (pulse, rotate, bounce, fade, wobble, slide) ` +
|
|
498
527
|
`or pinepaper_keyframe_animate for timed/sequenced animations with precise control.`);
|
|
499
528
|
}
|
|
@@ -608,6 +637,62 @@ async function handleToolCallInner(toolName, args, options, tracker, baseTimerId
|
|
|
608
637
|
return executeOrGenerate(code, `Query: ${input.action}`, options, 'pinepaper_query');
|
|
609
638
|
}
|
|
610
639
|
// -----------------------------------------------------------------------
|
|
640
|
+
// DEFORMATION, SPRITE SHEETS, STORAGE, INTERACTION
|
|
641
|
+
// -----------------------------------------------------------------------
|
|
642
|
+
case 'pinepaper_deform': {
|
|
643
|
+
const input = DeformInputSchema.parse(args);
|
|
644
|
+
const code = codeGenerator.generateDeform(input);
|
|
645
|
+
return executeOrGenerate(code, `Deform: ${input.action}`, options, 'pinepaper_deform');
|
|
646
|
+
}
|
|
647
|
+
case 'pinepaper_sprite_sheet': {
|
|
648
|
+
const input = SpriteSheetInputSchema.parse(args);
|
|
649
|
+
const code = codeGenerator.generateSpriteSheet(input);
|
|
650
|
+
return executeOrGenerate(code, `Sprite sheet: ${input.action}`, options, 'pinepaper_sprite_sheet');
|
|
651
|
+
}
|
|
652
|
+
case 'pinepaper_storage': {
|
|
653
|
+
const input = StorageInputSchema.parse(args);
|
|
654
|
+
const code = codeGenerator.generateStorage(input);
|
|
655
|
+
return executeOrGenerate(code, `Storage: ${input.action}`, options, 'pinepaper_storage');
|
|
656
|
+
}
|
|
657
|
+
case 'pinepaper_interaction': {
|
|
658
|
+
const input = InteractionInputSchema.parse(args);
|
|
659
|
+
const code = codeGenerator.generateInteraction(input);
|
|
660
|
+
return executeOrGenerate(code, `Interaction: ${input.action}`, options, 'pinepaper_interaction');
|
|
661
|
+
}
|
|
662
|
+
case 'pinepaper_export_widget': {
|
|
663
|
+
const input = ExportWidgetInputSchema.parse(args);
|
|
664
|
+
const code = codeGenerator.generateExportWidget(input);
|
|
665
|
+
return executeOrGenerate(code, 'Export widget JSON', options, 'pinepaper_export_widget');
|
|
666
|
+
}
|
|
667
|
+
case 'pinepaper_export_widget_html': {
|
|
668
|
+
const input = ExportWidgetHtmlInputSchema.parse(args);
|
|
669
|
+
const code = codeGenerator.generateExportWidgetHtml(input);
|
|
670
|
+
return executeOrGenerate(code, 'Export widget HTML', options, 'pinepaper_export_widget_html');
|
|
671
|
+
}
|
|
672
|
+
// -----------------------------------------------------------------------
|
|
673
|
+
// DATA VISUALIZATION, MAGIC, PHYSICS, MEASUREMENT
|
|
674
|
+
// -----------------------------------------------------------------------
|
|
675
|
+
case 'pinepaper_create_chart': {
|
|
676
|
+
const input = CreateChartInputSchema.parse(args);
|
|
677
|
+
const code = codeGenerator.generateChart(input);
|
|
678
|
+
return executeOrGenerate(code, `Chart: ${input.action}`, options, 'pinepaper_create_chart');
|
|
679
|
+
}
|
|
680
|
+
case 'pinepaper_magic': {
|
|
681
|
+
const input = MagicInputSchema.parse(args);
|
|
682
|
+
const code = codeGenerator.generateMagic(input);
|
|
683
|
+
return executeOrGenerate(code, `Magic: ${input.action}`, options, 'pinepaper_magic');
|
|
684
|
+
}
|
|
685
|
+
case 'pinepaper_physics': {
|
|
686
|
+
const input = PhysicsInputSchema.parse(args);
|
|
687
|
+
const code = codeGenerator.generatePhysics(input);
|
|
688
|
+
return executeOrGenerate(code, `Physics: ${input.action}`, options, 'pinepaper_physics');
|
|
689
|
+
}
|
|
690
|
+
case 'pinepaper_measurement': {
|
|
691
|
+
const input = MeasurementInputSchema.parse(args);
|
|
692
|
+
const code = codeGenerator.generateMeasurement(input);
|
|
693
|
+
return executeOrGenerate(code, `Measurement: ${input.action}`, options, 'pinepaper_measurement');
|
|
694
|
+
}
|
|
695
|
+
// -----------------------------------------------------------------------
|
|
611
696
|
// BATCH OPERATION TOOLS
|
|
612
697
|
// -----------------------------------------------------------------------
|
|
613
698
|
case 'pinepaper_batch_create': {
|
|
@@ -750,168 +835,11 @@ async function handleToolCallInner(toolName, args, options, tracker, baseTimerId
|
|
|
750
835
|
return executeOrGenerate(code, 'Gets available mask animation presets', options, 'pinepaper_get_mask_animations');
|
|
751
836
|
}
|
|
752
837
|
// -----------------------------------------------------------------------
|
|
753
|
-
// CAMERA TOOLS
|
|
754
|
-
// -----------------------------------------------------------------------
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
const loop = args.loop ?? false;
|
|
759
|
-
const delay = args.delay ?? 0;
|
|
760
|
-
const keyframesStr = JSON.stringify(keyframes);
|
|
761
|
-
const code = `app.camera && app.camera.animate ? app.camera.animate(${keyframesStr}, ${duration}, ${loop}, ${delay}) : app.addRelation('camera', 'camera', 'camera_animates', { keyframes: ${keyframesStr}, duration: ${duration}, loop: ${loop}, delay: ${delay} });`;
|
|
762
|
-
return executeOrGenerate(code, `Animates camera with ${keyframes.length} keyframes over ${duration}s`, options, 'pinepaper_camera_animate');
|
|
763
|
-
}
|
|
764
|
-
case 'pinepaper_camera_zoom': {
|
|
765
|
-
const direction = args.direction;
|
|
766
|
-
const level = args.level ?? (direction === 'in' ? 2 : 0.5);
|
|
767
|
-
const duration = args.duration ?? 0.5;
|
|
768
|
-
const method = direction === 'in' ? 'zoomIn' : 'zoomOut';
|
|
769
|
-
const code = `app.camera && app.camera.${method} ? app.camera.${method}(${level}, ${duration}) : null;`;
|
|
770
|
-
return executeOrGenerate(code, `Camera zoom ${direction} to ${level}x`, options, 'pinepaper_camera_zoom');
|
|
771
|
-
}
|
|
772
|
-
case 'pinepaper_camera_pan': {
|
|
773
|
-
const direction = args.direction;
|
|
774
|
-
const amount = args.amount ?? 100;
|
|
775
|
-
const x = args.x;
|
|
776
|
-
const y = args.y;
|
|
777
|
-
const duration = args.duration ?? 0.5;
|
|
778
|
-
let code;
|
|
779
|
-
let description;
|
|
780
|
-
if (x !== undefined && y !== undefined) {
|
|
781
|
-
code = `app.camera && app.camera.panTo ? app.camera.panTo(${x}, ${y}, ${duration}) : null;`;
|
|
782
|
-
description = `Camera pan to (${x}, ${y})`;
|
|
783
|
-
}
|
|
784
|
-
else if (direction) {
|
|
785
|
-
const methodMap = { left: 'panLeft', right: 'panRight', up: 'panUp', down: 'panDown' };
|
|
786
|
-
const method = methodMap[direction];
|
|
787
|
-
code = `app.camera && app.camera.${method} ? app.camera.${method}(${amount}, ${duration}) : null;`;
|
|
788
|
-
description = `Camera pan ${direction} by ${amount}px`;
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
code = `// No direction or coordinates specified`;
|
|
792
|
-
description = 'Camera pan (no parameters)';
|
|
793
|
-
}
|
|
794
|
-
return executeOrGenerate(code, description, options, 'pinepaper_camera_pan');
|
|
795
|
-
}
|
|
796
|
-
case 'pinepaper_camera_move_to': {
|
|
797
|
-
const x = args.x;
|
|
798
|
-
const y = args.y;
|
|
799
|
-
const zoom = args.zoom;
|
|
800
|
-
const duration = args.duration ?? 0.5;
|
|
801
|
-
const code = `app.camera && app.camera.moveTo ? app.camera.moveTo(${x}, ${y}, ${zoom}, ${duration}) : null;`;
|
|
802
|
-
return executeOrGenerate(code, `Camera move to (${x}, ${y}) at ${zoom}x zoom`, options, 'pinepaper_camera_move_to');
|
|
803
|
-
}
|
|
804
|
-
case 'pinepaper_camera_reset': {
|
|
805
|
-
const duration = args.duration ?? 0.5;
|
|
806
|
-
const code = `app.camera && app.camera.reset ? app.camera.reset(${duration}) : null;`;
|
|
807
|
-
return executeOrGenerate(code, 'Reset camera to default state', options, 'pinepaper_camera_reset');
|
|
808
|
-
}
|
|
809
|
-
case 'pinepaper_camera_stop': {
|
|
810
|
-
const code = `app.camera && app.camera.stop ? app.camera.stop() : null;`;
|
|
811
|
-
return executeOrGenerate(code, 'Stop camera animation', options, 'pinepaper_camera_stop');
|
|
812
|
-
}
|
|
813
|
-
case 'pinepaper_camera_state': {
|
|
814
|
-
const code = `app.camera && app.camera.getState ? app.camera.getState() : { zoom: 1, center: [400, 300], isAnimating: false };`;
|
|
815
|
-
return executeOrGenerate(code, 'Get current camera state', options, 'pinepaper_camera_state');
|
|
816
|
-
}
|
|
817
|
-
// -----------------------------------------------------------------------
|
|
818
|
-
// FONT TOOLS
|
|
819
|
-
// -----------------------------------------------------------------------
|
|
820
|
-
case 'pinepaper_font_show_studio': {
|
|
821
|
-
const code = `app.fontStudio && app.fontStudio.show ? app.fontStudio.show() : null;`;
|
|
822
|
-
return executeOrGenerate(code, 'Opens Font Studio UI', options, 'pinepaper_font_show_studio');
|
|
823
|
-
}
|
|
824
|
-
case 'pinepaper_font_set_name': {
|
|
825
|
-
const { name } = args;
|
|
826
|
-
const code = `app.fontStudio.setName(${JSON.stringify(name)});`;
|
|
827
|
-
return executeOrGenerate(code, `Set font name to "${name}"`, options, 'pinepaper_font_set_name');
|
|
828
|
-
}
|
|
829
|
-
case 'pinepaper_font_get_required_chars': {
|
|
830
|
-
const { set } = args;
|
|
831
|
-
const setArg = set ? JSON.stringify(set) : '"minimum"';
|
|
832
|
-
const code = `app.fontStudio.getRequiredChars(${setArg});`;
|
|
833
|
-
return executeOrGenerate(code, `Get required characters (${set || 'minimum'} set)`, options, 'pinepaper_font_get_required_chars');
|
|
834
|
-
}
|
|
835
|
-
case 'pinepaper_font_get_status': {
|
|
836
|
-
const code = `app.fontStudio.getStatus();`;
|
|
837
|
-
return executeOrGenerate(code, 'Get font completion status', options, 'pinepaper_font_get_status');
|
|
838
|
-
}
|
|
839
|
-
case 'pinepaper_font_create_glyph': {
|
|
840
|
-
const { character, pathId } = args;
|
|
841
|
-
const code = `app.fontStudio.createGlyph(${JSON.stringify(character)}, ${JSON.stringify(pathId)});`;
|
|
842
|
-
return executeOrGenerate(code, `Create glyph for "${character}" from path ${pathId}`, options, 'pinepaper_font_create_glyph');
|
|
843
|
-
}
|
|
844
|
-
case 'pinepaper_font_create_space': {
|
|
845
|
-
const { width } = args;
|
|
846
|
-
const code = width !== undefined
|
|
847
|
-
? `app.fontStudio.createSpace(${width});`
|
|
848
|
-
: `app.fontStudio.createSpace();`;
|
|
849
|
-
return executeOrGenerate(code, `Create space glyph${width ? ` (width: ${width})` : ''}`, options, 'pinepaper_font_create_space');
|
|
850
|
-
}
|
|
851
|
-
case 'pinepaper_font_remove_glyph': {
|
|
852
|
-
const { character } = args;
|
|
853
|
-
const code = `app.fontStudio.removeGlyph(${JSON.stringify(character)});`;
|
|
854
|
-
return executeOrGenerate(code, `Remove glyph for "${character}"`, options, 'pinepaper_font_remove_glyph');
|
|
855
|
-
}
|
|
856
|
-
case 'pinepaper_font_set_metrics': {
|
|
857
|
-
const metrics = args;
|
|
858
|
-
const code = `app.fontStudio.setMetrics(${JSON.stringify(metrics)});`;
|
|
859
|
-
return executeOrGenerate(code, 'Set font metrics', options, 'pinepaper_font_set_metrics');
|
|
860
|
-
}
|
|
861
|
-
case 'pinepaper_font_export': {
|
|
862
|
-
const { download } = args;
|
|
863
|
-
const code = download === false
|
|
864
|
-
? `app.fontStudio.export({ download: false });`
|
|
865
|
-
: `app.fontStudio.export();`;
|
|
866
|
-
return executeOrGenerate(code, 'Export font as OTF', options, 'pinepaper_font_export');
|
|
867
|
-
}
|
|
868
|
-
case 'pinepaper_font_load_into_document': {
|
|
869
|
-
const code = `app.fontStudio.loadIntoDocument();`;
|
|
870
|
-
return executeOrGenerate(code, 'Load font into document', options, 'pinepaper_font_load_into_document');
|
|
871
|
-
}
|
|
872
|
-
case 'pinepaper_font_export_data': {
|
|
873
|
-
const { download } = args;
|
|
874
|
-
const code = download === false
|
|
875
|
-
? `app.fontStudio.exportData({ download: false });`
|
|
876
|
-
: `app.fontStudio.exportData();`;
|
|
877
|
-
return executeOrGenerate(code, 'Export font data as JSON', options, 'pinepaper_font_export_data');
|
|
878
|
-
}
|
|
879
|
-
case 'pinepaper_font_import_data': {
|
|
880
|
-
const { data } = args;
|
|
881
|
-
const code = `app.fontStudio.importData(${JSON.stringify(data)});`;
|
|
882
|
-
return executeOrGenerate(code, 'Import font data from JSON', options, 'pinepaper_font_import_data');
|
|
883
|
-
}
|
|
884
|
-
case 'pinepaper_font_clear': {
|
|
885
|
-
const code = `app.fontStudio.clear();`;
|
|
886
|
-
return executeOrGenerate(code, 'Clear all glyphs and reset font', options, 'pinepaper_font_clear');
|
|
887
|
-
}
|
|
888
|
-
case 'pinepaper_font_remove_overlap': {
|
|
889
|
-
const { pathId } = args;
|
|
890
|
-
const code = `app.fontStudio.removeOverlap(${JSON.stringify(pathId)});`;
|
|
891
|
-
return executeOrGenerate(code, `Remove overlaps from path ${pathId}`, options, 'pinepaper_font_remove_overlap');
|
|
892
|
-
}
|
|
893
|
-
case 'pinepaper_font_correct_direction': {
|
|
894
|
-
const { pathId } = args;
|
|
895
|
-
const code = `app.fontStudio.correctDirection(${JSON.stringify(pathId)});`;
|
|
896
|
-
return executeOrGenerate(code, `Correct path direction for ${pathId}`, options, 'pinepaper_font_correct_direction');
|
|
897
|
-
}
|
|
898
|
-
case 'pinepaper_font_cleanup_path': {
|
|
899
|
-
const { pathId, removeOverlap, correctDirection, smooth, smoothTolerance } = args;
|
|
900
|
-
const optsObj = {};
|
|
901
|
-
if (removeOverlap !== undefined)
|
|
902
|
-
optsObj.removeOverlap = removeOverlap;
|
|
903
|
-
if (correctDirection !== undefined)
|
|
904
|
-
optsObj.correctDirection = correctDirection;
|
|
905
|
-
if (smooth !== undefined)
|
|
906
|
-
optsObj.smooth = smooth;
|
|
907
|
-
if (smoothTolerance !== undefined)
|
|
908
|
-
optsObj.smoothTolerance = smoothTolerance;
|
|
909
|
-
const hasOpts = Object.keys(optsObj).length > 0;
|
|
910
|
-
const code = hasOpts
|
|
911
|
-
? `app.fontStudio.cleanupPath(${JSON.stringify(pathId)}, ${JSON.stringify(optsObj)});`
|
|
912
|
-
: `app.fontStudio.cleanupPath(${JSON.stringify(pathId)});`;
|
|
913
|
-
return executeOrGenerate(code, `Cleanup path ${pathId}`, options, 'pinepaper_font_cleanup_path');
|
|
914
|
-
}
|
|
838
|
+
// CAMERA TOOLS — extracted to src/tools/handlers/camera.ts
|
|
839
|
+
// -----------------------------------------------------------------------
|
|
840
|
+
// -----------------------------------------------------------------------
|
|
841
|
+
// FONT TOOLS — extracted to src/tools/handlers/font.ts
|
|
842
|
+
// -----------------------------------------------------------------------
|
|
915
843
|
// -----------------------------------------------------------------------
|
|
916
844
|
// QUERY TOOLS
|
|
917
845
|
// -----------------------------------------------------------------------
|
|
@@ -956,7 +884,7 @@ async function handleToolCallInner(toolName, args, options, tracker, baseTimerId
|
|
|
956
884
|
case 'pinepaper_refresh_page': {
|
|
957
885
|
const controller = options.browserController || getBrowserController();
|
|
958
886
|
if (!controller.connected) {
|
|
959
|
-
return errorResult(
|
|
887
|
+
return errorResult(ErrorCodes.BROWSER_NOT_CONNECTED, 'Not connected to PinePaper Studio. Call pinepaper_browser_connect first.');
|
|
960
888
|
}
|
|
961
889
|
try {
|
|
962
890
|
// Refresh the page
|
|
@@ -985,7 +913,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
985
913
|
return { content };
|
|
986
914
|
}
|
|
987
915
|
catch (error) {
|
|
988
|
-
return errorResult(
|
|
916
|
+
return errorResult(ErrorCodes.REFRESH_FAILED, error instanceof Error ? error.message : 'Failed to refresh page');
|
|
989
917
|
}
|
|
990
918
|
}
|
|
991
919
|
// -----------------------------------------------------------------------
|
|
@@ -997,6 +925,15 @@ You can now start creating new items on a clean canvas.`,
|
|
|
997
925
|
const description = 'Imports SVG onto the canvas';
|
|
998
926
|
return executeOrGenerate(code, description, options, 'pinepaper_import_svg');
|
|
999
927
|
}
|
|
928
|
+
case 'pinepaper_import_mermaid': {
|
|
929
|
+
const input = ImportMermaidInputSchema.parse(args);
|
|
930
|
+
const code = codeGenerator.generateImportMermaid(input.mermaidText, {
|
|
931
|
+
autoLayout: input.autoLayout,
|
|
932
|
+
clearExisting: input.clearExisting,
|
|
933
|
+
});
|
|
934
|
+
const description = 'Imports a Mermaid diagram onto the canvas';
|
|
935
|
+
return executeOrGenerate(code, description, options, 'pinepaper_import_mermaid');
|
|
936
|
+
}
|
|
1000
937
|
// -----------------------------------------------------------------------
|
|
1001
938
|
// FILTER TOOLS
|
|
1002
939
|
// -----------------------------------------------------------------------
|
|
@@ -1007,46 +944,43 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1007
944
|
return executeOrGenerate(code, description, options, 'pinepaper_add_filter');
|
|
1008
945
|
}
|
|
1009
946
|
// -----------------------------------------------------------------------
|
|
1010
|
-
// EXPORT TOOLS
|
|
947
|
+
// EXPORT TOOLS — extracted to src/tools/handlers/export.ts
|
|
1011
948
|
// -----------------------------------------------------------------------
|
|
1012
|
-
case 'pinepaper_export_svg': {
|
|
1013
|
-
const code = codeGenerator.generateExportSVG();
|
|
1014
|
-
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
1015
|
-
format: 'SVG',
|
|
1016
|
-
});
|
|
1017
|
-
return executeOrGenerate(code, description, options, 'pinepaper_export_svg');
|
|
1018
|
-
}
|
|
1019
|
-
case 'pinepaper_export_training_data': {
|
|
1020
|
-
const input = ExportTrainingDataInputSchema.parse(args);
|
|
1021
|
-
const code = codeGenerator.generateExportTrainingData(input.format, input.includeMetadata);
|
|
1022
|
-
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
1023
|
-
format: input.format?.toUpperCase() || 'JSON',
|
|
1024
|
-
});
|
|
1025
|
-
return executeOrGenerate(code, description, options, 'pinepaper_export_training_data');
|
|
1026
|
-
}
|
|
1027
|
-
case 'pinepaper_export_scene': {
|
|
1028
|
-
const code = codeGenerator.generateExportScene();
|
|
1029
|
-
return executeOrGenerate(code, 'Exports complete scene state', options, 'pinepaper_export_scene');
|
|
1030
|
-
}
|
|
1031
949
|
// -----------------------------------------------------------------------
|
|
1032
950
|
// BROWSER CONTROL TOOLS
|
|
1033
951
|
// -----------------------------------------------------------------------
|
|
1034
952
|
case 'pinepaper_browser_connect': {
|
|
1035
953
|
// Default to headless: false — if you explicitly call browser_connect, you likely want to see it
|
|
1036
954
|
const headless = args.headless ?? false;
|
|
1037
|
-
|
|
1038
|
-
//
|
|
1039
|
-
|
|
955
|
+
// Target a custom Studio instance (e.g. local dev at http://localhost:3000).
|
|
956
|
+
// Falls back to the PINEPAPER_STUDIO_URL env var, else PuppeteerController's
|
|
957
|
+
// built-in prod default. "/editor" + agent params are appended by the controller.
|
|
958
|
+
const rawUrl = typeof args.url === 'string' ? args.url.trim() : '';
|
|
959
|
+
const studioUrl = (rawUrl || (process.env.PINEPAPER_STUDIO_URL || '').trim()) || undefined;
|
|
960
|
+
// Only http(s) is supported — reject file://, data://, javascript:, etc.
|
|
961
|
+
if (studioUrl) {
|
|
962
|
+
const v = validateStudioUrl(studioUrl);
|
|
963
|
+
if (!v.ok)
|
|
964
|
+
return errorResult(ErrorCodes.INVALID_INPUT, v.error);
|
|
965
|
+
}
|
|
966
|
+
const cfg = studioUrl ? { headless, studioUrl } : { headless };
|
|
967
|
+
const controller = getBrowserController(cfg);
|
|
968
|
+
const urlChanged = !!studioUrl && controller.connected &&
|
|
969
|
+
!sameStudioTarget(controller.studioUrl, studioUrl);
|
|
970
|
+
// Already connected, same headless mode, same URL → nothing to do
|
|
971
|
+
if (controller.connected && controller.isHeadless === headless && !urlChanged) {
|
|
1040
972
|
return {
|
|
1041
|
-
content: [{ type: 'text', text: `Already connected to PinePaper Studio (headless: ${headless}).` }],
|
|
973
|
+
content: [{ type: 'text', text: `Already connected to PinePaper Studio (${controller.studioUrl || 'default'}, headless: ${headless}).` }],
|
|
1042
974
|
};
|
|
1043
975
|
}
|
|
1044
|
-
//
|
|
1045
|
-
|
|
976
|
+
// Connected but headless mode OR target URL changed → tear down so the
|
|
977
|
+
// new config takes effect (getBrowserController ignores config once the
|
|
978
|
+
// singleton exists).
|
|
979
|
+
if (controller.connected && (controller.isHeadless !== headless || urlChanged)) {
|
|
1046
980
|
await resetBrowserController();
|
|
1047
981
|
}
|
|
1048
982
|
try {
|
|
1049
|
-
const newController = controller.connected ? controller : getBrowserController(
|
|
983
|
+
const newController = controller.connected ? controller : getBrowserController(cfg);
|
|
1050
984
|
if (!newController.connected)
|
|
1051
985
|
await newController.connect();
|
|
1052
986
|
const canvasSizeResult = await newController.executeCode(`const size = app.getCanvasSize ? app.getCanvasSize() : { width: 800, height: 600 }; ({ width: size.width || 800, height: size.height || 600 });`, false);
|
|
@@ -1054,7 +988,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1054
988
|
? canvasSizeResult.result
|
|
1055
989
|
: { width: 800, height: 600 };
|
|
1056
990
|
return {
|
|
1057
|
-
content: [{ type: 'text', text: `Connected to PinePaper Studio (headless: ${headless}, canvas: ${canvasSize.width}x${canvasSize.height}).` }],
|
|
991
|
+
content: [{ type: 'text', text: `Connected to PinePaper Studio (${newController.studioUrl || 'default'}, headless: ${headless}, canvas: ${canvasSize.width}x${canvasSize.height}).` }],
|
|
1058
992
|
};
|
|
1059
993
|
}
|
|
1060
994
|
catch (error) {
|
|
@@ -1089,13 +1023,13 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1089
1023
|
case 'pinepaper_browser_screenshot': {
|
|
1090
1024
|
const controller = getBrowserController();
|
|
1091
1025
|
if (!controller.connected) {
|
|
1092
|
-
return errorResult(
|
|
1026
|
+
return errorResult(ErrorCodes.BROWSER_NOT_CONNECTED, 'Not connected to PinePaper Studio. Call pinepaper_browser_connect first.');
|
|
1093
1027
|
}
|
|
1094
1028
|
const screenshot = await controller.takeScreenshot();
|
|
1095
1029
|
if (!screenshot) {
|
|
1096
1030
|
// Capture canvas state for debugging
|
|
1097
1031
|
const canvasState = await captureCanvasState(controller);
|
|
1098
|
-
return errorResult(
|
|
1032
|
+
return errorResult(ErrorCodes.SCREENSHOT_FAILED, 'Failed to capture screenshot', undefined, {
|
|
1099
1033
|
toolName: 'pinepaper_browser_screenshot',
|
|
1100
1034
|
canvasState: canvasState || undefined,
|
|
1101
1035
|
});
|
|
@@ -1382,54 +1316,8 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1382
1316
|
};
|
|
1383
1317
|
}
|
|
1384
1318
|
// -----------------------------------------------------------------------
|
|
1385
|
-
// TOOL GUIDE
|
|
1319
|
+
// TOOL GUIDE — extracted to src/tools/handlers/tool-guide.ts
|
|
1386
1320
|
// -----------------------------------------------------------------------
|
|
1387
|
-
case 'pinepaper_tool_guide': {
|
|
1388
|
-
const input = ToolGuideInputSchema.parse(args);
|
|
1389
|
-
const { PINEPAPER_TOOLS, AI_AGENT_GUIDE } = await import('./definitions.js');
|
|
1390
|
-
const { TOOL_TAGS } = await import('./toolkits.js');
|
|
1391
|
-
// No args → full AI Agent Guide
|
|
1392
|
-
if (!input.tool && !input.category) {
|
|
1393
|
-
return {
|
|
1394
|
-
content: [{ type: 'text', text: AI_AGENT_GUIDE }],
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
// Specific tool → full verbose description
|
|
1398
|
-
if (input.tool) {
|
|
1399
|
-
const tool = PINEPAPER_TOOLS.find((t) => t.name === input.tool);
|
|
1400
|
-
if (!tool) {
|
|
1401
|
-
return {
|
|
1402
|
-
content: [{ type: 'text', text: `Unknown tool: ${input.tool}. Use pinepaper_tool_guide with no args to see the AI Agent Guide.` }],
|
|
1403
|
-
isError: true,
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
return {
|
|
1407
|
-
content: [{ type: 'text', text: `# ${tool.name}\n\n${tool.description}` }],
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
// Category → all tools in that tag with descriptions
|
|
1411
|
-
if (input.category) {
|
|
1412
|
-
const toolNames = TOOL_TAGS[input.category];
|
|
1413
|
-
if (!toolNames) {
|
|
1414
|
-
const available = Object.keys(TOOL_TAGS).join(', ');
|
|
1415
|
-
return {
|
|
1416
|
-
content: [{ type: 'text', text: `Unknown category: ${input.category}. Available: ${available}` }],
|
|
1417
|
-
isError: true,
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
const lines = [`# Category: ${input.category}\n`];
|
|
1421
|
-
for (const name of toolNames) {
|
|
1422
|
-
const tool = PINEPAPER_TOOLS.find((t) => t.name === name);
|
|
1423
|
-
if (tool) {
|
|
1424
|
-
lines.push(`## ${tool.name}\n${tool.description}\n`);
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
return {
|
|
1428
|
-
content: [{ type: 'text', text: lines.join('\n') }],
|
|
1429
|
-
};
|
|
1430
|
-
}
|
|
1431
|
-
return { content: [{ type: 'text', text: AI_AGENT_GUIDE }] };
|
|
1432
|
-
}
|
|
1433
1321
|
// -----------------------------------------------------------------------
|
|
1434
1322
|
// ASSET TOOLS
|
|
1435
1323
|
// -----------------------------------------------------------------------
|
|
@@ -1713,6 +1601,37 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1713
1601
|
}
|
|
1714
1602
|
case 'pinepaper_agent_batch_execute': {
|
|
1715
1603
|
const input = AgentBatchExecuteInputSchema.parse(args);
|
|
1604
|
+
// Ontology preflight — catch typos in itemType/relationType/
|
|
1605
|
+
// effectType/generatorName before generating JS, so the LLM gets a
|
|
1606
|
+
// structured hint instead of a silent failure inside the browser.
|
|
1607
|
+
// Opt-out via skipValidation: true when the caller knows what they're
|
|
1608
|
+
// doing (e.g. experimental vocabulary).
|
|
1609
|
+
if (!input.skipValidation) {
|
|
1610
|
+
const ops = input.operations;
|
|
1611
|
+
const violations = validateBatchVocabulary(ops);
|
|
1612
|
+
if (violations.length > 0) {
|
|
1613
|
+
return errorResult(ErrorCodes.VALIDATION_ERROR, `Batch preflight rejected ${violations.length} operation${violations.length > 1 ? 's' : ''} with unknown vocabulary value${violations.length > 1 ? 's' : ''}. Fix the offending fields and retry, or pass skipValidation: true to bypass.`, violations.map((v) => ({
|
|
1614
|
+
path: `operations[${v.opIndex}].${v.field}`,
|
|
1615
|
+
opType: v.opType,
|
|
1616
|
+
vocabulary: v.hint,
|
|
1617
|
+
})));
|
|
1618
|
+
}
|
|
1619
|
+
// Property-key typo detection — narrow scope (Levenshtein ≤2) so
|
|
1620
|
+
// legitimate extras like `gradient` pass through. Catches the
|
|
1621
|
+
// common typo class (radiues vs radius, fontSiz vs fontSize)
|
|
1622
|
+
// before browser execution silently drops them.
|
|
1623
|
+
const typos = detectBatchPropertyTypos(ops);
|
|
1624
|
+
if (typos.length > 0) {
|
|
1625
|
+
return errorResult(ErrorCodes.VALIDATION_ERROR, `Batch preflight detected ${typos.length} likely property-key typo${typos.length > 1 ? 's' : ''}. Each suggestion is a Levenshtein-≤2 match against the schema for that itemType — fix and retry, or pass skipValidation: true to bypass.`, typos.map((t) => ({
|
|
1626
|
+
path: `operations[${t.opIndex}].properties.${t.property}`,
|
|
1627
|
+
opType: t.opType,
|
|
1628
|
+
itemType: t.itemType,
|
|
1629
|
+
received: t.property,
|
|
1630
|
+
suggestion: t.suggestion,
|
|
1631
|
+
validKeys: t.validKeys,
|
|
1632
|
+
})));
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1716
1635
|
const code = codeGenerator.generateAgentBatchExecute(input);
|
|
1717
1636
|
const description = `Batch executed ${input.operations.length} operations${input.atomic !== false ? ' (atomic)' : ''}`;
|
|
1718
1637
|
// Check for out-of-bounds items before execution
|
|
@@ -1887,140 +1806,9 @@ You can now start creating new items on a clean canvas.`,
|
|
|
1887
1806
|
// -----------------------------------------------------------------------
|
|
1888
1807
|
// MAP TOOLS
|
|
1889
1808
|
// -----------------------------------------------------------------------
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
const description = `Loads ${input.mapId} map with ${input.projection || 'default'} projection`;
|
|
1894
|
-
return executeOrGenerate(code, description, options, 'pinepaper_load_map');
|
|
1895
|
-
}
|
|
1896
|
-
case 'pinepaper_highlight_regions': {
|
|
1897
|
-
const input = HighlightRegionsInputSchema.parse(args);
|
|
1898
|
-
const code = codeGenerator.generateHighlightRegions(input);
|
|
1899
|
-
const description = `Highlights ${input.regionIds.length} region(s) on the map`;
|
|
1900
|
-
return executeOrGenerate(code, description, options, 'pinepaper_highlight_regions');
|
|
1901
|
-
}
|
|
1902
|
-
case 'pinepaper_unhighlight_regions': {
|
|
1903
|
-
const input = UnhighlightRegionsInputSchema.parse(args);
|
|
1904
|
-
const code = codeGenerator.generateUnhighlightRegions(input);
|
|
1905
|
-
return executeOrGenerate(code, 'Removes region highlights', options, 'pinepaper_unhighlight_regions');
|
|
1906
|
-
}
|
|
1907
|
-
case 'pinepaper_apply_data_colors': {
|
|
1908
|
-
const input = ApplyDataColorsInputSchema.parse(args);
|
|
1909
|
-
const code = codeGenerator.generateApplyDataColors(input);
|
|
1910
|
-
const regionCount = Object.keys(input.data).length;
|
|
1911
|
-
const description = `Applies choropleth coloring to ${regionCount} region(s)`;
|
|
1912
|
-
return executeOrGenerate(code, description, options, 'pinepaper_apply_data_colors');
|
|
1913
|
-
}
|
|
1914
|
-
case 'pinepaper_add_marker': {
|
|
1915
|
-
const input = AddMarkerInputSchema.parse(args);
|
|
1916
|
-
const code = codeGenerator.generateAddMarker(input);
|
|
1917
|
-
const description = `Adds marker at [${input.lat}, ${input.lon}]${input.label ? `: ${input.label}` : ''}`;
|
|
1918
|
-
return executeOrGenerate(code, description, options, 'pinepaper_add_marker');
|
|
1919
|
-
}
|
|
1920
|
-
case 'pinepaper_add_map_labels': {
|
|
1921
|
-
const input = AddMapLabelsInputSchema.parse(args);
|
|
1922
|
-
const code = codeGenerator.generateAddMapLabels(input);
|
|
1923
|
-
return executeOrGenerate(code, 'Adds labels to map regions', options, 'pinepaper_add_map_labels');
|
|
1924
|
-
}
|
|
1925
|
-
case 'pinepaper_pan_map': {
|
|
1926
|
-
const input = PanMapInputSchema.parse(args);
|
|
1927
|
-
const code = codeGenerator.generatePanMap(input);
|
|
1928
|
-
const description = `Pans map to [${input.lat}, ${input.lon}]`;
|
|
1929
|
-
return executeOrGenerate(code, description, options, 'pinepaper_pan_map');
|
|
1930
|
-
}
|
|
1931
|
-
case 'pinepaper_zoom_map': {
|
|
1932
|
-
const input = ZoomMapInputSchema.parse(args);
|
|
1933
|
-
const code = codeGenerator.generateZoomMap(input);
|
|
1934
|
-
const description = `Sets map zoom level to ${input.level}`;
|
|
1935
|
-
return executeOrGenerate(code, description, options, 'pinepaper_zoom_map');
|
|
1936
|
-
}
|
|
1937
|
-
case 'pinepaper_export_map': {
|
|
1938
|
-
const code = codeGenerator.generateExportMap();
|
|
1939
|
-
return executeOrGenerate(code, 'Exports map configuration', options, 'pinepaper_export_map');
|
|
1940
|
-
}
|
|
1941
|
-
case 'pinepaper_import_custom_map': {
|
|
1942
|
-
const input = ImportCustomMapInputSchema.parse(args);
|
|
1943
|
-
const code = codeGenerator.generateImportCustomMap(input);
|
|
1944
|
-
const description = input.url ? `Imports custom map from URL` : 'Imports custom GeoJSON map';
|
|
1945
|
-
return executeOrGenerate(code, description, options, 'pinepaper_import_custom_map');
|
|
1946
|
-
}
|
|
1947
|
-
case 'pinepaper_get_region_at_point': {
|
|
1948
|
-
const input = GetRegionAtPointInputSchema.parse(args);
|
|
1949
|
-
const code = codeGenerator.generateGetRegionAtPoint(input);
|
|
1950
|
-
const description = `Gets region at point [${input.x}, ${input.y}]`;
|
|
1951
|
-
return executeOrGenerate(code, description, options, 'pinepaper_get_region_at_point');
|
|
1952
|
-
}
|
|
1953
|
-
// -----------------------------------------------------------------------
|
|
1954
|
-
// MAP ANIMATION/CSV TOOLS
|
|
1955
|
-
// -----------------------------------------------------------------------
|
|
1956
|
-
case 'pinepaper_animate_map_regions': {
|
|
1957
|
-
const input = AnimateMapRegionsInputSchema.parse(args);
|
|
1958
|
-
const code = codeGenerator.generateAnimateMapRegions(input);
|
|
1959
|
-
const regionCount = Object.keys(input.regions).length;
|
|
1960
|
-
const description = `Animates ${regionCount} map region(s) over ${input.duration || 5}s`;
|
|
1961
|
-
return executeOrGenerate(code, description, options, 'pinepaper_animate_map_regions');
|
|
1962
|
-
}
|
|
1963
|
-
case 'pinepaper_animate_map_wave': {
|
|
1964
|
-
const input = AnimateMapWaveInputSchema.parse(args);
|
|
1965
|
-
const code = codeGenerator.generateAnimateMapWave(input);
|
|
1966
|
-
const description = `Creates ${input.waveDirection || 'horizontal'} wave animation`;
|
|
1967
|
-
return executeOrGenerate(code, description, options, 'pinepaper_animate_map_wave');
|
|
1968
|
-
}
|
|
1969
|
-
case 'pinepaper_stop_map_animations': {
|
|
1970
|
-
const input = StopMapAnimationsInputSchema.parse(args);
|
|
1971
|
-
const code = codeGenerator.generateStopMapAnimations(input);
|
|
1972
|
-
return executeOrGenerate(code, 'Stops map region animations', options, 'pinepaper_stop_map_animations');
|
|
1973
|
-
}
|
|
1974
|
-
case 'pinepaper_get_animated_map_regions': {
|
|
1975
|
-
const code = codeGenerator.generateGetAnimatedMapRegions();
|
|
1976
|
-
return executeOrGenerate(code, 'Gets list of animated map regions', options, 'pinepaper_get_animated_map_regions');
|
|
1977
|
-
}
|
|
1978
|
-
case 'pinepaper_export_map_region_csv': {
|
|
1979
|
-
const input = ExportMapRegionCSVInputSchema.parse(args);
|
|
1980
|
-
const code = codeGenerator.generateExportMapRegionCSV(input);
|
|
1981
|
-
return executeOrGenerate(code, 'Exports map region data as CSV', options, 'pinepaper_export_map_region_csv');
|
|
1982
|
-
}
|
|
1983
|
-
case 'pinepaper_import_map_region_csv': {
|
|
1984
|
-
const input = ImportMapRegionCSVInputSchema.parse(args);
|
|
1985
|
-
const code = codeGenerator.generateImportMapRegionCSV(input);
|
|
1986
|
-
return executeOrGenerate(code, 'Imports CSV data to update map regions', options, 'pinepaper_import_map_region_csv');
|
|
1987
|
-
}
|
|
1988
|
-
case 'pinepaper_select_map_regions': {
|
|
1989
|
-
const input = SelectMapRegionsInputSchema.parse(args);
|
|
1990
|
-
const code = codeGenerator.generateSelectMapRegions(input);
|
|
1991
|
-
const description = `Selects ${input.regionIds.length} map region(s)`;
|
|
1992
|
-
return executeOrGenerate(code, description, options, 'pinepaper_select_map_regions');
|
|
1993
|
-
}
|
|
1994
|
-
case 'pinepaper_deselect_map_regions': {
|
|
1995
|
-
const input = DeselectMapRegionsInputSchema.parse(args);
|
|
1996
|
-
const code = codeGenerator.generateDeselectMapRegions(input);
|
|
1997
|
-
return executeOrGenerate(code, 'Deselects map regions', options, 'pinepaper_deselect_map_regions');
|
|
1998
|
-
}
|
|
1999
|
-
case 'pinepaper_get_highlighted_map_regions': {
|
|
2000
|
-
const code = codeGenerator.generateGetHighlightedMapRegions();
|
|
2001
|
-
return executeOrGenerate(code, 'Gets list of highlighted map regions', options, 'pinepaper_get_highlighted_map_regions');
|
|
2002
|
-
}
|
|
2003
|
-
case 'pinepaper_export_map_geojson': {
|
|
2004
|
-
const code = codeGenerator.generateExportMapGeoJson({
|
|
2005
|
-
includeStyles: args.includeStyles,
|
|
2006
|
-
includeMetadata: args.includeMetadata,
|
|
2007
|
-
selectedOnly: args.selectedOnly,
|
|
2008
|
-
download: args.download,
|
|
2009
|
-
filename: args.filename,
|
|
2010
|
-
});
|
|
2011
|
-
return executeOrGenerate(code, 'Exports map as GeoJSON', options, 'pinepaper_export_map_geojson');
|
|
2012
|
-
}
|
|
2013
|
-
case 'pinepaper_export_original_map_geojson': {
|
|
2014
|
-
const code = codeGenerator.generateExportOriginalMapGeoJson({
|
|
2015
|
-
download: args.download,
|
|
2016
|
-
filename: args.filename,
|
|
2017
|
-
});
|
|
2018
|
-
return executeOrGenerate(code, 'Exports original map GeoJSON', options, 'pinepaper_export_original_map_geojson');
|
|
2019
|
-
}
|
|
2020
|
-
case 'pinepaper_get_map_source_info': {
|
|
2021
|
-
const code = codeGenerator.generateGetMapSourceInfo();
|
|
2022
|
-
return executeOrGenerate(code, 'Gets map source information', options, 'pinepaper_get_map_source_info');
|
|
2023
|
-
}
|
|
1809
|
+
// -----------------------------------------------------------------------
|
|
1810
|
+
// MAP TOOLS — extracted to src/tools/handlers/maps.ts
|
|
1811
|
+
// -----------------------------------------------------------------------
|
|
2024
1812
|
case 'pinepaper_register_item': {
|
|
2025
1813
|
const code = codeGenerator.generateRegisterItem({
|
|
2026
1814
|
itemJson: args.itemJson,
|
|
@@ -2046,169 +1834,8 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2046
1834
|
return executeOrGenerate(code, 'Imports image', options, 'pinepaper_import_image');
|
|
2047
1835
|
}
|
|
2048
1836
|
// -----------------------------------------------------------------------
|
|
2049
|
-
// ONTOLOGY TOOLS
|
|
2050
|
-
// -----------------------------------------------------------------------
|
|
2051
|
-
case 'pinepaper_analyze_design': {
|
|
2052
|
-
const input = AnalyzeDesignInputSchema.parse(args);
|
|
2053
|
-
const { DesignGraph } = await import('../ontology/index.js');
|
|
2054
|
-
const dg = new DesignGraph();
|
|
2055
|
-
const graph = dg.extractFromDefinition(input.definition);
|
|
2056
|
-
const jsonLd = dg.toJsonLd(graph);
|
|
2057
|
-
return {
|
|
2058
|
-
content: [{
|
|
2059
|
-
type: 'text',
|
|
2060
|
-
text: JSON.stringify({
|
|
2061
|
-
templateId: graph.templateId,
|
|
2062
|
-
templateName: graph.templateName,
|
|
2063
|
-
category: graph.category,
|
|
2064
|
-
dimensions: graph.dimensions,
|
|
2065
|
-
duration: graph.duration,
|
|
2066
|
-
nodeCount: graph.nodes.length,
|
|
2067
|
-
edgeCount: graph.edges.length,
|
|
2068
|
-
nodeTypes: Object.fromEntries(Object.entries(graph.fingerprint?.nodeTypeCounts || {}).sort((a, b) => b[1] - a[1])),
|
|
2069
|
-
edgeTypes: Object.fromEntries(Object.entries(graph.fingerprint?.edgeTypeCounts || {}).sort((a, b) => b[1] - a[1])),
|
|
2070
|
-
patterns: graph.patterns,
|
|
2071
|
-
mathFunctions: graph.mathFunctions,
|
|
2072
|
-
generator: graph.generator,
|
|
2073
|
-
semantics: graph.semantics,
|
|
2074
|
-
fingerprint: graph.fingerprint,
|
|
2075
|
-
jsonLd,
|
|
2076
|
-
}, null, 2),
|
|
2077
|
-
}],
|
|
2078
|
-
};
|
|
2079
|
-
}
|
|
2080
|
-
case 'pinepaper_validate_design': {
|
|
2081
|
-
const input = ValidateDesignInputSchema.parse(args);
|
|
2082
|
-
const { DesignGraph, KnowledgeGraphValidator } = await import('../ontology/index.js');
|
|
2083
|
-
const dg = new DesignGraph();
|
|
2084
|
-
const validator = new KnowledgeGraphValidator();
|
|
2085
|
-
const definition = input.definition;
|
|
2086
|
-
const validation = validator.validateTemplate(definition);
|
|
2087
|
-
let quality = null;
|
|
2088
|
-
if (validation.valid) {
|
|
2089
|
-
const graph = dg.extractFromDefinition(definition);
|
|
2090
|
-
quality = validator.scoreQuality(definition, graph);
|
|
2091
|
-
}
|
|
2092
|
-
return {
|
|
2093
|
-
content: [{
|
|
2094
|
-
type: 'text',
|
|
2095
|
-
text: JSON.stringify({
|
|
2096
|
-
validation,
|
|
2097
|
-
quality,
|
|
2098
|
-
}, null, 2),
|
|
2099
|
-
}],
|
|
2100
|
-
};
|
|
2101
|
-
}
|
|
1837
|
+
// ONTOLOGY TOOLS — extracted to src/tools/handlers/ontology.ts
|
|
2102
1838
|
// -----------------------------------------------------------------------
|
|
2103
|
-
// ONTOLOGY QUERY (read-only graph navigation)
|
|
2104
|
-
// -----------------------------------------------------------------------
|
|
2105
|
-
case 'pinepaper_query_ontology': {
|
|
2106
|
-
const input = QueryOntologyInputSchema.parse(args);
|
|
2107
|
-
const { PP_VOCABULARY, ITEM_TYPE_MAP, RELATION_TYPE_MAP } = await import('../ontology/vocabulary.js');
|
|
2108
|
-
const { DesignGraph } = await import('../ontology/design-graph.js');
|
|
2109
|
-
const dg = new DesignGraph();
|
|
2110
|
-
let result;
|
|
2111
|
-
switch (input.query) {
|
|
2112
|
-
case 'list_types': {
|
|
2113
|
-
const entries = Object.entries(PP_VOCABULARY.types);
|
|
2114
|
-
const filtered = entries.filter(([key, def]) => {
|
|
2115
|
-
if (input.category && def.category !== input.category)
|
|
2116
|
-
return false;
|
|
2117
|
-
if (!input.includeAbstract && def.abstract)
|
|
2118
|
-
return false;
|
|
2119
|
-
return true;
|
|
2120
|
-
});
|
|
2121
|
-
result = Object.fromEntries(filtered);
|
|
2122
|
-
break;
|
|
2123
|
-
}
|
|
2124
|
-
case 'list_edges': {
|
|
2125
|
-
const entries = Object.entries(PP_VOCABULARY.edges);
|
|
2126
|
-
const filtered = input.category
|
|
2127
|
-
? entries.filter(([, def]) => def.category === input.category)
|
|
2128
|
-
: entries;
|
|
2129
|
-
result = Object.fromEntries(filtered);
|
|
2130
|
-
break;
|
|
2131
|
-
}
|
|
2132
|
-
case 'list_generators': {
|
|
2133
|
-
const entries = Object.entries(PP_VOCABULARY.generators);
|
|
2134
|
-
const filtered = input.category
|
|
2135
|
-
? entries.filter(([, def]) => def.category === input.category)
|
|
2136
|
-
: entries;
|
|
2137
|
-
result = Object.fromEntries(filtered);
|
|
2138
|
-
break;
|
|
2139
|
-
}
|
|
2140
|
-
case 'list_effects': {
|
|
2141
|
-
result = ['sparkle', 'blast', 'smoke', 'fire', 'rain', 'snow', 'confetti', 'ripple', 'glow', 'electric'];
|
|
2142
|
-
break;
|
|
2143
|
-
}
|
|
2144
|
-
case 'list_patterns': {
|
|
2145
|
-
result = PP_VOCABULARY.patterns;
|
|
2146
|
-
break;
|
|
2147
|
-
}
|
|
2148
|
-
case 'list_math_functions': {
|
|
2149
|
-
result = PP_VOCABULARY.mathFunctions;
|
|
2150
|
-
break;
|
|
2151
|
-
}
|
|
2152
|
-
case 'type_hierarchy': {
|
|
2153
|
-
if (!input.ppType)
|
|
2154
|
-
return errorResult('INVALID_INPUT', 'ppType is required for type_hierarchy');
|
|
2155
|
-
result = dg.getTypeHierarchy(input.ppType);
|
|
2156
|
-
break;
|
|
2157
|
-
}
|
|
2158
|
-
case 'type_children': {
|
|
2159
|
-
if (!input.ppType)
|
|
2160
|
-
return errorResult('INVALID_INPUT', 'ppType is required for type_children');
|
|
2161
|
-
result = dg.getTypeChildren(input.ppType);
|
|
2162
|
-
break;
|
|
2163
|
-
}
|
|
2164
|
-
case 'type_properties': {
|
|
2165
|
-
if (!input.ppType)
|
|
2166
|
-
return errorResult('INVALID_INPUT', 'ppType is required for type_properties');
|
|
2167
|
-
result = dg.getPropertiesFor(input.ppType);
|
|
2168
|
-
break;
|
|
2169
|
-
}
|
|
2170
|
-
case 'animatable_properties': {
|
|
2171
|
-
if (!input.ppType)
|
|
2172
|
-
return errorResult('INVALID_INPUT', 'ppType is required for animatable_properties');
|
|
2173
|
-
result = dg.getAnimatableProperties(input.ppType);
|
|
2174
|
-
break;
|
|
2175
|
-
}
|
|
2176
|
-
case 'is_subtype': {
|
|
2177
|
-
if (!input.typeA || !input.typeB)
|
|
2178
|
-
return errorResult('INVALID_INPUT', 'typeA and typeB are required for is_subtype');
|
|
2179
|
-
result = { isSubtype: dg.isSubtypeOf(input.typeA, input.typeB) };
|
|
2180
|
-
break;
|
|
2181
|
-
}
|
|
2182
|
-
case 'edge_info': {
|
|
2183
|
-
const edgeName = input.relationName || input.ppType;
|
|
2184
|
-
if (!edgeName)
|
|
2185
|
-
return errorResult('INVALID_INPUT', 'relationName or ppType is required for edge_info');
|
|
2186
|
-
const ppEdge = PP_VOCABULARY.edges[edgeName] || PP_VOCABULARY.edges[RELATION_TYPE_MAP[edgeName] || ''];
|
|
2187
|
-
result = ppEdge || { error: `Unknown edge: ${edgeName}` };
|
|
2188
|
-
break;
|
|
2189
|
-
}
|
|
2190
|
-
case 'node_type': {
|
|
2191
|
-
if (!input.itemType)
|
|
2192
|
-
return errorResult('INVALID_INPUT', 'itemType is required for node_type');
|
|
2193
|
-
result = { ppType: dg.getNodeType(input.itemType) };
|
|
2194
|
-
break;
|
|
2195
|
-
}
|
|
2196
|
-
case 'edge_type': {
|
|
2197
|
-
if (!input.relationName)
|
|
2198
|
-
return errorResult('INVALID_INPUT', 'relationName is required for edge_type');
|
|
2199
|
-
result = { ppEdge: dg.getEdgeType(input.relationName) };
|
|
2200
|
-
break;
|
|
2201
|
-
}
|
|
2202
|
-
default:
|
|
2203
|
-
return errorResult('INVALID_INPUT', `Unknown query: ${input.query}`);
|
|
2204
|
-
}
|
|
2205
|
-
return {
|
|
2206
|
-
content: [{
|
|
2207
|
-
type: 'text',
|
|
2208
|
-
text: JSON.stringify(result, null, 2),
|
|
2209
|
-
}],
|
|
2210
|
-
};
|
|
2211
|
-
}
|
|
2212
1839
|
// -----------------------------------------------------------------------
|
|
2213
1840
|
// UNKNOWN TOOL
|
|
2214
1841
|
// -----------------------------------------------------------------------
|
|
@@ -2216,7 +1843,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2216
1843
|
const message = i18n
|
|
2217
1844
|
? i18n.getError('unknownTool', { toolName })
|
|
2218
1845
|
: `Unknown tool: ${toolName}`;
|
|
2219
|
-
return errorResult(
|
|
1846
|
+
return errorResult(ErrorCodes.UNKNOWN_TOOL, message, {
|
|
2220
1847
|
availableTools: [
|
|
2221
1848
|
'pinepaper_create_item',
|
|
2222
1849
|
'pinepaper_modify_item',
|
|
@@ -2245,12 +1872,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2245
1872
|
'pinepaper_get_mask_types',
|
|
2246
1873
|
'pinepaper_get_mask_animations',
|
|
2247
1874
|
'pinepaper_camera_animate',
|
|
2248
|
-
'
|
|
2249
|
-
'pinepaper_camera_pan',
|
|
2250
|
-
'pinepaper_camera_move_to',
|
|
2251
|
-
'pinepaper_camera_reset',
|
|
2252
|
-
'pinepaper_camera_stop',
|
|
2253
|
-
'pinepaper_camera_state',
|
|
1875
|
+
'pinepaper_camera',
|
|
2254
1876
|
'pinepaper_get_items',
|
|
2255
1877
|
'pinepaper_get_relation_stats',
|
|
2256
1878
|
'pinepaper_set_background_color',
|
|
@@ -2259,6 +1881,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2259
1881
|
'pinepaper_clear_canvas',
|
|
2260
1882
|
'pinepaper_refresh_page',
|
|
2261
1883
|
'pinepaper_import_svg',
|
|
1884
|
+
'pinepaper_import_mermaid',
|
|
2262
1885
|
'pinepaper_add_filter',
|
|
2263
1886
|
'pinepaper_export_svg',
|
|
2264
1887
|
'pinepaper_export_training_data',
|
|
@@ -2307,48 +1930,13 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2307
1930
|
'pinepaper_get_letter_collage_options',
|
|
2308
1931
|
// Canvas presets tools
|
|
2309
1932
|
'pinepaper_get_canvas_presets',
|
|
2310
|
-
// Map tools
|
|
2311
|
-
'
|
|
2312
|
-
'
|
|
2313
|
-
'
|
|
2314
|
-
'
|
|
2315
|
-
'pinepaper_add_marker',
|
|
2316
|
-
'pinepaper_add_map_labels',
|
|
2317
|
-
'pinepaper_pan_map',
|
|
2318
|
-
'pinepaper_zoom_map',
|
|
2319
|
-
'pinepaper_export_map',
|
|
2320
|
-
'pinepaper_import_custom_map',
|
|
2321
|
-
'pinepaper_get_region_at_point',
|
|
2322
|
-
// Map animation/CSV tools
|
|
2323
|
-
'pinepaper_animate_map_regions',
|
|
2324
|
-
'pinepaper_animate_map_wave',
|
|
2325
|
-
'pinepaper_stop_map_animations',
|
|
2326
|
-
'pinepaper_get_animated_map_regions',
|
|
2327
|
-
'pinepaper_export_map_region_csv',
|
|
2328
|
-
'pinepaper_import_map_region_csv',
|
|
2329
|
-
'pinepaper_select_map_regions',
|
|
2330
|
-
'pinepaper_deselect_map_regions',
|
|
2331
|
-
'pinepaper_get_highlighted_map_regions',
|
|
2332
|
-
'pinepaper_export_map_geojson',
|
|
2333
|
-
'pinepaper_export_original_map_geojson',
|
|
2334
|
-
'pinepaper_get_map_source_info',
|
|
1933
|
+
// Map tools (4 action-dispatched)
|
|
1934
|
+
'pinepaper_map',
|
|
1935
|
+
'pinepaper_map_regions',
|
|
1936
|
+
'pinepaper_map_animation',
|
|
1937
|
+
'pinepaper_map_data',
|
|
2335
1938
|
// Font tools
|
|
2336
|
-
'
|
|
2337
|
-
'pinepaper_font_set_name',
|
|
2338
|
-
'pinepaper_font_get_required_chars',
|
|
2339
|
-
'pinepaper_font_get_status',
|
|
2340
|
-
'pinepaper_font_create_glyph',
|
|
2341
|
-
'pinepaper_font_create_space',
|
|
2342
|
-
'pinepaper_font_remove_glyph',
|
|
2343
|
-
'pinepaper_font_set_metrics',
|
|
2344
|
-
'pinepaper_font_export',
|
|
2345
|
-
'pinepaper_font_load_into_document',
|
|
2346
|
-
'pinepaper_font_export_data',
|
|
2347
|
-
'pinepaper_font_import_data',
|
|
2348
|
-
'pinepaper_font_clear',
|
|
2349
|
-
'pinepaper_font_remove_overlap',
|
|
2350
|
-
'pinepaper_font_correct_direction',
|
|
2351
|
-
'pinepaper_font_cleanup_path',
|
|
1939
|
+
'pinepaper_font',
|
|
2352
1940
|
// Template tools
|
|
2353
1941
|
'pinepaper_apply_template',
|
|
2354
1942
|
// Image import tools
|
|
@@ -2359,6 +1947,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2359
1947
|
'pinepaper_tool_guide',
|
|
2360
1948
|
'pinepaper_set_toolkit',
|
|
2361
1949
|
// Ontology tools
|
|
1950
|
+
'pinepaper_get_canvas_ontology',
|
|
2362
1951
|
'pinepaper_analyze_design',
|
|
2363
1952
|
'pinepaper_validate_design',
|
|
2364
1953
|
'pinepaper_query_ontology',
|
|
@@ -2376,6 +1965,19 @@ You can now start creating new items on a clean canvas.`,
|
|
|
2376
1965
|
'pinepaper_background',
|
|
2377
1966
|
// Canvas query tools
|
|
2378
1967
|
'pinepaper_query',
|
|
1968
|
+
// Deformation, sprite sheets, storage, interaction
|
|
1969
|
+
'pinepaper_deform',
|
|
1970
|
+
'pinepaper_sprite_sheet',
|
|
1971
|
+
'pinepaper_storage',
|
|
1972
|
+
'pinepaper_interaction',
|
|
1973
|
+
// Widget export
|
|
1974
|
+
'pinepaper_export_widget',
|
|
1975
|
+
'pinepaper_export_widget_html',
|
|
1976
|
+
// Data visualization, magic, physics, measurement
|
|
1977
|
+
'pinepaper_create_chart',
|
|
1978
|
+
'pinepaper_magic',
|
|
1979
|
+
'pinepaper_physics',
|
|
1980
|
+
'pinepaper_measurement',
|
|
2379
1981
|
],
|
|
2380
1982
|
});
|
|
2381
1983
|
}
|