@pinepaper.studio/mcp-server 1.6.32 → 1.6.34
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 +115 -1
- package/dist/agent/types.d.ts +3 -3
- package/dist/build-info.json +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +1 -1
- package/dist/ontology/upstream-vocabulary.js +1 -1
- package/dist/tools/batch-macros.d.ts +20 -1
- package/dist/tools/batch-macros.d.ts.map +1 -1
- package/dist/tools/batch-macros.js +146 -7
- package/dist/tools/batch-macros.js.map +1 -1
- package/dist/tools/compact-descriptions.js +1 -1
- package/dist/tools/compact-descriptions.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +82 -55
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +5 -3
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +11 -3
- package/dist/tools/engine-lists.js.map +1 -1
- package/dist/tools/engine-surface.d.ts +1 -1
- package/dist/tools/engine-surface.d.ts.map +1 -1
- package/dist/tools/engine-surface.js +11 -5
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +71 -16
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/lane.d.ts +8 -1
- package/dist/tools/lane.d.ts.map +1 -1
- package/dist/tools/lane.js +56 -15
- package/dist/tools/lane.js.map +1 -1
- package/dist/tools/minimal-descriptions.js +1 -1
- package/dist/tools/minimal-descriptions.js.map +1 -1
- package/dist/tools/reply-fields.d.ts +15 -0
- package/dist/tools/reply-fields.d.ts.map +1 -0
- package/dist/tools/reply-fields.js +117 -0
- package/dist/tools/reply-fields.js.map +1 -0
- package/dist/tools/scene-cache-export.d.ts.map +1 -1
- package/dist/tools/scene-cache-export.js +2 -1
- package/dist/tools/scene-cache-export.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.d.ts.map +1 -1
- package/dist/tools/shape-params.js +4 -2
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/toolkits.d.ts +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +7 -2
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +142 -50
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +40 -6
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +20 -7
- package/dist/types/schemas.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/tools/handlers.js
CHANGED
|
@@ -9,8 +9,9 @@ import { dropPrivateRelationParams, normalizeBatchOperationNames, renamedArgumen
|
|
|
9
9
|
import { nestedIgnoredPaths } from './nested-ignored.js';
|
|
10
10
|
import { CRAFT_FRAME_JS, generateDrawWeave, generateDrawKnots, generateDrawSashiko, generateDrawSubdivision, generateUiKit, uiKitCallProblems, } from './craft-tools.js';
|
|
11
11
|
import { exportPerScene } from './scene-cache-export.js';
|
|
12
|
+
import { boundedStructured, reportedIgnoredPaths } from './reply-fields.js';
|
|
12
13
|
import { codeGenerator, generateQueryMutationsCode, SHEET_RUBRIC } from '../types/code-generator.js';
|
|
13
|
-
import { expandBatchMacros, BatchMacroError } from './batch-macros.js';
|
|
14
|
+
import { expandBatchMacros, BatchMacroError, batchPreflightView, withKeyColumns } from './batch-macros.js';
|
|
14
15
|
import { CreateItemInputSchema, ModifyItemInputSchema, DeleteItemInputSchema, AddRelationInputSchema, RemoveRelationInputSchema, QueryRelationsInputSchema, AnimateItemInputSchema, ImportMotionCaptureInputSchema, KeyframeAnimateInputSchema, ExecuteGeneratorInputSchema, ApplyEffectInputSchema, GetItemsInputSchema, PlayTimelineInputSchema, SetBackgroundColorInputSchema, SetCanvasSizeInputSchema, ImportSVGInputSchema, ImportMermaidInputSchema, AddFilterInputSchema, CreateGlossySphereInputSchema, CreateDiagonalStripesInputSchema, BatchCreateInputSchema, BatchModifyInputSchema, CreateGridInputSchema, GeometryInputSchema, EquationPathInputSchema, EventInputSchema, ConstructionSequenceInputSchema, ValidateSceneInputSchema, CaptureFramesInputSchema, InstantiateOntologyInputSchema, LintSceneInputSchema, MediaInputSchema, TextStyleInputSchema, TextEffectInputSchema, DesignMediumInputSchema, RelightInputSchema, ChoreographInputSchema, EmitterInputSchema, MorphSequenceInputSchema, OriginalCharacterInputSchema, LookInputSchema, RenderHookInputSchema, ShaderGraphInputSchema, ShatterImageInputSchema, ImportLayeredCharacterInputSchema, CharacterInputSchema, GameInputSchema, World3DInputSchema, BrandKitInputSchema, ComponentInputSchema, ArtboardInputSchema, CommentInputSchema, ProvenanceInputSchema, SceneDiffInputSchema, AudioBeatsInputSchema, TemplateParamsInputSchema, RenderBatchInputSchema, AccessibilityCheckInputSchema, QueryMutationsInputSchema, ComposeInputSchema, CropImageInputSchema, PathOpInputSchema, MotionInputSchema, SoundInputSchema, InterchangeInputSchema, StickInputSchema, DesignSystemInputSchema, StoryInputSchema, ChromaKeyInputSchema, RiggingInputSchema, GroupInputSchema, CameraDirectorInputSchema, DetectObjectsInputSchema, ExtractObjectInputSchema, ArrangeInputSchema, CreateSceneInputSchema, GetPerformanceMetricsInputSchema, DiagnosticReportInputSchema, SearchAssetsInputSchema, ImportAssetInputSchema, P5DrawInputSchema,
|
|
15
16
|
// Diagram schemas
|
|
16
17
|
CreateDiagramShapeInputSchema, ConnectInputSchema, ConnectPortsInputSchema, AddPortsInputSchema, AutoLayoutInputSchema, GetDiagramShapesInputSchema, UpdateConnectorInputSchema, RemoveConnectorInputSchema, DiagramModeInputSchema,
|
|
@@ -161,11 +162,11 @@ function exportGovernorTimeoutMs() {
|
|
|
161
162
|
* size cap. This reads the user's disk on their instruction, the same as the
|
|
162
163
|
* export side writes to it, and neither should be a wildcard.
|
|
163
164
|
*/
|
|
164
|
-
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.avif']);
|
|
165
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.apng', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.avif']);
|
|
165
166
|
const MAX_LOCAL_IMAGE_BYTES = 32 * 1024 * 1024;
|
|
166
167
|
const IMAGE_MIME = {
|
|
167
168
|
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif',
|
|
168
|
-
'.webp': 'image/webp', '.svg': 'image/svg+xml', '.bmp': 'image/bmp', '.avif': 'image/avif',
|
|
169
|
+
'.webp': 'image/webp', '.apng': 'image/apng', '.svg': 'image/svg+xml', '.bmp': 'image/bmp', '.avif': 'image/avif',
|
|
169
170
|
};
|
|
170
171
|
/**
|
|
171
172
|
* THE PAGE CANNOT FETCH A THIRD-PARTY IMAGE. THIS PROCESS CAN.
|
|
@@ -421,6 +422,7 @@ async function saveAdExport(r, input, platform) {
|
|
|
421
422
|
if (warnings.length && cleanResult.fidelity.note)
|
|
422
423
|
delete cleanResult.fidelity.note;
|
|
423
424
|
return {
|
|
425
|
+
structuredContent: boundedStructured(cleanResult),
|
|
424
426
|
content: [{
|
|
425
427
|
type: 'text',
|
|
426
428
|
text: `Ad saved:\n\n${Object.entries(files).map(([k, v]) => `${k}: ${v}`).join('\n')}\nFormat: ${r.format}\nSize: ${r.adSize.width}x${r.adSize.height}, upload ${(uploadBytes / 1024).toFixed(1)} KB\n\nResult: ${JSON.stringify(cleanResult, null, 2)}`,
|
|
@@ -1909,22 +1911,60 @@ export function batchOpIgnoredPaths(args) {
|
|
|
1909
1911
|
return out.slice(0, 50);
|
|
1910
1912
|
}
|
|
1911
1913
|
export const IGNORED_ARGUMENTS_META_KEY = 'pinepaper.studio/ignoredArguments';
|
|
1912
|
-
/**
|
|
1914
|
+
/**
|
|
1915
|
+
* Adds fields to a reply whose first block is a JSON object, and to its structuredContent when it already has one (a
|
|
1916
|
+
* saved export: prose first, data beside it). False when neither took them (or nothing to add is true).
|
|
1917
|
+
*/
|
|
1913
1918
|
function withReplyFields(result, fields) {
|
|
1914
1919
|
if (!Object.keys(fields).length)
|
|
1915
1920
|
return true;
|
|
1921
|
+
const hadStructured = !!result.structuredContent;
|
|
1922
|
+
if (result.structuredContent)
|
|
1923
|
+
result.structuredContent = { ...result.structuredContent, ...fields };
|
|
1916
1924
|
const first = result.content?.[0];
|
|
1917
1925
|
if (first?.type !== 'text')
|
|
1918
|
-
return
|
|
1926
|
+
return hadStructured;
|
|
1919
1927
|
try {
|
|
1920
1928
|
const obj = JSON.parse(first.text);
|
|
1921
1929
|
if (!obj || typeof obj !== 'object' || Array.isArray(obj))
|
|
1922
|
-
return
|
|
1930
|
+
return hadStructured;
|
|
1923
1931
|
result.content = [{ ...first, text: JSON.stringify({ ...obj, ...fields }, null, 2) }, ...result.content.slice(1)];
|
|
1924
1932
|
return true;
|
|
1925
1933
|
}
|
|
1926
1934
|
catch {
|
|
1927
|
-
return
|
|
1935
|
+
return hadStructured;
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
/** How many ops a written batch op becomes; a macro that does not expand is refused before anything runs. */
|
|
1939
|
+
function expandedOpCount(op) {
|
|
1940
|
+
try {
|
|
1941
|
+
return expandBatchMacros([op]).length;
|
|
1942
|
+
}
|
|
1943
|
+
catch {
|
|
1944
|
+
return 1;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* The tools that hand back something the studio rendered. Render behaviour follows the live studio, not this package,
|
|
1949
|
+
* so a result is traced by the build that made it. agent_export's generated code says so itself; the rest are asked
|
|
1950
|
+
* here, once, after the call.
|
|
1951
|
+
*/
|
|
1952
|
+
const RENDERING_TOOLS = new Set(['pinepaper_agent_export', 'pinepaper_capture_frames', 'pinepaper_export_scene', 'pinepaper_export_svg',
|
|
1953
|
+
'pinepaper_export_training_data', 'pinepaper_export_widget', 'pinepaper_export_widget_html', 'pinepaper_render_batch', 'pinepaper_sprite_sheet']);
|
|
1954
|
+
async function renderingBuildField(toolName, args, result, options) {
|
|
1955
|
+
if (!RENDERING_TOOLS.has(toolName) || args.estimateOnly === true || result.isError || !options.executeInBrowser || result.structuredContent?.studioBuild)
|
|
1956
|
+
return {};
|
|
1957
|
+
if ((options.executionMode ?? getExecutionMode()) === 'code')
|
|
1958
|
+
return {};
|
|
1959
|
+
const controller = (options.browserController ?? peekBrowserController());
|
|
1960
|
+
if (!controller?.connected || typeof controller.executeCode !== 'function')
|
|
1961
|
+
return {};
|
|
1962
|
+
try {
|
|
1963
|
+
const r = await controller.executeCode(`(function () { return typeof app !== 'undefined' && app.buildId ? app.buildId : null; })();`, false, { bypassGovernor: true });
|
|
1964
|
+
return r?.success && typeof r.result === 'string' ? { studioBuild: r.result } : {};
|
|
1965
|
+
}
|
|
1966
|
+
catch {
|
|
1967
|
+
return {}; // the export stands
|
|
1928
1968
|
}
|
|
1929
1969
|
}
|
|
1930
1970
|
export async function handleToolCall(toolName, args, options = {}) {
|
|
@@ -1955,10 +1995,12 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
1955
1995
|
}
|
|
1956
1996
|
}
|
|
1957
1997
|
const ignored = await ignoredArgumentsNoteFor(toolName, args);
|
|
1958
|
-
if (ignored)
|
|
1998
|
+
if (ignored)
|
|
1959
1999
|
result.content = [...(result.content ?? []), { type: 'text', text: ignored.note }];
|
|
1960
|
-
|
|
1961
|
-
|
|
2000
|
+
// What only the run can tell: an option or property the op's own warning named. Its sentence is already in the reply.
|
|
2001
|
+
const ignoredPaths = [...new Set([...(ignored?.ignored ?? []), ...reportedIgnoredPaths(toolName, args, result, expandedOpCount)])];
|
|
2002
|
+
if (ignoredPaths.length)
|
|
2003
|
+
result._meta = { ...(result._meta ?? {}), [IGNORED_ARGUMENTS_META_KEY]: ignoredPaths };
|
|
1962
2004
|
if (renamed.length)
|
|
1963
2005
|
result._meta = { ...(result._meta ?? {}), [RENAMED_ARGUMENTS_META_KEY]: renamed };
|
|
1964
2006
|
// IN THE REPLY'S OWN JSON. A client that has structuredContent reads that, and it is built from the first block
|
|
@@ -1966,7 +2008,8 @@ export async function handleToolCall(toolName, args, options = {}) {
|
|
|
1966
2008
|
const folded = withReplyFields(result, {
|
|
1967
2009
|
...(renamed.length ? { translatedArguments: renamed } : {}),
|
|
1968
2010
|
...(dropped.length ? { droppedArguments: dropped } : {}),
|
|
1969
|
-
...(
|
|
2011
|
+
...(ignoredPaths.length ? { ignoredArguments: ignoredPaths } : {}),
|
|
2012
|
+
...await renderingBuildField(toolName, args, result, options),
|
|
1970
2013
|
});
|
|
1971
2014
|
if (!folded) {
|
|
1972
2015
|
const lines = [...(renamed.length ? [renamedArgumentsNote(renamed)] : []), ...(dropped.length ? [`Not sent to the studio, as its private state: ${dropped.join(', ')}.`] : [])];
|
|
@@ -2910,6 +2953,15 @@ async function handleToolCallInner(toolName, args, options, tracker, baseTimerId
|
|
|
2910
2953
|
return executeOrGenerate(code, what, options, 'pinepaper_import_motion_capture');
|
|
2911
2954
|
}
|
|
2912
2955
|
case 'pinepaper_keyframe_animate': {
|
|
2956
|
+
// keys: the same keyframes by column; the rest of this path never sees them.
|
|
2957
|
+
try {
|
|
2958
|
+
args = withKeyColumns(args, 'pinepaper_keyframe_animate');
|
|
2959
|
+
}
|
|
2960
|
+
catch (e) {
|
|
2961
|
+
if (e instanceof BatchMacroError)
|
|
2962
|
+
return errorResult(ErrorCodes.VALIDATION_ERROR, e.message, {}, { toolName: 'pinepaper_keyframe_animate' });
|
|
2963
|
+
throw e;
|
|
2964
|
+
}
|
|
2913
2965
|
const input = KeyframeAnimateInputSchema.parse(args);
|
|
2914
2966
|
const code = codeGenerator.generateKeyframeAnimate(input);
|
|
2915
2967
|
return executeOrGenerate(code, `Applies keyframe animation with ${input.keyframes.length} keyframes to ${input.itemId}`, options, 'pinepaper_keyframe_animate');
|
|
@@ -3924,12 +3976,13 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
3924
3976
|
// Opt-out via skipValidation: true when the caller knows what they're
|
|
3925
3977
|
// doing (e.g. experimental vocabulary).
|
|
3926
3978
|
if (!input.skipValidation) {
|
|
3927
|
-
|
|
3979
|
+
// A create_many item gets the checks a create gets, reported at its own path.
|
|
3980
|
+
const { ops, paths } = batchPreflightView(input.operations);
|
|
3928
3981
|
// A relation registered with register_custom_relation this session is a valid relationType, as in add_relation.
|
|
3929
3982
|
const violations = validateBatchVocabulary(ops, { relationType: CUSTOM_RELATION_NAMES });
|
|
3930
3983
|
if (violations.length > 0) {
|
|
3931
3984
|
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) => ({
|
|
3932
|
-
path:
|
|
3985
|
+
path: `${paths[v.opIndex]}.${v.field}`,
|
|
3933
3986
|
opType: v.opType,
|
|
3934
3987
|
vocabulary: v.hint,
|
|
3935
3988
|
})));
|
|
@@ -3941,7 +3994,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
3941
3994
|
const typos = detectBatchPropertyTypos(ops);
|
|
3942
3995
|
if (typos.length > 0) {
|
|
3943
3996
|
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) => ({
|
|
3944
|
-
path:
|
|
3997
|
+
path: `${paths[t.opIndex]}.properties.${t.property}`,
|
|
3945
3998
|
opType: t.opType,
|
|
3946
3999
|
itemType: t.itemType,
|
|
3947
4000
|
received: t.property,
|
|
@@ -3969,7 +4022,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
3969
4022
|
}
|
|
3970
4023
|
const code = codeGenerator.generateAgentBatchExecute(input);
|
|
3971
4024
|
const description = `Batch executed ${input.operations.length} operations${input.atomic !== false ? ' (atomic)' : ''}`
|
|
3972
|
-
+ (expanded.length !== input.operations.length ? ` (${expanded.length} after expanding ring / grid / orbit / stagger)` : '');
|
|
4025
|
+
+ (expanded.length !== input.operations.length ? ` (${expanded.length} after expanding ring / grid / orbit / stagger / create_many)` : '');
|
|
3973
4026
|
// Check for out-of-bounds items before execution
|
|
3974
4027
|
let boundsWarning = '';
|
|
3975
4028
|
const sizeOp = input.operations.find((op) => op.type === 'set_canvas_size');
|
|
@@ -4229,6 +4282,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4229
4282
|
const receipt = await exportFileReceiptOrReason(filePath, exportResult);
|
|
4230
4283
|
const cleanResult = { ...exportResult, data: undefined, filePath, fileSize, chunks, file: receipt };
|
|
4231
4284
|
return withEngineReport({
|
|
4285
|
+
structuredContent: boundedStructured(cleanResult),
|
|
4232
4286
|
content: [{
|
|
4233
4287
|
type: 'text',
|
|
4234
4288
|
text: `Export saved to file:\n\nFile: ${filePath}\nFormat: ${format}\nSize: ${(fileSize / 1024).toFixed(1)} KB\nPlatform: ${input.platform}\nPaged out of the studio's export store in ${chunks} chunk${chunks === 1 ? '' : 's'}\n${receiptErrorLine(receipt)}${'receiptError' in receipt ? '' : probeLines(receipt)}${lintLines(exportResult)}\nResult: ${JSON.stringify(cleanResult, null, 2)}`,
|
|
@@ -4265,7 +4319,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4265
4319
|
const { sccCues: _c, ...rest } = exportResult;
|
|
4266
4320
|
void _c;
|
|
4267
4321
|
const cleanResult = { ...rest, filePath, fileSize, frameRate: '29.97 drop-frame', fidelity: { warnings } };
|
|
4268
|
-
return withEngineReport({ content: [{ type: 'text', text: `Export saved to file:\n\nFile: ${filePath}\nFormat: scc (CEA-608, CC1, pop-on)\nSize: ${fileSize} bytes\n\nResult: ${JSON.stringify(cleanResult, null, 2)}` }, exportFileLink(filePath, fileSize)] }, exportBrowserResult.report);
|
|
4322
|
+
return withEngineReport({ structuredContent: boundedStructured(cleanResult), content: [{ type: 'text', text: `Export saved to file:\n\nFile: ${filePath}\nFormat: scc (CEA-608, CC1, pop-on)\nSize: ${fileSize} bytes\n\nResult: ${JSON.stringify(cleanResult, null, 2)}` }, exportFileLink(filePath, fileSize)] }, exportBrowserResult.report);
|
|
4269
4323
|
}
|
|
4270
4324
|
if ((format === 'html5-ad' || format === 'playable') && typeof exportResult?.adPage === 'string') {
|
|
4271
4325
|
try {
|
|
@@ -4295,6 +4349,7 @@ You can now start creating new items on a clean canvas.${sizeNote}`,
|
|
|
4295
4349
|
// it has to be said out loud here rather than left in the JSON.
|
|
4296
4350
|
const dropNote = exportResult.incomplete;
|
|
4297
4351
|
return withEngineReport({
|
|
4352
|
+
structuredContent: boundedStructured(cleanResult),
|
|
4298
4353
|
content: [{
|
|
4299
4354
|
type: 'text',
|
|
4300
4355
|
text: `Export saved to file:\n\nFile: ${filePath}\nFormat: ${format}\nSize: ${(fileSize / 1024).toFixed(1)} KB\nPlatform: ${input.platform}\n`
|