@pinepaper.studio/mcp-server 1.2.1 → 1.3.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/README.md +109 -2
- package/dist/assets/asset-manager.d.ts +75 -0
- package/dist/assets/asset-manager.d.ts.map +1 -0
- package/dist/assets/asset-manager.js +156 -0
- package/dist/assets/asset-manager.js.map +1 -0
- package/dist/assets/index.d.ts +12 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +12 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/assets/repositories/fontawesome.d.ts +43 -0
- package/dist/assets/repositories/fontawesome.d.ts.map +1 -0
- package/dist/assets/repositories/fontawesome.js +163 -0
- package/dist/assets/repositories/fontawesome.js.map +1 -0
- package/dist/assets/repositories/iconify.d.ts +44 -0
- package/dist/assets/repositories/iconify.d.ts.map +1 -0
- package/dist/assets/repositories/iconify.js +208 -0
- package/dist/assets/repositories/iconify.js.map +1 -0
- package/dist/assets/repositories/openclipart.d.ts +41 -0
- package/dist/assets/repositories/openclipart.d.ts.map +1 -0
- package/dist/assets/repositories/openclipart.js +138 -0
- package/dist/assets/repositories/openclipart.js.map +1 -0
- package/dist/assets/repositories/svgrepo.d.ts +61 -0
- package/dist/assets/repositories/svgrepo.d.ts.map +1 -0
- package/dist/assets/repositories/svgrepo.js +276 -0
- package/dist/assets/repositories/svgrepo.js.map +1 -0
- package/dist/assets/types.d.ts +85 -0
- package/dist/assets/types.d.ts.map +1 -0
- package/dist/assets/types.js +7 -0
- package/dist/assets/types.js.map +1 -0
- package/dist/execution/canvas-state.d.ts +65 -0
- package/dist/execution/canvas-state.d.ts.map +1 -0
- package/dist/execution/canvas-state.js +165 -0
- package/dist/execution/canvas-state.js.map +1 -0
- package/dist/execution/index.d.ts +8 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +8 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/metrics/index.d.ts +8 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +8 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/performance-tracker.d.ts +96 -0
- package/dist/metrics/performance-tracker.d.ts.map +1 -0
- package/dist/metrics/performance-tracker.js +270 -0
- package/dist/metrics/performance-tracker.js.map +1 -0
- package/dist/metrics/types.d.ts +86 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +7 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +510 -0
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +313 -34
- package/dist/tools/handlers.js.map +1 -1
- package/dist/types/code-generator.d.ts +13 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +91 -1
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +210 -47
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +59 -0
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +42 -2
- package/package.json +1 -1
package/dist/tools/handlers.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
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, ExportTrainingDataInputSchema, ImportSVGInputSchema, AddFilterInputSchema, CreateGlossySphereInputSchema, CreateDiagonalStripesInputSchema, ErrorCodes, } from '../types/schemas.js';
|
|
9
|
+
import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, AddRelationInputSchema, RemoveRelationInputSchema, QueryRelationsInputSchema, AnimateItemInputSchema, KeyframeAnimateInputSchema, ExecuteGeneratorInputSchema, ApplyEffectInputSchema, GetItemsInputSchema, PlayTimelineInputSchema, SetBackgroundColorInputSchema, SetCanvasSizeInputSchema, ExportTrainingDataInputSchema, ImportSVGInputSchema, AddFilterInputSchema, CreateGlossySphereInputSchema, CreateDiagonalStripesInputSchema, BatchCreateInputSchema, BatchModifyInputSchema, CreateGridInputSchema, GetPerformanceMetricsInputSchema, SearchAssetsInputSchema, ImportAssetInputSchema, ErrorCodes, } from '../types/schemas.js';
|
|
10
10
|
import { ZodError } from 'zod';
|
|
11
11
|
import { getBrowserController, } from '../browser/puppeteer-controller.js';
|
|
12
|
+
import { getPerformanceTracker } from '../metrics/index.js';
|
|
13
|
+
import { formatErrorContext, captureCanvasState } from '../execution/index.js';
|
|
12
14
|
/**
|
|
13
15
|
* Get screenshot mode from environment variable.
|
|
14
16
|
* Defaults to 'on_request' for optimal performance.
|
|
@@ -72,15 +74,24 @@ function screenshotResult(screenshot) {
|
|
|
72
74
|
],
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
|
-
function errorResult(code, message, details) {
|
|
77
|
+
function errorResult(code, message, details, context) {
|
|
78
|
+
// Build error object
|
|
79
|
+
const errorObj = {
|
|
80
|
+
success: false,
|
|
81
|
+
error: { code, message, details },
|
|
82
|
+
};
|
|
83
|
+
// Add formatted context if available
|
|
84
|
+
if (context) {
|
|
85
|
+
const contextText = formatErrorContext(context);
|
|
86
|
+
if (contextText) {
|
|
87
|
+
errorObj.context = contextText;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
76
90
|
return {
|
|
77
91
|
content: [
|
|
78
92
|
{
|
|
79
93
|
type: 'text',
|
|
80
|
-
text: JSON.stringify(
|
|
81
|
-
success: false,
|
|
82
|
-
error: { code, message, details },
|
|
83
|
-
}, null, 2),
|
|
94
|
+
text: JSON.stringify(errorObj, null, 2),
|
|
84
95
|
},
|
|
85
96
|
],
|
|
86
97
|
isError: true,
|
|
@@ -105,22 +116,83 @@ function handleValidationError(error, i18n) {
|
|
|
105
116
|
*
|
|
106
117
|
* Default is 'on_request' for optimal performance per best practices.
|
|
107
118
|
*/
|
|
108
|
-
async function executeOrGenerate(code, description, options) {
|
|
119
|
+
async function executeOrGenerate(code, description, options, toolName) {
|
|
109
120
|
const { executeInBrowser, browserController, screenshotMode } = options;
|
|
110
121
|
const effectiveScreenshotMode = screenshotMode ?? getScreenshotMode();
|
|
122
|
+
const tracker = getPerformanceTracker();
|
|
123
|
+
// Start total timer
|
|
124
|
+
const timerId = `${toolName}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
125
|
+
tracker.startTimer(`${timerId}_total`);
|
|
111
126
|
if (!executeInBrowser) {
|
|
127
|
+
const totalDuration = tracker.endTimer(`${timerId}_total`);
|
|
128
|
+
tracker.recordMetric({
|
|
129
|
+
toolName,
|
|
130
|
+
phase: 'total',
|
|
131
|
+
duration: totalDuration,
|
|
132
|
+
timestamp: Date.now(),
|
|
133
|
+
success: true,
|
|
134
|
+
});
|
|
112
135
|
return successResult(code, description);
|
|
113
136
|
}
|
|
114
137
|
const controller = browserController || getBrowserController();
|
|
115
138
|
if (!controller.connected) {
|
|
139
|
+
const totalDuration = tracker.endTimer(`${timerId}_total`);
|
|
140
|
+
tracker.recordMetric({
|
|
141
|
+
toolName,
|
|
142
|
+
phase: 'total',
|
|
143
|
+
duration: totalDuration,
|
|
144
|
+
timestamp: Date.now(),
|
|
145
|
+
success: true,
|
|
146
|
+
metadata: { browserConnected: false },
|
|
147
|
+
});
|
|
116
148
|
return successResult(code, `${description}\n\n⚠️ Browser not connected. Call pinepaper_browser_connect first to execute code live.`);
|
|
117
149
|
}
|
|
150
|
+
// Track browser execution time
|
|
151
|
+
tracker.startTimer(`${timerId}_browser_execution`);
|
|
118
152
|
// Only take screenshot if mode is 'always'
|
|
119
153
|
// 'on_request' mode means screenshots only via pinepaper_browser_screenshot
|
|
120
154
|
const shouldTakeScreenshot = effectiveScreenshotMode === 'always';
|
|
155
|
+
// Track screenshot time separately if taking screenshot
|
|
156
|
+
if (shouldTakeScreenshot) {
|
|
157
|
+
tracker.startTimer(`${timerId}_screenshot`);
|
|
158
|
+
}
|
|
121
159
|
const result = await controller.executeCode(code, shouldTakeScreenshot);
|
|
160
|
+
const browserDuration = tracker.endTimer(`${timerId}_browser_execution`);
|
|
161
|
+
tracker.recordMetric({
|
|
162
|
+
toolName,
|
|
163
|
+
phase: 'browser_execution',
|
|
164
|
+
duration: browserDuration,
|
|
165
|
+
timestamp: Date.now(),
|
|
166
|
+
success: result.success,
|
|
167
|
+
error: result.error,
|
|
168
|
+
});
|
|
169
|
+
if (shouldTakeScreenshot) {
|
|
170
|
+
const screenshotDuration = tracker.endTimer(`${timerId}_screenshot`);
|
|
171
|
+
tracker.recordMetric({
|
|
172
|
+
toolName,
|
|
173
|
+
phase: 'screenshot',
|
|
174
|
+
duration: screenshotDuration,
|
|
175
|
+
timestamp: Date.now(),
|
|
176
|
+
success: !!result.screenshot,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Record total duration
|
|
180
|
+
const totalDuration = tracker.endTimer(`${timerId}_total`);
|
|
181
|
+
tracker.recordMetric({
|
|
182
|
+
toolName,
|
|
183
|
+
phase: 'total',
|
|
184
|
+
duration: totalDuration,
|
|
185
|
+
timestamp: Date.now(),
|
|
186
|
+
success: result.success,
|
|
187
|
+
error: result.error,
|
|
188
|
+
});
|
|
122
189
|
if (!result.success) {
|
|
123
|
-
|
|
190
|
+
// Capture canvas state for error context
|
|
191
|
+
const canvasState = await captureCanvasState(controller);
|
|
192
|
+
return errorResult(ErrorCodes.EXECUTION_ERROR, result.error || 'Failed to execute code in browser', { code }, {
|
|
193
|
+
toolName,
|
|
194
|
+
canvasState: canvasState || undefined,
|
|
195
|
+
});
|
|
124
196
|
}
|
|
125
197
|
return executedResult(code, result.result, result.screenshot, description);
|
|
126
198
|
}
|
|
@@ -135,24 +207,82 @@ function getLocalizedSuccessMessage(i18n, key, params) {
|
|
|
135
207
|
return i18n.getSuccess(key, params);
|
|
136
208
|
}
|
|
137
209
|
// =============================================================================
|
|
210
|
+
// PERFORMANCE TRACKING HELPER
|
|
211
|
+
// =============================================================================
|
|
212
|
+
/**
|
|
213
|
+
* Execute a tool handler with automatic performance tracking for validation and code generation
|
|
214
|
+
*/
|
|
215
|
+
async function executeToolWithTracking(toolName, args, options, validator, codeGenerator, description) {
|
|
216
|
+
const tracker = getPerformanceTracker();
|
|
217
|
+
const baseTimerId = `${toolName}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
218
|
+
// Track validation
|
|
219
|
+
tracker.startTimer(`${baseTimerId}_validation`);
|
|
220
|
+
const input = validator();
|
|
221
|
+
const validationDuration = tracker.endTimer(`${baseTimerId}_validation`);
|
|
222
|
+
tracker.recordMetric({
|
|
223
|
+
toolName,
|
|
224
|
+
phase: 'validation',
|
|
225
|
+
duration: validationDuration,
|
|
226
|
+
timestamp: Date.now(),
|
|
227
|
+
success: true,
|
|
228
|
+
});
|
|
229
|
+
// Track code generation
|
|
230
|
+
tracker.startTimer(`${baseTimerId}_code_generation`);
|
|
231
|
+
const code = codeGenerator(input);
|
|
232
|
+
const codeGenDuration = tracker.endTimer(`${baseTimerId}_code_generation`);
|
|
233
|
+
tracker.recordMetric({
|
|
234
|
+
toolName,
|
|
235
|
+
phase: 'code_generation',
|
|
236
|
+
duration: codeGenDuration,
|
|
237
|
+
timestamp: Date.now(),
|
|
238
|
+
success: true,
|
|
239
|
+
});
|
|
240
|
+
// Get final description
|
|
241
|
+
const finalDescription = typeof description === 'function' ? description(input) : description;
|
|
242
|
+
// Execute (will handle browser execution and screenshot timing)
|
|
243
|
+
return executeOrGenerate(code, finalDescription, options, toolName);
|
|
244
|
+
}
|
|
245
|
+
// =============================================================================
|
|
138
246
|
// TOOL HANDLERS
|
|
139
247
|
// =============================================================================
|
|
140
248
|
export async function handleToolCall(toolName, args, options = {}) {
|
|
141
249
|
const { i18n } = options;
|
|
250
|
+
const tracker = getPerformanceTracker();
|
|
251
|
+
const baseTimerId = `${toolName}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
142
252
|
try {
|
|
143
253
|
switch (toolName) {
|
|
144
254
|
// -----------------------------------------------------------------------
|
|
145
255
|
// ITEM TOOLS
|
|
146
256
|
// -----------------------------------------------------------------------
|
|
147
257
|
case 'pinepaper_create_item': {
|
|
258
|
+
// Track validation phase
|
|
259
|
+
tracker.startTimer(`${baseTimerId}_validation`);
|
|
148
260
|
const input = CreateItemInputSchema.parse(args);
|
|
261
|
+
const validationDuration = tracker.endTimer(`${baseTimerId}_validation`);
|
|
262
|
+
tracker.recordMetric({
|
|
263
|
+
toolName,
|
|
264
|
+
phase: 'validation',
|
|
265
|
+
duration: validationDuration,
|
|
266
|
+
timestamp: Date.now(),
|
|
267
|
+
success: true,
|
|
268
|
+
});
|
|
269
|
+
// Track code generation phase
|
|
270
|
+
tracker.startTimer(`${baseTimerId}_code_generation`);
|
|
149
271
|
const code = codeGenerator.generateCreateItem(input);
|
|
272
|
+
const codeGenDuration = tracker.endTimer(`${baseTimerId}_code_generation`);
|
|
273
|
+
tracker.recordMetric({
|
|
274
|
+
toolName,
|
|
275
|
+
phase: 'code_generation',
|
|
276
|
+
duration: codeGenDuration,
|
|
277
|
+
timestamp: Date.now(),
|
|
278
|
+
success: true,
|
|
279
|
+
});
|
|
150
280
|
const description = getLocalizedSuccessMessage(i18n, 'itemCreated', {
|
|
151
281
|
itemType: input.itemType,
|
|
152
282
|
x: input.position.x,
|
|
153
283
|
y: input.position.y,
|
|
154
284
|
});
|
|
155
|
-
return executeOrGenerate(code, description, options);
|
|
285
|
+
return executeOrGenerate(code, description, options, toolName);
|
|
156
286
|
}
|
|
157
287
|
case 'pinepaper_modify_item': {
|
|
158
288
|
const input = ModifyItemInputSchema.parse(args);
|
|
@@ -160,7 +290,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
160
290
|
const description = getLocalizedSuccessMessage(i18n, 'itemModified', {
|
|
161
291
|
itemId: input.itemId,
|
|
162
292
|
});
|
|
163
|
-
return executeOrGenerate(code, description, options);
|
|
293
|
+
return executeOrGenerate(code, description, options, 'pinepaper_modify_item');
|
|
164
294
|
}
|
|
165
295
|
case 'pinepaper_delete_item': {
|
|
166
296
|
const input = DeleteItemInputSchema.parse(args);
|
|
@@ -168,7 +298,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
168
298
|
const description = getLocalizedSuccessMessage(i18n, 'itemDeleted', {
|
|
169
299
|
itemId: input.itemId,
|
|
170
300
|
});
|
|
171
|
-
return executeOrGenerate(code, description, options);
|
|
301
|
+
return executeOrGenerate(code, description, options, 'pinepaper_delete_item');
|
|
172
302
|
}
|
|
173
303
|
// -----------------------------------------------------------------------
|
|
174
304
|
// HIGH-LEVEL DESIGN TOOLS
|
|
@@ -177,13 +307,34 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
177
307
|
const input = CreateGlossySphereInputSchema.parse(args);
|
|
178
308
|
const code = codeGenerator.generateCreateGlossySphere(input);
|
|
179
309
|
const description = `Creates a 3D glossy sphere with ${input.baseColor} color at (${input.position.x}, ${input.position.y})`;
|
|
180
|
-
return executeOrGenerate(code, description, options);
|
|
310
|
+
return executeOrGenerate(code, description, options, 'pinepaper_create_glossy_sphere');
|
|
181
311
|
}
|
|
182
312
|
case 'pinepaper_create_diagonal_stripes': {
|
|
183
313
|
const input = CreateDiagonalStripesInputSchema.parse(args);
|
|
184
314
|
const code = codeGenerator.generateCreateDiagonalStripes(input);
|
|
185
315
|
const description = `Creates diagonal stripes pattern at (${input.position.x}, ${input.position.y}) with ${input.colors.length} colors`;
|
|
186
|
-
return executeOrGenerate(code, description, options);
|
|
316
|
+
return executeOrGenerate(code, description, options, 'pinepaper_create_diagonal_stripes');
|
|
317
|
+
}
|
|
318
|
+
// -----------------------------------------------------------------------
|
|
319
|
+
// BATCH OPERATION TOOLS
|
|
320
|
+
// -----------------------------------------------------------------------
|
|
321
|
+
case 'pinepaper_batch_create': {
|
|
322
|
+
const input = BatchCreateInputSchema.parse(args);
|
|
323
|
+
const code = codeGenerator.generateBatchCreate(input);
|
|
324
|
+
const description = `Batch creates ${input.items.length} items with single history save`;
|
|
325
|
+
return executeOrGenerate(code, description, options, 'pinepaper_batch_create');
|
|
326
|
+
}
|
|
327
|
+
case 'pinepaper_batch_modify': {
|
|
328
|
+
const input = BatchModifyInputSchema.parse(args);
|
|
329
|
+
const code = codeGenerator.generateBatchModify(input);
|
|
330
|
+
const description = `Batch modifies ${input.modifications.length} items with single history save`;
|
|
331
|
+
return executeOrGenerate(code, description, options, 'pinepaper_batch_modify');
|
|
332
|
+
}
|
|
333
|
+
case 'pinepaper_create_grid': {
|
|
334
|
+
const input = CreateGridInputSchema.parse(args);
|
|
335
|
+
const code = codeGenerator.generateCreateGrid(input);
|
|
336
|
+
const description = `Creates a ${input.cols}x${input.rows} grid${input.animated ? ' with wave animation' : ''}`;
|
|
337
|
+
return executeOrGenerate(code, description, options, 'pinepaper_create_grid');
|
|
187
338
|
}
|
|
188
339
|
// -----------------------------------------------------------------------
|
|
189
340
|
// RELATION TOOLS
|
|
@@ -196,7 +347,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
196
347
|
sourceId: input.sourceId,
|
|
197
348
|
targetId: input.targetId,
|
|
198
349
|
});
|
|
199
|
-
return executeOrGenerate(code, description, options);
|
|
350
|
+
return executeOrGenerate(code, description, options, 'pinepaper_add_relation');
|
|
200
351
|
}
|
|
201
352
|
case 'pinepaper_remove_relation': {
|
|
202
353
|
const input = RemoveRelationInputSchema.parse(args);
|
|
@@ -205,12 +356,12 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
205
356
|
sourceId: input.sourceId,
|
|
206
357
|
targetId: input.targetId,
|
|
207
358
|
});
|
|
208
|
-
return executeOrGenerate(code, description, options);
|
|
359
|
+
return executeOrGenerate(code, description, options, 'pinepaper_remove_relation');
|
|
209
360
|
}
|
|
210
361
|
case 'pinepaper_query_relations': {
|
|
211
362
|
const input = QueryRelationsInputSchema.parse(args);
|
|
212
363
|
const code = codeGenerator.generateQueryRelations(input.itemId, input.relationType, input.direction);
|
|
213
|
-
return executeOrGenerate(code, `Queries ${input.direction || 'all'} relations for ${input.itemId}`, options);
|
|
364
|
+
return executeOrGenerate(code, `Queries ${input.direction || 'all'} relations for ${input.itemId}`, options, 'pinepaper_query_relations');
|
|
214
365
|
}
|
|
215
366
|
// -----------------------------------------------------------------------
|
|
216
367
|
// ANIMATION TOOLS
|
|
@@ -222,17 +373,17 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
222
373
|
animationType: input.animationType,
|
|
223
374
|
itemId: input.itemId,
|
|
224
375
|
});
|
|
225
|
-
return executeOrGenerate(code, description, options);
|
|
376
|
+
return executeOrGenerate(code, description, options, 'pinepaper_animate');
|
|
226
377
|
}
|
|
227
378
|
case 'pinepaper_keyframe_animate': {
|
|
228
379
|
const input = KeyframeAnimateInputSchema.parse(args);
|
|
229
380
|
const code = codeGenerator.generateKeyframeAnimate(input);
|
|
230
|
-
return executeOrGenerate(code, `Applies keyframe animation with ${input.keyframes.length} keyframes to ${input.itemId}`, options);
|
|
381
|
+
return executeOrGenerate(code, `Applies keyframe animation with ${input.keyframes.length} keyframes to ${input.itemId}`, options, 'pinepaper_keyframe_animate');
|
|
231
382
|
}
|
|
232
383
|
case 'pinepaper_play_timeline': {
|
|
233
384
|
const input = PlayTimelineInputSchema.parse(args);
|
|
234
385
|
const code = codeGenerator.generatePlayTimeline(input.action, input.duration, input.loop, input.time);
|
|
235
|
-
return executeOrGenerate(code, `Timeline action: ${input.action}`, options);
|
|
386
|
+
return executeOrGenerate(code, `Timeline action: ${input.action}`, options, 'pinepaper_play_timeline');
|
|
236
387
|
}
|
|
237
388
|
// -----------------------------------------------------------------------
|
|
238
389
|
// GENERATOR TOOLS
|
|
@@ -243,11 +394,11 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
243
394
|
const description = getLocalizedSuccessMessage(i18n, 'generatorExecuted', {
|
|
244
395
|
generatorName: input.generatorName,
|
|
245
396
|
});
|
|
246
|
-
return executeOrGenerate(code, description, options);
|
|
397
|
+
return executeOrGenerate(code, description, options, 'pinepaper_execute_generator');
|
|
247
398
|
}
|
|
248
399
|
case 'pinepaper_list_generators': {
|
|
249
400
|
const code = codeGenerator.generateListGenerators();
|
|
250
|
-
return executeOrGenerate(code, 'Lists all available generators', options);
|
|
401
|
+
return executeOrGenerate(code, 'Lists all available generators', options, 'pinepaper_list_generators');
|
|
251
402
|
}
|
|
252
403
|
// -----------------------------------------------------------------------
|
|
253
404
|
// EFFECT TOOLS
|
|
@@ -259,7 +410,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
259
410
|
effectType: input.effectType,
|
|
260
411
|
itemId: input.itemId,
|
|
261
412
|
});
|
|
262
|
-
return executeOrGenerate(code, description, options);
|
|
413
|
+
return executeOrGenerate(code, description, options, 'pinepaper_apply_effect');
|
|
263
414
|
}
|
|
264
415
|
// -----------------------------------------------------------------------
|
|
265
416
|
// QUERY TOOLS
|
|
@@ -267,11 +418,11 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
267
418
|
case 'pinepaper_get_items': {
|
|
268
419
|
const input = GetItemsInputSchema.parse(args);
|
|
269
420
|
const code = codeGenerator.generateGetItems(input.filter);
|
|
270
|
-
return executeOrGenerate(code, 'Gets items from canvas', options);
|
|
421
|
+
return executeOrGenerate(code, 'Gets items from canvas', options, 'pinepaper_get_items');
|
|
271
422
|
}
|
|
272
423
|
case 'pinepaper_get_relation_stats': {
|
|
273
424
|
const code = codeGenerator.generateGetRelationStats();
|
|
274
|
-
return executeOrGenerate(code, 'Gets relation statistics', options);
|
|
425
|
+
return executeOrGenerate(code, 'Gets relation statistics', options, 'pinepaper_get_relation_stats');
|
|
275
426
|
}
|
|
276
427
|
// -----------------------------------------------------------------------
|
|
277
428
|
// CANVAS TOOLS
|
|
@@ -282,7 +433,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
282
433
|
const description = getLocalizedSuccessMessage(i18n, 'backgroundSet', {
|
|
283
434
|
color: input.color,
|
|
284
435
|
});
|
|
285
|
-
return executeOrGenerate(code, description, options);
|
|
436
|
+
return executeOrGenerate(code, description, options, 'pinepaper_set_background_color');
|
|
286
437
|
}
|
|
287
438
|
case 'pinepaper_set_canvas_size': {
|
|
288
439
|
const input = SetCanvasSizeInputSchema.parse(args);
|
|
@@ -291,16 +442,16 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
291
442
|
width: input.width,
|
|
292
443
|
height: input.height,
|
|
293
444
|
});
|
|
294
|
-
return executeOrGenerate(code, description, options);
|
|
445
|
+
return executeOrGenerate(code, description, options, 'pinepaper_set_canvas_size');
|
|
295
446
|
}
|
|
296
447
|
case 'pinepaper_get_canvas_size': {
|
|
297
448
|
const code = codeGenerator.generateGetCanvasSize();
|
|
298
|
-
return executeOrGenerate(code, 'Gets current canvas dimensions', options);
|
|
449
|
+
return executeOrGenerate(code, 'Gets current canvas dimensions', options, 'pinepaper_get_canvas_size');
|
|
299
450
|
}
|
|
300
451
|
case 'pinepaper_clear_canvas': {
|
|
301
452
|
const code = codeGenerator.generateClearCanvas();
|
|
302
453
|
const description = 'Clears all items from the canvas, including any welcome template items';
|
|
303
|
-
return executeOrGenerate(code, description, options);
|
|
454
|
+
return executeOrGenerate(code, description, options, 'pinepaper_clear_canvas');
|
|
304
455
|
}
|
|
305
456
|
case 'pinepaper_refresh_page': {
|
|
306
457
|
const controller = options.browserController || getBrowserController();
|
|
@@ -344,7 +495,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
344
495
|
const input = ImportSVGInputSchema.parse(args);
|
|
345
496
|
const code = codeGenerator.generateImportSVG(input.svgString, input.url, input.position, input.scale);
|
|
346
497
|
const description = 'Imports SVG onto the canvas';
|
|
347
|
-
return executeOrGenerate(code, description, options);
|
|
498
|
+
return executeOrGenerate(code, description, options, 'pinepaper_import_svg');
|
|
348
499
|
}
|
|
349
500
|
// -----------------------------------------------------------------------
|
|
350
501
|
// FILTER TOOLS
|
|
@@ -353,7 +504,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
353
504
|
const input = AddFilterInputSchema.parse(args);
|
|
354
505
|
const code = codeGenerator.generateAddFilter(input.filterType, input.params);
|
|
355
506
|
const description = `Adds ${input.filterType} filter to the canvas`;
|
|
356
|
-
return executeOrGenerate(code, description, options);
|
|
507
|
+
return executeOrGenerate(code, description, options, 'pinepaper_add_filter');
|
|
357
508
|
}
|
|
358
509
|
// -----------------------------------------------------------------------
|
|
359
510
|
// EXPORT TOOLS
|
|
@@ -363,7 +514,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
363
514
|
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
364
515
|
format: 'SVG',
|
|
365
516
|
});
|
|
366
|
-
return executeOrGenerate(code, description, options);
|
|
517
|
+
return executeOrGenerate(code, description, options, 'pinepaper_export_svg');
|
|
367
518
|
}
|
|
368
519
|
case 'pinepaper_export_training_data': {
|
|
369
520
|
const input = ExportTrainingDataInputSchema.parse(args);
|
|
@@ -371,7 +522,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
371
522
|
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
372
523
|
format: input.format?.toUpperCase() || 'JSON',
|
|
373
524
|
});
|
|
374
|
-
return executeOrGenerate(code, description, options);
|
|
525
|
+
return executeOrGenerate(code, description, options, 'pinepaper_export_training_data');
|
|
375
526
|
}
|
|
376
527
|
// -----------------------------------------------------------------------
|
|
377
528
|
// BROWSER CONTROL TOOLS
|
|
@@ -455,7 +606,12 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
455
606
|
}
|
|
456
607
|
const screenshot = await controller.takeScreenshot();
|
|
457
608
|
if (!screenshot) {
|
|
458
|
-
|
|
609
|
+
// Capture canvas state for debugging
|
|
610
|
+
const canvasState = await captureCanvasState(controller);
|
|
611
|
+
return errorResult('SCREENSHOT_FAILED', 'Failed to capture screenshot', undefined, {
|
|
612
|
+
toolName: 'pinepaper_browser_screenshot',
|
|
613
|
+
canvasState: canvasState || undefined,
|
|
614
|
+
});
|
|
459
615
|
}
|
|
460
616
|
return screenshotResult(screenshot);
|
|
461
617
|
}
|
|
@@ -474,6 +630,106 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
474
630
|
};
|
|
475
631
|
}
|
|
476
632
|
// -----------------------------------------------------------------------
|
|
633
|
+
// PERFORMANCE TOOLS
|
|
634
|
+
// -----------------------------------------------------------------------
|
|
635
|
+
case 'pinepaper_get_performance_metrics': {
|
|
636
|
+
const input = GetPerformanceMetricsInputSchema.parse(args);
|
|
637
|
+
const perfTracker = getPerformanceTracker();
|
|
638
|
+
// Build filter
|
|
639
|
+
const filter = {
|
|
640
|
+
toolName: input.toolName,
|
|
641
|
+
phase: input.phase,
|
|
642
|
+
since: input.since,
|
|
643
|
+
limit: input.limit ?? 100,
|
|
644
|
+
};
|
|
645
|
+
// Get format (default to 'summary')
|
|
646
|
+
const format = input.format ?? 'summary';
|
|
647
|
+
// Export metrics in requested format
|
|
648
|
+
const output = perfTracker.exportMetrics(format, filter);
|
|
649
|
+
// Get tracker stats
|
|
650
|
+
const trackerStats = perfTracker.getStats();
|
|
651
|
+
return {
|
|
652
|
+
content: [
|
|
653
|
+
{
|
|
654
|
+
type: 'text',
|
|
655
|
+
text: format === 'csv' || format === 'summary'
|
|
656
|
+
? output
|
|
657
|
+
: JSON.stringify({
|
|
658
|
+
metrics: output,
|
|
659
|
+
trackerInfo: trackerStats,
|
|
660
|
+
}, null, 2),
|
|
661
|
+
},
|
|
662
|
+
],
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
// -----------------------------------------------------------------------
|
|
666
|
+
// ASSET TOOLS
|
|
667
|
+
// -----------------------------------------------------------------------
|
|
668
|
+
case 'pinepaper_search_assets': {
|
|
669
|
+
const input = SearchAssetsInputSchema.parse(args);
|
|
670
|
+
const { getAssetManager } = await import('../assets/index.js');
|
|
671
|
+
const assetManager = getAssetManager();
|
|
672
|
+
try {
|
|
673
|
+
const results = await assetManager.search(input.query, input.repository || 'all', input.limit || 10);
|
|
674
|
+
return {
|
|
675
|
+
content: [
|
|
676
|
+
{
|
|
677
|
+
type: 'text',
|
|
678
|
+
text: JSON.stringify({
|
|
679
|
+
success: true,
|
|
680
|
+
query: input.query,
|
|
681
|
+
repository: input.repository || 'all',
|
|
682
|
+
count: results.length,
|
|
683
|
+
results: results.map((r) => ({
|
|
684
|
+
id: r.id,
|
|
685
|
+
repository: r.repository,
|
|
686
|
+
title: r.title,
|
|
687
|
+
description: r.description,
|
|
688
|
+
previewUrl: r.previewUrl,
|
|
689
|
+
license: r.license,
|
|
690
|
+
tags: r.tags,
|
|
691
|
+
})),
|
|
692
|
+
}, null, 2),
|
|
693
|
+
},
|
|
694
|
+
],
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
return errorResult(ErrorCodes.EXECUTION_ERROR, error instanceof Error ? error.message : 'Failed to search assets', { query: input.query });
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
case 'pinepaper_import_asset': {
|
|
702
|
+
const input = ImportAssetInputSchema.parse(args);
|
|
703
|
+
const { getAssetManager } = await import('../assets/index.js');
|
|
704
|
+
const assetManager = getAssetManager();
|
|
705
|
+
try {
|
|
706
|
+
// Validate that either assetId or url is provided
|
|
707
|
+
if (!input.assetId && !input.url) {
|
|
708
|
+
return errorResult(ErrorCodes.INVALID_PARAMS, 'Either assetId or url must be provided');
|
|
709
|
+
}
|
|
710
|
+
let svg;
|
|
711
|
+
let metadata;
|
|
712
|
+
if (input.assetId) {
|
|
713
|
+
// Download from asset manager
|
|
714
|
+
const result = await assetManager.download(input.assetId);
|
|
715
|
+
svg = result.svg;
|
|
716
|
+
metadata = result.metadata;
|
|
717
|
+
}
|
|
718
|
+
else if (input.url) {
|
|
719
|
+
// For URL imports, we'd need to fetch the SVG
|
|
720
|
+
// For now, delegate to pinepaper_import_svg
|
|
721
|
+
return errorResult(ErrorCodes.INVALID_PARAMS, 'URL imports not yet implemented - use pinepaper_import_svg with url parameter instead', { url: input.url });
|
|
722
|
+
}
|
|
723
|
+
// Import the SVG onto canvas using existing import_svg tool
|
|
724
|
+
const code = codeGenerator.generateImportSVG(svg, undefined, input.position, input.scale);
|
|
725
|
+
const description = `Imported asset: ${metadata.title} (${metadata.license.name})`;
|
|
726
|
+
return executeOrGenerate(code, description, options, 'pinepaper_import_asset');
|
|
727
|
+
}
|
|
728
|
+
catch (error) {
|
|
729
|
+
return errorResult(ErrorCodes.EXECUTION_ERROR, error instanceof Error ? error.message : 'Failed to import asset', { assetId: input.assetId, url: input.url });
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
// -----------------------------------------------------------------------
|
|
477
733
|
// UNKNOWN TOOL
|
|
478
734
|
// -----------------------------------------------------------------------
|
|
479
735
|
default: {
|
|
@@ -487,6 +743,9 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
487
743
|
'pinepaper_delete_item',
|
|
488
744
|
'pinepaper_create_glossy_sphere',
|
|
489
745
|
'pinepaper_create_diagonal_stripes',
|
|
746
|
+
'pinepaper_batch_create',
|
|
747
|
+
'pinepaper_batch_modify',
|
|
748
|
+
'pinepaper_create_grid',
|
|
490
749
|
'pinepaper_add_relation',
|
|
491
750
|
'pinepaper_remove_relation',
|
|
492
751
|
'pinepaper_query_relations',
|
|
@@ -511,6 +770,9 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
511
770
|
'pinepaper_browser_disconnect',
|
|
512
771
|
'pinepaper_browser_screenshot',
|
|
513
772
|
'pinepaper_browser_status',
|
|
773
|
+
'pinepaper_get_performance_metrics',
|
|
774
|
+
'pinepaper_search_assets',
|
|
775
|
+
'pinepaper_import_asset',
|
|
514
776
|
],
|
|
515
777
|
});
|
|
516
778
|
}
|
|
@@ -520,18 +782,35 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
520
782
|
if (error instanceof ZodError) {
|
|
521
783
|
return handleValidationError(error, i18n);
|
|
522
784
|
}
|
|
785
|
+
// Try to capture canvas state for error context (if browser is connected)
|
|
786
|
+
let canvasState = null;
|
|
787
|
+
try {
|
|
788
|
+
const controller = options.browserController || getBrowserController();
|
|
789
|
+
if (controller.connected) {
|
|
790
|
+
canvasState = await captureCanvasState(controller);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
catch (stateError) {
|
|
794
|
+
// Ignore errors from canvas state capture
|
|
795
|
+
}
|
|
523
796
|
if (error instanceof Error) {
|
|
524
797
|
const message = i18n
|
|
525
798
|
? i18n.getError('executionError', { message: error.message })
|
|
526
799
|
: error.message;
|
|
527
800
|
return errorResult(ErrorCodes.EXECUTION_ERROR, message, {
|
|
528
801
|
stack: error.stack,
|
|
802
|
+
}, {
|
|
803
|
+
toolName,
|
|
804
|
+
canvasState: canvasState || undefined,
|
|
529
805
|
});
|
|
530
806
|
}
|
|
531
807
|
const message = i18n
|
|
532
808
|
? i18n.getError('executionError', { message: 'Unknown error occurred' })
|
|
533
809
|
: 'Unknown error occurred';
|
|
534
|
-
return errorResult(ErrorCodes.EXECUTION_ERROR, message, { error }
|
|
810
|
+
return errorResult(ErrorCodes.EXECUTION_ERROR, message, { error }, {
|
|
811
|
+
toolName,
|
|
812
|
+
canvasState: canvasState || undefined,
|
|
813
|
+
});
|
|
535
814
|
}
|
|
536
815
|
}
|
|
537
816
|
//# sourceMappingURL=handlers.js.map
|