@pinepaper.studio/mcp-server 1.6.27 → 1.6.29
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 +112 -2
- package/SECURITY.md +6 -6
- package/dist/agent/export-manager.js +125 -125
- package/dist/assets/repositories/fontawesome.d.ts.map +1 -1
- package/dist/assets/repositories/fontawesome.js +2 -1
- package/dist/assets/repositories/fontawesome.js.map +1 -1
- package/dist/assets/repositories/iconify.d.ts.map +1 -1
- package/dist/assets/repositories/iconify.js +4 -3
- package/dist/assets/repositories/iconify.js.map +1 -1
- package/dist/browser/puppeteer-controller.js +38 -23
- package/dist/build-info.json +2 -2
- package/dist/cli.js +54 -54
- package/dist/execution/canvas-state.js +25 -25
- package/dist/i18n/locales/en.js +22 -22
- package/dist/i18n/locales/fil.js +44 -44
- package/dist/i18n/locales/is.js +22 -22
- package/dist/i18n/locales/ur.js +22 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5563 -5560
- package/dist/index.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.js +6 -6
- package/dist/tools/choreograph.d.ts.map +1 -1
- package/dist/tools/choreograph.js +7 -0
- package/dist/tools/choreograph.js.map +1 -1
- package/dist/tools/craft-tools.js +18 -18
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +2830 -2812
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/effect-check.js +68 -68
- package/dist/tools/engine-lists.d.ts +11 -4
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +49 -4
- package/dist/tools/engine-lists.js.map +1 -1
- package/dist/tools/engine-methods.d.ts.map +1 -1
- package/dist/tools/engine-methods.js +2 -1
- package/dist/tools/engine-methods.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 +16 -4
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/export-file-receipt.d.ts +21 -0
- package/dist/tools/export-file-receipt.d.ts.map +1 -1
- package/dist/tools/export-file-receipt.js +36 -13
- package/dist/tools/export-file-receipt.js.map +1 -1
- package/dist/tools/handlers/export.d.ts.map +1 -1
- package/dist/tools/handlers/export.js +6 -2
- package/dist/tools/handlers/export.js.map +1 -1
- package/dist/tools/handlers/font.js +22 -22
- package/dist/tools/handlers/generate.d.ts.map +1 -1
- package/dist/tools/handlers/generate.js +4 -3
- package/dist/tools/handlers/generate.js.map +1 -1
- package/dist/tools/handlers.d.ts +5 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +29 -16
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/lane.d.ts +7 -3
- package/dist/tools/lane.d.ts.map +1 -1
- package/dist/tools/lane.js +82 -67
- package/dist/tools/lane.js.map +1 -1
- package/dist/tools/p5-compat/p5-helpers.js +341 -341
- package/dist/tools/scene-cache-export.d.ts.map +1 -1
- package/dist/tools/scene-cache-export.js +8 -4
- package/dist/tools/scene-cache-export.js.map +1 -1
- package/dist/tools/shape-params.d.ts +2 -2
- package/dist/tools/shape-params.js +2 -2
- package/dist/tools/stick-vocabulary.d.ts +1 -1
- package/dist/tools/stick-vocabulary.js +1 -1
- package/dist/tools/timeline.js +82 -82
- package/dist/tools/toolkits.d.ts +1 -1
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +8 -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 +6682 -5832
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +29 -2
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +9 -23
- package/dist/types/schemas.js.map +1 -1
- package/dist/utils/asset-paths.d.ts.map +1 -1
- package/dist/utils/asset-paths.js +11 -0
- package/dist/utils/asset-paths.js.map +1 -1
- package/dist/utils/capabilities.d.ts +15 -0
- package/dist/utils/capabilities.d.ts.map +1 -0
- package/dist/utils/capabilities.js +63 -0
- package/dist/utils/capabilities.js.map +1 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +2 -1
- package/dist/utils/env.js.map +1 -1
- package/dist/utils/safe-fetch.d.ts +8 -0
- package/dist/utils/safe-fetch.d.ts.map +1 -1
- package/dist/utils/safe-fetch.js +125 -34
- package/dist/utils/safe-fetch.js.map +1 -1
- package/dist/vendor/design/device-mockup-generator.js +167 -150
- package/dist/vendor/design/recursive-subdivision-generator.js +107 -107
- package/dist/vendor/design/textile-weave-generator.js +429 -429
- package/dist/vendor/design/ui-kit-runtime.js +674 -674
- package/manifest.json +18 -2
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -105,6 +105,25 @@ real browser, install Puppeteer **in the same `npx` call**. A separate
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
> **Security switches: off by default.** Two capabilities are a security
|
|
109
|
+
> boundary and stay off until you, the person running the server, turn them on.
|
|
110
|
+
> An agent cannot turn them on from a tool call.
|
|
111
|
+
>
|
|
112
|
+
> | Switch | Turns on |
|
|
113
|
+
> |---|---|
|
|
114
|
+
> | `PINEPAPER_ALLOW_CODE=1` | Running JavaScript the agent writes: `pinepaper_execute_custom_code`, `pinepaper_p5_draw`, `pinepaper_render_hook` (register), `pinepaper_register_custom_relation`, and the custom relations saved in a scene file (`pinepaper_import_scene` `registerCustomRelations`). |
|
|
115
|
+
> | `PINEPAPER_ALLOW_LOCAL_FILES=1` | Importing images, audio, video and scenes from your disk (the working folder and `PINEPAPER_ASSET_DIRS`). URLs and the export folder always work. |
|
|
116
|
+
>
|
|
117
|
+
> With a switch off, those calls are refused with the switch named, and
|
|
118
|
+
> everything else works. Turn one on only if you trust what your agent reads,
|
|
119
|
+
> since a web page or a scene file can steer what it writes. In the Claude
|
|
120
|
+
> Desktop extension they are the "Allow custom code" and "Allow local files"
|
|
121
|
+
> settings. In a config file, add them to the server's `env`:
|
|
122
|
+
>
|
|
123
|
+
> ```json
|
|
124
|
+
> "env": { "PINEPAPER_ALLOW_CODE": "1", "PINEPAPER_ALLOW_LOCAL_FILES": "1" }
|
|
125
|
+
> ```
|
|
126
|
+
|
|
108
127
|
For code-only use (no Chrome, no 320 MB download), use
|
|
109
128
|
`"args": ["-y", "@pinepaper.studio/mcp-server"]` and set
|
|
110
129
|
`"env": { "PINEPAPER_EXECUTION_MODE": "code" }`. A global install works too:
|
|
@@ -235,6 +254,8 @@ The same code an agent generates is the code you can paste — the canvas is you
|
|
|
235
254
|
|
|
236
255
|
**Every tool emits JavaScript — that is the architecture, not an exception.** A tool call is compiled into a snippet written against the PinePaper and Paper.js APIs; the snippet is the product. `pinepaper_execute_custom_code` is simply the case where the *agent* writes the snippet instead of the server generating it, which is what lets a model draw something no other tool has a name for. Removing execution would not harden this package, it would delete it.
|
|
237
256
|
|
|
257
|
+
**Code the agent writes is off unless you turn it on.** The tools that run JavaScript the agent wrote (`pinepaper_execute_custom_code`, `pinepaper_p5_draw`, `pinepaper_render_hook` register, `pinepaper_register_custom_relation`, and `pinepaper_import_scene`'s `registerCustomRelations`) refuse, naming the switch, unless the server is started with `PINEPAPER_ALLOW_CODE=1`. Reading files from your disk for an import (images, audio, video, scenes) needs `PINEPAPER_ALLOW_LOCAL_FILES=1`; files in the export folder, the server's own results, are always readable. In the Claude Desktop extension both are settings, off by default. An agent takes instructions from whatever it reads, a web page or a scene file included, so whether that text may become code is the decision of whoever starts the server.
|
|
258
|
+
|
|
238
259
|
**Where the code runs.** In a browser page on your own machine, against your own canvas. It does not run in the server process, and nothing is sent anywhere else to be executed.
|
|
239
260
|
|
|
240
261
|
**Two modes, and one of them never executes anything:**
|
|
@@ -255,8 +276,97 @@ If you do not want an agent executing anything, `code` mode is a first-class pat
|
|
|
255
276
|
- Code an agent writes runs with whatever that browser page has. Give this server the same trust you would give anything else you let write and run code on your machine — which is the trust you already extend to an MCP client with tool access.
|
|
256
277
|
- Puppeteer mode launches Chrome with `--no-sandbox` and `--disable-setuid-sandbox`. That is routine for headless automation and it does weaken Chrome's own process sandbox. If that matters where you are running it, use `code` mode or put the server in a container.
|
|
257
278
|
- Puppeteer itself is not a dependency at all (it was an optional peer until 1.6.25), kept out of the tree precisely because a headless browser plus an install script is what scanners flag hardest. Install it only if you want the executing mode. The server loads it only from where its own dependencies would be found (the same `npx` call, a global install, a project install) or from a folder you name in `PINEPAPER_PUPPETEER_FROM`; never from the folder it happens to be started in. puppeteer 22 or newer is required.
|
|
258
|
-
- The package
|
|
259
|
-
- The server itself fetches the images, SVGs and media a tool call names by URL, and reads local files named by path. URLs that resolve to loopback, private, link-local or reserved addresses are refused, redirects included, and so are cloud metadata addresses. Local files are read only from the working directory, the export folder, and folders listed in `PINEPAPER_ASSET_DIRS
|
|
279
|
+
- The npm package starts no process. Two export features use `ffprobe` and `ffmpeg`: checking a saved video against what the studio encoded, and joining the cached segments of a `perScene` export (`ffmpeg -f concat`). Only the Claude Desktop extension runs them, through a small runner it bundles that allows those two binaries alone, via `execFile` (no shell, argument lists the server writes, absolute paths). From npm, the check is skipped and said so, and a `perScene` export runs whole.
|
|
280
|
+
- The server itself fetches the images, SVGs and media a tool call names by URL, and reads local files named by path. URLs that resolve to loopback, private, link-local or reserved addresses are refused, redirects included, and so are cloud metadata addresses. Local files are read only with `PINEPAPER_ALLOW_LOCAL_FILES=1`, and then only from the working directory, the export folder, and folders listed in `PINEPAPER_ASSET_DIRS` (the export folder is readable without the switch). `PINEPAPER_ALLOW_PRIVATE_NETWORK=1` allows local and LAN hosts. Metadata addresses stay refused even with it set.
|
|
281
|
+
|
|
282
|
+
## What's new in 1.6.29
|
|
283
|
+
|
|
284
|
+
### Changed
|
|
285
|
+
|
|
286
|
+
- The package installs one dependency, `zod`. The guarded fetch that protects
|
|
287
|
+
URL imports from reaching private and loopback addresses now runs on Node's
|
|
288
|
+
own `http` / `https`, with every connection still pinned to the addresses
|
|
289
|
+
that passed the check. `undici` is no longer installed.
|
|
290
|
+
- Every request the server makes, including icon search and the hosted
|
|
291
|
+
generation API, goes through that one guarded module.
|
|
292
|
+
- `package.json` names the issue tracker and homepage.
|
|
293
|
+
|
|
294
|
+
### Fixed
|
|
295
|
+
|
|
296
|
+
- `scale`, `scaleX` and `scaleY` on `pinepaper_create_item` are applied (a
|
|
297
|
+
squashed circle stays squashed). Before, the studio ignored them at create.
|
|
298
|
+
- `pinepaper_morph_sequence` takes `hideTarget` (per state or for the whole
|
|
299
|
+
call): `false` keeps the reference item visible.
|
|
300
|
+
- `pinepaper_design_medium` ink with `keepColor` and no `color` draws its marks
|
|
301
|
+
in the item's own colour, not the brush default.
|
|
302
|
+
- Keyframes on `skewX`, `skewY` or `shear`, which the studio does not animate,
|
|
303
|
+
are named in `ignoredProperties`. A sheared motion is a `transform` track.
|
|
304
|
+
- New warnings where the result used to look right but wasn't: `x` keyed
|
|
305
|
+
beside `fontSize` on one text item (it drifts in export), a `bloom` image
|
|
306
|
+
filter (its halo stops at the image edge), and removing a look (geometry is
|
|
307
|
+
not restored).
|
|
308
|
+
|
|
309
|
+
## What's new in 1.6.28
|
|
310
|
+
|
|
311
|
+
### Changed
|
|
312
|
+
|
|
313
|
+
- **Security boundary: code the agent writes and local file imports are off
|
|
314
|
+
by default, and only you can turn them on** (see Quick start).
|
|
315
|
+
`pinepaper_execute_custom_code`, `pinepaper_p5_draw`, `pinepaper_render_hook`
|
|
316
|
+
(register), `pinepaper_register_custom_relation` and `pinepaper_import_scene`'s
|
|
317
|
+
`registerCustomRelations` need a server started with `PINEPAPER_ALLOW_CODE=1`;
|
|
318
|
+
importing an image, audio, video or scene from your disk needs
|
|
319
|
+
`PINEPAPER_ALLOW_LOCAL_FILES=1`. Without the switch the call is refused and
|
|
320
|
+
names it. Files in the export folder stay readable, so saving and restoring a
|
|
321
|
+
scene works as before. URL imports are unchanged. In the Claude Desktop
|
|
322
|
+
extension both are settings ("Allow custom code", "Allow local files").
|
|
323
|
+
- **The npm package starts no process.** `ffprobe` (checking a saved video)
|
|
324
|
+
and `ffmpeg` (joining a `perScene` export) now run only in the Claude
|
|
325
|
+
Desktop extension, which bundles them. From npm, a `perScene` export runs as
|
|
326
|
+
one whole export and says why.
|
|
327
|
+
|
|
328
|
+
### Added
|
|
329
|
+
|
|
330
|
+
- `pinepaper_lint_scene` says how to change what it lists: an `edit` section
|
|
331
|
+
with, for every relation, the batch op that changes it; for a group bound by
|
|
332
|
+
a name pattern (`"dot-*"`), one entry with the op that changes the group and
|
|
333
|
+
the ops that add or remove a member; and for a custom motion, the call that
|
|
334
|
+
redefines it. An editing agent can work from that alone.
|
|
335
|
+
- An `edit` toolkit (`PINEPAPER_TOOLKIT=edit`, or `pinepaper_set_toolkit`):
|
|
336
|
+
`pinepaper_lint_scene`, `pinepaper_agent_batch_execute`,
|
|
337
|
+
`pinepaper_register_custom_relation` and `pinepaper_agent_export`, with the
|
|
338
|
+
lane's short descriptions, for changing a scene that already exists.
|
|
339
|
+
- `pinepaper_animate` has the `ripple` and `undulate` field motions: a wave
|
|
340
|
+
that sweeps through a group's children from an `origin` (centre, a side or a
|
|
341
|
+
corner), with a `waveform` (sine, triangle, square, sawtooth, spike, pulse).
|
|
342
|
+
The list of loop animations now comes from the studio itself, so a new one
|
|
343
|
+
can be named the day it ships.
|
|
344
|
+
|
|
345
|
+
### Fixed
|
|
346
|
+
|
|
347
|
+
- A `moves_along_path` equation is read with y up, so on screen it is mirrored
|
|
348
|
+
against a curve written in screen coordinates. The result now says so and
|
|
349
|
+
points to `flipY: false`, and the docs say the item moves at constant speed
|
|
350
|
+
along the route.
|
|
351
|
+
- Keyframes on `wordSpacing`, `textDecoration` or `textTransform`, which the
|
|
352
|
+
studio does not animate, are named in `ignoredProperties` with a warning
|
|
353
|
+
instead of being accepted silently.
|
|
354
|
+
- `pinepaper_choreograph` says when a beat other than `shake` is given
|
|
355
|
+
`intensity` (only `shake` reads it), and names the beat's own size option.
|
|
356
|
+
- `pinepaper_pattern modify` with only new `params` works on a pattern whose
|
|
357
|
+
members were given as a plain list. Before, it was refused.
|
|
358
|
+
- The `deterministic` export option is described as it behaves: WebM files
|
|
359
|
+
come out byte-identical, but an MP4 can differ in its encoded bytes, so
|
|
360
|
+
compare MP4s by the receipt's `frameDigest`.
|
|
361
|
+
- The docs say a discrete change (a colour switching at a key) needs a `hold`
|
|
362
|
+
or `step` key, that font weight steps rather than ramps, that `phase_wave`
|
|
363
|
+
patterns on one item add up, and that two `ring` or `orbit` patterns on one
|
|
364
|
+
item conflict. Emitter `gravity`, `drag`, `friction`, `opacity`, `sizeEnd`
|
|
365
|
+
and `jitter` are documented as taking a `[min, max]` range.
|
|
366
|
+
- A batch `modify` with a top-level `position` (`{x, y}` or `[x, y]`) moves
|
|
367
|
+
the item, as `position` places one on `create`. Before, it reported
|
|
368
|
+
`modified: true` and the item stayed where it was. A `modify` with nothing
|
|
369
|
+
to change is refused by name.
|
|
260
370
|
|
|
261
371
|
## What's new in 1.6.27
|
|
262
372
|
|
package/SECURITY.md
CHANGED
|
@@ -42,19 +42,19 @@ Examples of what is in scope:
|
|
|
42
42
|
- tool input that escapes the generated snippet and runs in the server process instead of the page;
|
|
43
43
|
- exposing a credential such as `PINEPAPER_API_KEY`, or sending it somewhere it should not go;
|
|
44
44
|
- a crash or hang of the server caused by a single crafted tool call;
|
|
45
|
-
- the server loading `puppeteer` (or any module) from somewhere other than where its own dependencies resolve or `PINEPAPER_PUPPETEER_FROM`, or
|
|
45
|
+
- the server loading `puppeteer` (or any module) from somewhere other than where its own dependencies resolve or `PINEPAPER_PUPPETEER_FROM`, or starting a child process (the npm package starts none; the Desktop extension's bundled runner starts only the `ffprobe` read-back and the `ffmpeg` join described below);
|
|
46
|
+
- running caller-written JavaScript, or reading a local file outside the export folder, on a server started without `PINEPAPER_ALLOW_CODE=1` / `PINEPAPER_ALLOW_LOCAL_FILES=1`.
|
|
46
47
|
|
|
47
|
-
The server's own defences, `PINEPAPER_ALLOW_PRIVATE_NETWORK` and `PINEPAPER_ASSET_DIRS`, are documented in the README. Bypassing
|
|
48
|
+
The server's own defences, `PINEPAPER_ALLOW_CODE`, `PINEPAPER_ALLOW_LOCAL_FILES`, `PINEPAPER_ALLOW_PRIVATE_NETWORK` and `PINEPAPER_ASSET_DIRS`, are documented in the README. Bypassing any of them is in scope.
|
|
48
49
|
|
|
49
50
|
## Dependencies
|
|
50
51
|
|
|
51
|
-
The package installs
|
|
52
|
+
The package installs one runtime dependency, `zod`, for tool input schemas, and nothing else.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
- `undici`, used only by the guarded fetch (`src/utils/safe-fetch.ts`) to pin each connection to the addresses that passed the private-network check, which closes DNS rebinding. Node's built-in `fetch` cannot be given that pinned resolver, so undici stays.
|
|
54
|
+
Every outbound request goes through one file, `src/utils/safe-fetch.ts`, on Node's built-in `http` / `https`. A URL a tool call names is checked against private, loopback, link-local, reserved and cloud-metadata addresses, every redirect included, and the connection is pinned to the addresses that passed (a `lookup` that returns only those), which closes DNS rebinding. Requests to the server's own configured services (the hosted API, the icon libraries) go through the same file. Up to 1.6.28 the pinning used `undici`; Node's own `http` takes the same pinned `lookup`, so it was removed.
|
|
55
55
|
|
|
56
56
|
**Puppeteer is not a dependency**, not even an optional peer (it was one up to 1.6.25). It brings a browser download with an install script, shell access and a large network tree, and the browser tools are a minority of what the server does. Install it yourself to use them (`npm i puppeteer`, or `-p puppeteer` in the `npx` call; see the README). The server imports it by name only from where its own dependencies resolve, or from an absolute folder you set in `PINEPAPER_PUPPETEER_FROM`; never from its working directory, which can be an untrusted checkout. puppeteer 22 or newer is required and an older one is refused.
|
|
57
57
|
|
|
58
|
-
**
|
|
58
|
+
**No child process in the npm package.** `ffprobe` and `ffmpeg` run through `packages/mcp-ffmpeg`, which is never published (`private`) and is copied only into the Claude Desktop extension's bundle. The server loads it by name when it is there. It runs those two binaries and nothing else, through `execFile` (no shell), with argument lists `src/tools/export-file-receipt.ts` writes and absolute file paths. Without it (any npm install) both features are unavailable and the server says so.
|
|
59
59
|
|
|
60
60
|
The source contains no `eval` or `new Function`.
|
|
@@ -34,113 +34,113 @@ export class SmartExportManager {
|
|
|
34
34
|
* Generate code to analyze canvas content
|
|
35
35
|
*/
|
|
36
36
|
generateAnalysisCode() {
|
|
37
|
-
return
|
|
38
|
-
(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
colorComplexity: 'simple',
|
|
43
|
-
itemCount: 0,
|
|
44
|
-
canvasSize: { width: 0, height: 0 },
|
|
45
|
-
hasRelations: false,
|
|
46
|
-
relationTypes: [],
|
|
47
|
-
hasGradients: false,
|
|
48
|
-
hasShadows: false,
|
|
49
|
-
hasText: false,
|
|
50
|
-
hasImages: false,
|
|
51
|
-
};
|
|
37
|
+
return ("\n(function() {\n const analysis = {\n hasAnimations: false,\n animationTypes: [],\n colorComplexity: 'simple',\n itemCount: 0,\n canvasSize: { width: 0, height: 0 },\n hasRelations: false,\n relationTypes: [],\n hasGradients: false,\n hasShadows: false,\n hasText: false,\n hasImages: false,\n };\n\n // Get canvas size\n if (app.canvasEl) {\n analysis.canvasSize = {\n width: app.canvasEl.width,\n height: app.canvasEl.height\n };\n } else if (paper.view) {\n analysis.canvasSize = {\n width: paper.view.size.width,\n height: paper.view.size.height\n };\n }\n\n // Count items and analyze types\n const items = app.itemRegi" +
|
|
38
|
+
"stry ? app.itemRegistry.getAll() : [];\n analysis.itemCount = items.length;\n\n const animationSet = new Set();\n const relationSet = new Set();\n let hasGradient = false;\n let hasShadow = false;\n\n items.forEach(entry => {\n const item = entry.item;\n const data = item.data || {};\n\n // Check for text\n if (entry.type === 'text' || item.className === 'PointText') {\n analysis.hasText = true;\n }\n\n // Check for images (raster items)\n if (item.className === 'Raster') {\n analysis.hasImages = true;\n }\n\n // Check for animations ('none' is a still item, gate C5)\n if (data.animationType && data.animationType !== 'none') {\n analysis.h" +
|
|
39
|
+
"asAnimations = true;\n animationSet.add(data.animationType);\n }\n\n // Check for gradients\n if (item.fillColor && item.fillColor.gradient) {\n hasGradient = true;\n }\n if (item.strokeColor && item.strokeColor.gradient) {\n hasGradient = true;\n }\n\n // Check for shadows\n if (item.shadowColor || item.shadowBlur) {\n hasShadow = true;\n }\n });\n\n analysis.animationTypes = Array.from(animationSet);\n analysis.hasGradients = hasGradient;\n analysis.hasShadows = hasShadow;\n\n // Check for relations\n if (app.relationRegistry) {\n // getAll() has never existed on the registry, so this always took the\n // empty fallback and every" +
|
|
40
|
+
" analysis reported NO relations. getStats() is\n // the real accessor and answers both questions: associationsByType is\n // keyed by relation type, and activeItems counts the items carrying one.\n const relStats = typeof app.relationRegistry.getStats === 'function'\n ? app.relationRegistry.getStats()\n : null;\n Object.keys((relStats && relStats.associationsByType) || {}).forEach(t => relationSet.add(t));\n analysis.relationTypes = Array.from(relationSet);\n analysis.hasRelations = !!relStats && (relStats.activeItems > 0 || analysis.relationTypes.length > 0);\n\n // Relations imply animations\n if (analysis.hasRelations) {\n analysis.hasAnimations = " +
|
|
41
|
+
"true;\n }\n }\n\n // Determine color complexity\n if (hasGradient) {\n analysis.colorComplexity = 'gradient';\n } else if (analysis.itemCount > 20 || hasShadow) {\n analysis.colorComplexity = 'complex';\n } else {\n analysis.colorComplexity = 'simple';\n }\n\n return analysis;\n})();\n "
|
|
52
42
|
|
|
53
|
-
// Get canvas size
|
|
54
|
-
if (app.canvasEl) {
|
|
55
|
-
analysis.canvasSize = {
|
|
56
|
-
width: app.canvasEl.width,
|
|
57
|
-
height: app.canvasEl.height
|
|
58
|
-
};
|
|
59
|
-
} else if (paper.view) {
|
|
60
|
-
analysis.canvasSize = {
|
|
61
|
-
width: paper.view.size.width,
|
|
62
|
-
height: paper.view.size.height
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
43
|
|
|
66
|
-
// Count items and analyze types
|
|
67
|
-
const items = app.itemRegistry ? app.itemRegistry.getAll() : [];
|
|
68
|
-
analysis.itemCount = items.length;
|
|
69
44
|
|
|
70
|
-
const animationSet = new Set();
|
|
71
|
-
const relationSet = new Set();
|
|
72
|
-
let hasGradient = false;
|
|
73
|
-
let hasShadow = false;
|
|
74
45
|
|
|
75
|
-
items.forEach(entry => {
|
|
76
|
-
const item = entry.item;
|
|
77
|
-
const data = item.data || {};
|
|
78
46
|
|
|
79
|
-
// Check for text
|
|
80
|
-
if (entry.type === 'text' || item.className === 'PointText') {
|
|
81
|
-
analysis.hasText = true;
|
|
82
|
-
}
|
|
83
47
|
|
|
84
|
-
// Check for images (raster items)
|
|
85
|
-
if (item.className === 'Raster') {
|
|
86
|
-
analysis.hasImages = true;
|
|
87
|
-
}
|
|
88
48
|
|
|
89
|
-
// Check for animations ('none' is a still item, gate C5)
|
|
90
|
-
if (data.animationType && data.animationType !== 'none') {
|
|
91
|
-
analysis.hasAnimations = true;
|
|
92
|
-
animationSet.add(data.animationType);
|
|
93
|
-
}
|
|
94
49
|
|
|
95
|
-
// Check for gradients
|
|
96
|
-
if (item.fillColor && item.fillColor.gradient) {
|
|
97
|
-
hasGradient = true;
|
|
98
|
-
}
|
|
99
|
-
if (item.strokeColor && item.strokeColor.gradient) {
|
|
100
|
-
hasGradient = true;
|
|
101
|
-
}
|
|
102
50
|
|
|
103
|
-
// Check for shadows
|
|
104
|
-
if (item.shadowColor || item.shadowBlur) {
|
|
105
|
-
hasShadow = true;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
51
|
|
|
109
|
-
analysis.animationTypes = Array.from(animationSet);
|
|
110
|
-
analysis.hasGradients = hasGradient;
|
|
111
|
-
analysis.hasShadows = hasShadow;
|
|
112
|
-
|
|
113
|
-
// Check for relations
|
|
114
|
-
if (app.relationRegistry) {
|
|
115
|
-
// getAll() has never existed on the registry, so this always took the
|
|
116
|
-
// empty fallback and every analysis reported NO relations. getStats() is
|
|
117
|
-
// the real accessor and answers both questions: associationsByType is
|
|
118
|
-
// keyed by relation type, and activeItems counts the items carrying one.
|
|
119
|
-
const relStats = typeof app.relationRegistry.getStats === 'function'
|
|
120
|
-
? app.relationRegistry.getStats()
|
|
121
|
-
: null;
|
|
122
|
-
Object.keys((relStats && relStats.associationsByType) || {}).forEach(t => relationSet.add(t));
|
|
123
|
-
analysis.relationTypes = Array.from(relationSet);
|
|
124
|
-
analysis.hasRelations = !!relStats && (relStats.activeItems > 0 || analysis.relationTypes.length > 0);
|
|
125
|
-
|
|
126
|
-
// Relations imply animations
|
|
127
|
-
if (analysis.hasRelations) {
|
|
128
|
-
analysis.hasAnimations = true;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
52
|
|
|
132
|
-
// Determine color complexity
|
|
133
|
-
if (hasGradient) {
|
|
134
|
-
analysis.colorComplexity = 'gradient';
|
|
135
|
-
} else if (analysis.itemCount > 20 || hasShadow) {
|
|
136
|
-
analysis.colorComplexity = 'complex';
|
|
137
|
-
} else {
|
|
138
|
-
analysis.colorComplexity = 'simple';
|
|
139
|
-
}
|
|
140
53
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
).trim();
|
|
144
144
|
}
|
|
145
145
|
/**
|
|
146
146
|
* Recommend export format based on content analysis
|
|
@@ -372,39 +372,39 @@ export class SmartExportManager {
|
|
|
372
372
|
*/
|
|
373
373
|
generateVideoExportCode(format, fps, _dimensions) {
|
|
374
374
|
const mimeType = format === 'mp4' ? 'video/mp4' : 'video/webm';
|
|
375
|
-
return
|
|
376
|
-
(
|
|
377
|
-
if (
|
|
378
|
-
|
|
379
|
-
|
|
375
|
+
return ("\n(async function() {\n if (!app.exportEngine) {\n return { success: false, error: '" +
|
|
376
|
+
String(format.toUpperCase()) +
|
|
377
|
+
" export not available' };\n }\n\n let blob;\n if (app.exportEngine._quickExportVideo) {\n const result = await app.exportEngine._quickExportVideo('" +
|
|
378
|
+
String(format) +
|
|
379
|
+
"', { fps: " +
|
|
380
|
+
String(fps) +
|
|
381
|
+
", duration: 5 }, false);\n blob = result && result.blob ? result.blob : null;\n } else if (app.exportEngine.videoExporter) {\n blob = await app.exportEngine.videoExporter.export({ format: '" +
|
|
382
|
+
String(format) +
|
|
383
|
+
"', fps: " +
|
|
384
|
+
String(fps) +
|
|
385
|
+
", duration: 5 });\n }\n\n if (!blob) {\n return { success: false, error: '" +
|
|
386
|
+
String(format.toUpperCase()) +
|
|
387
|
+
" export returned no data' };\n }\n\n return new Promise((resolve) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve({\n success: true,\n format: '" +
|
|
388
|
+
String(format) +
|
|
389
|
+
"',\n data: reader.result,\n mimeType: '" +
|
|
390
|
+
String(mimeType) +
|
|
391
|
+
"',\n size: blob.size\n });\n };\n reader.readAsDataURL(blob);\n });\n})();\n "
|
|
380
392
|
|
|
381
|
-
let blob;
|
|
382
|
-
if (app.exportEngine._quickExportVideo) {
|
|
383
|
-
const result = await app.exportEngine._quickExportVideo('${format}', { fps: ${fps}, duration: 5 }, false);
|
|
384
|
-
blob = result && result.blob ? result.blob : null;
|
|
385
|
-
} else if (app.exportEngine.videoExporter) {
|
|
386
|
-
blob = await app.exportEngine.videoExporter.export({ format: '${format}', fps: ${fps}, duration: 5 });
|
|
387
|
-
}
|
|
388
393
|
|
|
389
|
-
if (!blob) {
|
|
390
|
-
return { success: false, error: '${format.toUpperCase()} export returned no data' };
|
|
391
|
-
}
|
|
392
394
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
})();
|
|
407
|
-
`.trim();
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
).trim();
|
|
408
408
|
}
|
|
409
409
|
/**
|
|
410
410
|
* Generate PDF export code
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontawesome.d.ts","sourceRoot":"","sources":["../../../src/assets/repositories/fontawesome.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"fontawesome.d.ts","sourceRoot":"","sources":["../../../src/assets/repositories/fontawesome.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAsB1E;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACxD,IAAI,SAAiB;IAErB,OAAO,CAAC,OAAO,CAAoE;IAEnF;;;OAGG;IACH,OAAO,CAAC,YAAY,CAgClB;IAEF;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA6BlE;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmChD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAe3D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,eAAe,CAE1D"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Fetches free SVG icons from Font Awesome
|
|
5
5
|
* Repository info: 2,000+ free icons (CC BY 4.0 license)
|
|
6
6
|
*/
|
|
7
|
+
import { trustedFetch } from '../../utils/safe-fetch.js';
|
|
7
8
|
/**
|
|
8
9
|
* Font Awesome adapter
|
|
9
10
|
*
|
|
@@ -115,7 +116,7 @@ export class FontAwesomeAdapter {
|
|
|
115
116
|
}
|
|
116
117
|
const [, style, iconName] = match;
|
|
117
118
|
const svgUrl = `${this.cdnBase}/${style}/${iconName}.svg`;
|
|
118
|
-
const response = await
|
|
119
|
+
const response = await trustedFetch(svgUrl, {
|
|
119
120
|
headers: {
|
|
120
121
|
'User-Agent': 'PinePaper-MCP-Server/1.2.2',
|
|
121
122
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fontawesome.js","sourceRoot":"","sources":["../../../src/assets/repositories/fontawesome.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"fontawesome.js","sourceRoot":"","sources":["../../../src/assets/repositories/fontawesome.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconify.d.ts","sourceRoot":"","sources":["../../../src/assets/repositories/iconify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"iconify.d.ts","sourceRoot":"","sources":["../../../src/assets/repositories/iconify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAoCxF,qBAAa,cAAe,YAAW,eAAe;IACpD,IAAI,SAAa;IAEjB,OAAO,CAAC,MAAM,CAAgC;IAE9C;;;;;OAKG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAoDlE;;;;OAIG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkChD;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA6C1D;;OAEG;IACH,OAAO,CAAC,YAAY;CAqErB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,eAAe,CAEtD"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Fetches SVG icons from iconify.design
|
|
5
5
|
* Repository info: 200,000+ icons from various icon sets with different licenses
|
|
6
6
|
*/
|
|
7
|
+
import { trustedFetch } from '../../utils/safe-fetch.js';
|
|
7
8
|
/**
|
|
8
9
|
* Iconify adapter
|
|
9
10
|
*
|
|
@@ -28,7 +29,7 @@ export class IconifyAdapter {
|
|
|
28
29
|
try {
|
|
29
30
|
// Iconify search endpoint
|
|
30
31
|
const searchUrl = `${this.apiUrl}/search?query=${encodeURIComponent(query)}&limit=${limit}`;
|
|
31
|
-
const response = await
|
|
32
|
+
const response = await trustedFetch(searchUrl, {
|
|
32
33
|
headers: {
|
|
33
34
|
'User-Agent': 'PinePaper-MCP-Server/1.2.2',
|
|
34
35
|
},
|
|
@@ -80,7 +81,7 @@ export class IconifyAdapter {
|
|
|
80
81
|
.replace('_', ':'); // Replace first underscore with colon
|
|
81
82
|
// Download SVG from Iconify API
|
|
82
83
|
const svgUrl = `${this.apiUrl}/${iconName}.svg`;
|
|
83
|
-
const response = await
|
|
84
|
+
const response = await trustedFetch(svgUrl, {
|
|
84
85
|
headers: {
|
|
85
86
|
'User-Agent': 'PinePaper-MCP-Server/1.2.2',
|
|
86
87
|
},
|
|
@@ -111,7 +112,7 @@ export class IconifyAdapter {
|
|
|
111
112
|
const [collection] = iconName.split(':');
|
|
112
113
|
// Fetch collection info
|
|
113
114
|
const collectionUrl = `${this.apiUrl}/collection?prefix=${collection}`;
|
|
114
|
-
const response = await
|
|
115
|
+
const response = await trustedFetch(collectionUrl, {
|
|
115
116
|
headers: {
|
|
116
117
|
'User-Agent': 'PinePaper-MCP-Server/1.2.2',
|
|
117
118
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iconify.js","sourceRoot":"","sources":["../../../src/assets/repositories/iconify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"iconify.js","sourceRoot":"","sources":["../../../src/assets/repositories/iconify.ts"],"names":[],"mappings":"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"}
|
|
@@ -1223,13 +1223,8 @@ export class PinePaperBrowserController {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
const atomic = options.atomic ?? true;
|
|
1225
1225
|
// Wrap all codes in a single IIFE for batch execution
|
|
1226
|
-
const batchCode =
|
|
1227
|
-
(
|
|
1228
|
-
const _results = [];
|
|
1229
|
-
const _itemIds = [];
|
|
1230
|
-
|
|
1231
|
-
try {
|
|
1232
|
-
${codes.map((code, i) => `
|
|
1226
|
+
const batchCode = ("\n(async function() {\n const _results = [];\n const _itemIds = [];\n\n try {\n" +
|
|
1227
|
+
String(codes.map((code, i) => `
|
|
1233
1228
|
// === Operation ${i + 1} ===
|
|
1234
1229
|
try {
|
|
1235
1230
|
const _result${i} = await (async () => {
|
|
@@ -1244,24 +1239,44 @@ ${codes.map((code, i) => `
|
|
|
1244
1239
|
_results.push({ index: ${i}, success: false, step: 'operation ${i}', itemId: null, reason: (e && typeof e.message === 'string' && e.message) || 'operation ${i} threw with no message', error: (e && typeof e.message === 'string' && e.message) || 'operation ${i} threw with no message' });
|
|
1245
1240
|
${atomic ? 'throw e; // Atomic mode: stop on first error' : '// Continue despite error'}
|
|
1246
1241
|
}
|
|
1247
|
-
`).join('\n')
|
|
1242
|
+
`).join('\n')) +
|
|
1243
|
+
"\n\n // Save history once for all operations\n if (app.historyManager) {\n app.historyManager.saveState();\n }\n\n return { success: true, itemIds: _itemIds, results: _results };\n } catch (e) {\n return {\n success: false,\n error: (e && typeof e.message === 'string' && e.message) || 'the batch threw with no message',\n itemIds: _itemIds,\n results: _results\n };\n }\n})();\n "
|
|
1248
1244
|
|
|
1249
|
-
// Save history once for all operations
|
|
1250
|
-
if (app.historyManager) {
|
|
1251
|
-
app.historyManager.saveState();
|
|
1252
|
-
}
|
|
1253
1245
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
).trim();
|
|
1265
1280
|
try {
|
|
1266
1281
|
// A string is run as a CDP Runtime.evaluate: the script's value, awaited, by value (no eval in this package).
|
|
1267
1282
|
const result = await this.page.evaluate(batchCode).catch((e) => ({
|