@pinepaper.studio/mcp-server 1.2.2 → 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 +360 -0
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +292 -37
- package/dist/tools/handlers.js.map +1 -1
- package/dist/types/schemas.d.ts +69 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +28 -0
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +14 -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, BatchCreateInputSchema, BatchModifyInputSchema, CreateGridInputSchema, 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,13 @@ 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');
|
|
187
317
|
}
|
|
188
318
|
// -----------------------------------------------------------------------
|
|
189
319
|
// BATCH OPERATION TOOLS
|
|
@@ -192,19 +322,19 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
192
322
|
const input = BatchCreateInputSchema.parse(args);
|
|
193
323
|
const code = codeGenerator.generateBatchCreate(input);
|
|
194
324
|
const description = `Batch creates ${input.items.length} items with single history save`;
|
|
195
|
-
return executeOrGenerate(code, description, options);
|
|
325
|
+
return executeOrGenerate(code, description, options, 'pinepaper_batch_create');
|
|
196
326
|
}
|
|
197
327
|
case 'pinepaper_batch_modify': {
|
|
198
328
|
const input = BatchModifyInputSchema.parse(args);
|
|
199
329
|
const code = codeGenerator.generateBatchModify(input);
|
|
200
330
|
const description = `Batch modifies ${input.modifications.length} items with single history save`;
|
|
201
|
-
return executeOrGenerate(code, description, options);
|
|
331
|
+
return executeOrGenerate(code, description, options, 'pinepaper_batch_modify');
|
|
202
332
|
}
|
|
203
333
|
case 'pinepaper_create_grid': {
|
|
204
334
|
const input = CreateGridInputSchema.parse(args);
|
|
205
335
|
const code = codeGenerator.generateCreateGrid(input);
|
|
206
336
|
const description = `Creates a ${input.cols}x${input.rows} grid${input.animated ? ' with wave animation' : ''}`;
|
|
207
|
-
return executeOrGenerate(code, description, options);
|
|
337
|
+
return executeOrGenerate(code, description, options, 'pinepaper_create_grid');
|
|
208
338
|
}
|
|
209
339
|
// -----------------------------------------------------------------------
|
|
210
340
|
// RELATION TOOLS
|
|
@@ -217,7 +347,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
217
347
|
sourceId: input.sourceId,
|
|
218
348
|
targetId: input.targetId,
|
|
219
349
|
});
|
|
220
|
-
return executeOrGenerate(code, description, options);
|
|
350
|
+
return executeOrGenerate(code, description, options, 'pinepaper_add_relation');
|
|
221
351
|
}
|
|
222
352
|
case 'pinepaper_remove_relation': {
|
|
223
353
|
const input = RemoveRelationInputSchema.parse(args);
|
|
@@ -226,12 +356,12 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
226
356
|
sourceId: input.sourceId,
|
|
227
357
|
targetId: input.targetId,
|
|
228
358
|
});
|
|
229
|
-
return executeOrGenerate(code, description, options);
|
|
359
|
+
return executeOrGenerate(code, description, options, 'pinepaper_remove_relation');
|
|
230
360
|
}
|
|
231
361
|
case 'pinepaper_query_relations': {
|
|
232
362
|
const input = QueryRelationsInputSchema.parse(args);
|
|
233
363
|
const code = codeGenerator.generateQueryRelations(input.itemId, input.relationType, input.direction);
|
|
234
|
-
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');
|
|
235
365
|
}
|
|
236
366
|
// -----------------------------------------------------------------------
|
|
237
367
|
// ANIMATION TOOLS
|
|
@@ -243,17 +373,17 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
243
373
|
animationType: input.animationType,
|
|
244
374
|
itemId: input.itemId,
|
|
245
375
|
});
|
|
246
|
-
return executeOrGenerate(code, description, options);
|
|
376
|
+
return executeOrGenerate(code, description, options, 'pinepaper_animate');
|
|
247
377
|
}
|
|
248
378
|
case 'pinepaper_keyframe_animate': {
|
|
249
379
|
const input = KeyframeAnimateInputSchema.parse(args);
|
|
250
380
|
const code = codeGenerator.generateKeyframeAnimate(input);
|
|
251
|
-
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');
|
|
252
382
|
}
|
|
253
383
|
case 'pinepaper_play_timeline': {
|
|
254
384
|
const input = PlayTimelineInputSchema.parse(args);
|
|
255
385
|
const code = codeGenerator.generatePlayTimeline(input.action, input.duration, input.loop, input.time);
|
|
256
|
-
return executeOrGenerate(code, `Timeline action: ${input.action}`, options);
|
|
386
|
+
return executeOrGenerate(code, `Timeline action: ${input.action}`, options, 'pinepaper_play_timeline');
|
|
257
387
|
}
|
|
258
388
|
// -----------------------------------------------------------------------
|
|
259
389
|
// GENERATOR TOOLS
|
|
@@ -264,11 +394,11 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
264
394
|
const description = getLocalizedSuccessMessage(i18n, 'generatorExecuted', {
|
|
265
395
|
generatorName: input.generatorName,
|
|
266
396
|
});
|
|
267
|
-
return executeOrGenerate(code, description, options);
|
|
397
|
+
return executeOrGenerate(code, description, options, 'pinepaper_execute_generator');
|
|
268
398
|
}
|
|
269
399
|
case 'pinepaper_list_generators': {
|
|
270
400
|
const code = codeGenerator.generateListGenerators();
|
|
271
|
-
return executeOrGenerate(code, 'Lists all available generators', options);
|
|
401
|
+
return executeOrGenerate(code, 'Lists all available generators', options, 'pinepaper_list_generators');
|
|
272
402
|
}
|
|
273
403
|
// -----------------------------------------------------------------------
|
|
274
404
|
// EFFECT TOOLS
|
|
@@ -280,7 +410,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
280
410
|
effectType: input.effectType,
|
|
281
411
|
itemId: input.itemId,
|
|
282
412
|
});
|
|
283
|
-
return executeOrGenerate(code, description, options);
|
|
413
|
+
return executeOrGenerate(code, description, options, 'pinepaper_apply_effect');
|
|
284
414
|
}
|
|
285
415
|
// -----------------------------------------------------------------------
|
|
286
416
|
// QUERY TOOLS
|
|
@@ -288,11 +418,11 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
288
418
|
case 'pinepaper_get_items': {
|
|
289
419
|
const input = GetItemsInputSchema.parse(args);
|
|
290
420
|
const code = codeGenerator.generateGetItems(input.filter);
|
|
291
|
-
return executeOrGenerate(code, 'Gets items from canvas', options);
|
|
421
|
+
return executeOrGenerate(code, 'Gets items from canvas', options, 'pinepaper_get_items');
|
|
292
422
|
}
|
|
293
423
|
case 'pinepaper_get_relation_stats': {
|
|
294
424
|
const code = codeGenerator.generateGetRelationStats();
|
|
295
|
-
return executeOrGenerate(code, 'Gets relation statistics', options);
|
|
425
|
+
return executeOrGenerate(code, 'Gets relation statistics', options, 'pinepaper_get_relation_stats');
|
|
296
426
|
}
|
|
297
427
|
// -----------------------------------------------------------------------
|
|
298
428
|
// CANVAS TOOLS
|
|
@@ -303,7 +433,7 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
303
433
|
const description = getLocalizedSuccessMessage(i18n, 'backgroundSet', {
|
|
304
434
|
color: input.color,
|
|
305
435
|
});
|
|
306
|
-
return executeOrGenerate(code, description, options);
|
|
436
|
+
return executeOrGenerate(code, description, options, 'pinepaper_set_background_color');
|
|
307
437
|
}
|
|
308
438
|
case 'pinepaper_set_canvas_size': {
|
|
309
439
|
const input = SetCanvasSizeInputSchema.parse(args);
|
|
@@ -312,16 +442,16 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
312
442
|
width: input.width,
|
|
313
443
|
height: input.height,
|
|
314
444
|
});
|
|
315
|
-
return executeOrGenerate(code, description, options);
|
|
445
|
+
return executeOrGenerate(code, description, options, 'pinepaper_set_canvas_size');
|
|
316
446
|
}
|
|
317
447
|
case 'pinepaper_get_canvas_size': {
|
|
318
448
|
const code = codeGenerator.generateGetCanvasSize();
|
|
319
|
-
return executeOrGenerate(code, 'Gets current canvas dimensions', options);
|
|
449
|
+
return executeOrGenerate(code, 'Gets current canvas dimensions', options, 'pinepaper_get_canvas_size');
|
|
320
450
|
}
|
|
321
451
|
case 'pinepaper_clear_canvas': {
|
|
322
452
|
const code = codeGenerator.generateClearCanvas();
|
|
323
453
|
const description = 'Clears all items from the canvas, including any welcome template items';
|
|
324
|
-
return executeOrGenerate(code, description, options);
|
|
454
|
+
return executeOrGenerate(code, description, options, 'pinepaper_clear_canvas');
|
|
325
455
|
}
|
|
326
456
|
case 'pinepaper_refresh_page': {
|
|
327
457
|
const controller = options.browserController || getBrowserController();
|
|
@@ -365,7 +495,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
365
495
|
const input = ImportSVGInputSchema.parse(args);
|
|
366
496
|
const code = codeGenerator.generateImportSVG(input.svgString, input.url, input.position, input.scale);
|
|
367
497
|
const description = 'Imports SVG onto the canvas';
|
|
368
|
-
return executeOrGenerate(code, description, options);
|
|
498
|
+
return executeOrGenerate(code, description, options, 'pinepaper_import_svg');
|
|
369
499
|
}
|
|
370
500
|
// -----------------------------------------------------------------------
|
|
371
501
|
// FILTER TOOLS
|
|
@@ -374,7 +504,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
374
504
|
const input = AddFilterInputSchema.parse(args);
|
|
375
505
|
const code = codeGenerator.generateAddFilter(input.filterType, input.params);
|
|
376
506
|
const description = `Adds ${input.filterType} filter to the canvas`;
|
|
377
|
-
return executeOrGenerate(code, description, options);
|
|
507
|
+
return executeOrGenerate(code, description, options, 'pinepaper_add_filter');
|
|
378
508
|
}
|
|
379
509
|
// -----------------------------------------------------------------------
|
|
380
510
|
// EXPORT TOOLS
|
|
@@ -384,7 +514,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
384
514
|
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
385
515
|
format: 'SVG',
|
|
386
516
|
});
|
|
387
|
-
return executeOrGenerate(code, description, options);
|
|
517
|
+
return executeOrGenerate(code, description, options, 'pinepaper_export_svg');
|
|
388
518
|
}
|
|
389
519
|
case 'pinepaper_export_training_data': {
|
|
390
520
|
const input = ExportTrainingDataInputSchema.parse(args);
|
|
@@ -392,7 +522,7 @@ You can now start creating new items on a clean canvas.`,
|
|
|
392
522
|
const description = getLocalizedSuccessMessage(i18n, 'exported', {
|
|
393
523
|
format: input.format?.toUpperCase() || 'JSON',
|
|
394
524
|
});
|
|
395
|
-
return executeOrGenerate(code, description, options);
|
|
525
|
+
return executeOrGenerate(code, description, options, 'pinepaper_export_training_data');
|
|
396
526
|
}
|
|
397
527
|
// -----------------------------------------------------------------------
|
|
398
528
|
// BROWSER CONTROL TOOLS
|
|
@@ -476,7 +606,12 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
476
606
|
}
|
|
477
607
|
const screenshot = await controller.takeScreenshot();
|
|
478
608
|
if (!screenshot) {
|
|
479
|
-
|
|
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
|
+
});
|
|
480
615
|
}
|
|
481
616
|
return screenshotResult(screenshot);
|
|
482
617
|
}
|
|
@@ -495,6 +630,106 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
495
630
|
};
|
|
496
631
|
}
|
|
497
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
|
+
// -----------------------------------------------------------------------
|
|
498
733
|
// UNKNOWN TOOL
|
|
499
734
|
// -----------------------------------------------------------------------
|
|
500
735
|
default: {
|
|
@@ -535,6 +770,9 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
535
770
|
'pinepaper_browser_disconnect',
|
|
536
771
|
'pinepaper_browser_screenshot',
|
|
537
772
|
'pinepaper_browser_status',
|
|
773
|
+
'pinepaper_get_performance_metrics',
|
|
774
|
+
'pinepaper_search_assets',
|
|
775
|
+
'pinepaper_import_asset',
|
|
538
776
|
],
|
|
539
777
|
});
|
|
540
778
|
}
|
|
@@ -544,18 +782,35 @@ Browser is ready. You can now use other pinepaper tools to create and animate gr
|
|
|
544
782
|
if (error instanceof ZodError) {
|
|
545
783
|
return handleValidationError(error, i18n);
|
|
546
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
|
+
}
|
|
547
796
|
if (error instanceof Error) {
|
|
548
797
|
const message = i18n
|
|
549
798
|
? i18n.getError('executionError', { message: error.message })
|
|
550
799
|
: error.message;
|
|
551
800
|
return errorResult(ErrorCodes.EXECUTION_ERROR, message, {
|
|
552
801
|
stack: error.stack,
|
|
802
|
+
}, {
|
|
803
|
+
toolName,
|
|
804
|
+
canvasState: canvasState || undefined,
|
|
553
805
|
});
|
|
554
806
|
}
|
|
555
807
|
const message = i18n
|
|
556
808
|
? i18n.getError('executionError', { message: 'Unknown error occurred' })
|
|
557
809
|
: 'Unknown error occurred';
|
|
558
|
-
return errorResult(ErrorCodes.EXECUTION_ERROR, message, { error }
|
|
810
|
+
return errorResult(ErrorCodes.EXECUTION_ERROR, message, { error }, {
|
|
811
|
+
toolName,
|
|
812
|
+
canvasState: canvasState || undefined,
|
|
813
|
+
});
|
|
559
814
|
}
|
|
560
815
|
}
|
|
561
816
|
//# sourceMappingURL=handlers.js.map
|