@pinepaper.studio/mcp-server 1.6.24 → 1.6.25
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 +130 -14
- package/dist/browser/puppeteer-controller.d.ts +6 -0
- package/dist/browser/puppeteer-controller.d.ts.map +1 -1
- package/dist/browser/puppeteer-controller.js +97 -69
- package/dist/browser/puppeteer-controller.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/cli.js +7 -5
- package/dist/cli.js.map +1 -1
- package/dist/design/design-systems.js +2 -2
- package/dist/design/design-systems.js.map +1 -1
- package/dist/i18n/locales/en.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -11
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +5 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +86 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +159 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/stdio.d.ts +20 -0
- package/dist/mcp/stdio.d.ts.map +1 -0
- package/dist/mcp/stdio.js +82 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/mcp/types.d.ts +598 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +140 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/metrics/performance-tracker.d.ts.map +1 -1
- package/dist/metrics/performance-tracker.js +4 -3
- package/dist/metrics/performance-tracker.js.map +1 -1
- package/dist/ontology/hints.d.ts.map +1 -1
- package/dist/ontology/hints.js +3 -1
- package/dist/ontology/hints.js.map +1 -1
- package/dist/ontology/upstream-vocabulary.d.ts +2 -2
- package/dist/ontology/upstream-vocabulary.d.ts.map +1 -1
- package/dist/ontology/upstream-vocabulary.js +8 -2
- package/dist/ontology/upstream-vocabulary.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/tools/batch-macros.d.ts.map +1 -1
- package/dist/tools/batch-macros.js +2 -1
- package/dist/tools/batch-macros.js.map +1 -1
- package/dist/tools/compact-descriptions.d.ts.map +1 -1
- package/dist/tools/compact-descriptions.js +7 -6
- package/dist/tools/compact-descriptions.js.map +1 -1
- package/dist/tools/craft-tools.d.ts +1 -1
- package/dist/tools/craft-tools.d.ts.map +1 -1
- package/dist/tools/create-known-keys.d.ts +2 -0
- package/dist/tools/create-known-keys.d.ts.map +1 -0
- package/dist/tools/create-known-keys.js +24 -0
- package/dist/tools/create-known-keys.js.map +1 -0
- package/dist/tools/definitions.d.ts +3 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +43 -22
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/effect-check.d.ts +1 -1
- package/dist/tools/effect-check.d.ts.map +1 -1
- package/dist/tools/effect-check.js +4 -0
- package/dist/tools/effect-check.js.map +1 -1
- package/dist/tools/engine-lists.d.ts +4 -1
- package/dist/tools/engine-lists.d.ts.map +1 -1
- package/dist/tools/engine-lists.js +9 -1
- 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 +1 -0
- 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 +18 -3
- package/dist/tools/engine-surface.js.map +1 -1
- package/dist/tools/export-file-receipt.d.ts +12 -0
- package/dist/tools/export-file-receipt.d.ts.map +1 -1
- package/dist/tools/export-file-receipt.js +21 -1
- package/dist/tools/export-file-receipt.js.map +1 -1
- package/dist/tools/handlers/beats.d.ts +1 -1
- package/dist/tools/handlers/beats.d.ts.map +1 -1
- package/dist/tools/handlers/camera.d.ts +1 -1
- package/dist/tools/handlers/camera.d.ts.map +1 -1
- package/dist/tools/handlers/export.d.ts +1 -1
- package/dist/tools/handlers/export.d.ts.map +1 -1
- package/dist/tools/handlers/export.js +3 -2
- package/dist/tools/handlers/export.js.map +1 -1
- package/dist/tools/handlers/font.d.ts +1 -1
- package/dist/tools/handlers/font.d.ts.map +1 -1
- package/dist/tools/handlers/font.js +8 -7
- package/dist/tools/handlers/font.js.map +1 -1
- package/dist/tools/handlers/generate.d.ts +1 -1
- 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/maps.d.ts +1 -1
- package/dist/tools/handlers/maps.d.ts.map +1 -1
- package/dist/tools/handlers/ontology.d.ts +1 -1
- package/dist/tools/handlers/ontology.d.ts.map +1 -1
- package/dist/tools/handlers/tool-guide.d.ts +1 -1
- package/dist/tools/handlers/tool-guide.d.ts.map +1 -1
- package/dist/tools/handlers.d.ts +15 -3
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +71 -31
- package/dist/tools/handlers.js.map +1 -1
- package/dist/tools/lane.d.ts +11 -6
- package/dist/tools/lane.d.ts.map +1 -1
- package/dist/tools/lane.js +46 -9
- 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/p5-compat/p5-helpers.d.ts +1 -1
- package/dist/tools/p5-compat/p5-helpers.js +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 +8 -2
- package/dist/tools/shape-params.js.map +1 -1
- package/dist/tools/stick-vocabulary.d.ts +2 -2
- package/dist/tools/stick-vocabulary.js +2 -2
- package/dist/tools/timeline.d.ts +2 -2
- package/dist/tools/timeline.d.ts.map +1 -1
- package/dist/tools/timeline.js +6 -1
- package/dist/tools/timeline.js.map +1 -1
- package/dist/tools/toolkits.d.ts +22 -7
- package/dist/tools/toolkits.d.ts.map +1 -1
- package/dist/tools/toolkits.js +102 -20
- package/dist/tools/toolkits.js.map +1 -1
- package/dist/types/code-generator.d.ts +25 -0
- package/dist/types/code-generator.d.ts.map +1 -1
- package/dist/types/code-generator.js +402 -157
- package/dist/types/code-generator.js.map +1 -1
- package/dist/types/schemas.d.ts +52 -47
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/schemas.js +7 -5
- package/dist/types/schemas.js.map +1 -1
- package/dist/utils/asset-paths.d.ts.map +1 -1
- package/dist/utils/asset-paths.js +4 -4
- package/dist/utils/asset-paths.js.map +1 -1
- package/dist/utils/env.d.ts +9 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +11 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/export-dir.d.ts +36 -0
- package/dist/utils/export-dir.d.ts.map +1 -0
- package/dist/utils/export-dir.js +86 -0
- package/dist/utils/export-dir.js.map +1 -0
- package/dist/utils/js-literal.d.ts +4 -0
- package/dist/utils/js-literal.d.ts.map +1 -0
- package/dist/utils/js-literal.js +25 -0
- package/dist/utils/js-literal.js.map +1 -0
- package/dist/utils/mcp-log.d.ts +1 -1
- package/dist/utils/mcp-log.d.ts.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +5 -12
- package/dist/version.js.map +1 -1
- package/manifest.json +42 -63
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -249,6 +249,124 @@ If you do not want an agent executing anything, `code` mode is a first-class pat
|
|
|
249
249
|
- Puppeteer itself is an **optional** peer dependency, kept out of the default tree precisely because a headless browser plus an install script is what scanners flag hardest. Install it only if you want the executing mode.
|
|
250
250
|
- 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`. `PINEPAPER_ALLOW_PRIVATE_NETWORK=1` allows local and LAN hosts. Metadata addresses stay refused even with it set.
|
|
251
251
|
|
|
252
|
+
## What's new in 1.6.25
|
|
253
|
+
|
|
254
|
+
### Added
|
|
255
|
+
|
|
256
|
+
- `pinepaper_pattern` kinds `ring` and `orbit`: members spaced evenly round a
|
|
257
|
+
turning circle, with a fixed `center` or a `target` item the centre follows.
|
|
258
|
+
The list of kinds now comes from the studio, so a kind it adds appears here
|
|
259
|
+
too.
|
|
260
|
+
|
|
261
|
+
### Changed
|
|
262
|
+
|
|
263
|
+
- The server speaks MCP itself instead of through the MCP SDK, so installing
|
|
264
|
+
it pulls in 2 packages (`zod` and `undici`) instead of 78. It behaves the
|
|
265
|
+
same on the wire: the same protocol versions (2024-10-07 to 2025-11-25),
|
|
266
|
+
errors, progress, cancellation and logging, checked against recordings of
|
|
267
|
+
the previous server. `createServer()` still accepts any MCP transport,
|
|
268
|
+
including the SDK's.
|
|
269
|
+
- The published code no longer uses `eval` or runs `git`, and it reads
|
|
270
|
+
environment variables in one place.
|
|
271
|
+
- New sessions start with a leaner tool list: the `core` toolkit, about half
|
|
272
|
+
the context of the previous default, with every craft tool the server
|
|
273
|
+
recommends. Other tools load when needed with `pinepaper_set_toolkit`
|
|
274
|
+
`{"load": ["map"]}` (a group) or a tool's name, and the list updates at
|
|
275
|
+
once. Claude Desktop, Cursor and Windsurf used to get all 178 tools.
|
|
276
|
+
`PINEPAPER_TOOLKIT=agent` or `full` restores a larger list.
|
|
277
|
+
- Exports are saved to `~/Downloads/PinePaper` instead of a temporary folder,
|
|
278
|
+
so Desktop users can find them (`PINEPAPER_EXPORT_DIR` still overrides it,
|
|
279
|
+
and machines without a Downloads folder keep the temporary folder). Each
|
|
280
|
+
saved file also comes back as a link the client can open, and
|
|
281
|
+
`resources/read` returns files up to 10 MB from the export folder.
|
|
282
|
+
- A Claude Desktop extension (`.mcpb`) can be built with `bun run
|
|
283
|
+
build:mcpb`: one file to open, no config to edit. It uses your installed
|
|
284
|
+
Chrome for the canvas tools. Without full `puppeteer`, the server now also
|
|
285
|
+
works with `puppeteer-core` and your installed Chrome, or another browser
|
|
286
|
+
set in `PINEPAPER_CHROME_PATH`.
|
|
287
|
+
|
|
288
|
+
### Fixed
|
|
289
|
+
|
|
290
|
+
- `pinepaper_pattern` no longer warns "NO CHANGE" after a `create` or
|
|
291
|
+
`modify` that has not moved anything yet, such as a wave at time 0 or one
|
|
292
|
+
whose window starts later.
|
|
293
|
+
- A failed batch step addressed by `$N` names the item that `$N` resolved to,
|
|
294
|
+
not `"$N"`.
|
|
295
|
+
- Batch `animate` and `relation` operations quote their `animationType` and
|
|
296
|
+
`relationType` correctly in the generated code.
|
|
297
|
+
- The scene lint that batches and custom code run on every call no longer
|
|
298
|
+
checks every pair of items, which made each call on a large scene slower.
|
|
299
|
+
It reports the same warnings.
|
|
300
|
+
- A video export that goes over the bitrate you asked for says so: the studio
|
|
301
|
+
reports `bitrate_exceeded` with the bitrate the file actually has, and how
|
|
302
|
+
to land under the target.
|
|
303
|
+
- The agent toolkit's export description now says what each format returns:
|
|
304
|
+
only MP4 and WebM carry a frame digest, and a small SVG comes back inline
|
|
305
|
+
rather than as a file.
|
|
306
|
+
- `on_event_fire_if` is documented: its predicate is an ExpressionIR object
|
|
307
|
+
(comparisons, and/or/not, reads of an item's data, active or visible
|
|
308
|
+
state), and it fires the event in `params.event`, not its target. A
|
|
309
|
+
predicate written as a string, or a relation with no event to fire, is
|
|
310
|
+
refused with the shape that works, wherever the relation comes from:
|
|
311
|
+
`pinepaper_add_relation`, a batch `relation` step, `pinepaper_create_scene`,
|
|
312
|
+
`pinepaper_instantiate_ontology`, or an `on_event_add_relation` that adds
|
|
313
|
+
one later. Before, the relation silently never fired.
|
|
314
|
+
- An emitter given a `[min, max]` range for a key that takes one number
|
|
315
|
+
(such as `gravity`, `opacity` or `count`) now gets a warning: the key draws
|
|
316
|
+
one value for every particle, not a spread. Before, there was no warning.
|
|
317
|
+
- `pinepaper_import_image` takes a `name`, so a batch `patch` can address an
|
|
318
|
+
imported image by name.
|
|
319
|
+
- Custom code that returns nothing is reported as returning nothing, not as
|
|
320
|
+
`{}`, when the scene lint has warnings.
|
|
321
|
+
- An export whose file was saved but could not be hashed or read back says
|
|
322
|
+
so. It used to report the save as failed.
|
|
323
|
+
- A batch step other than `create` that carries a key it does not read
|
|
324
|
+
now gets an `IGNORED ARGUMENTS` note naming the step and the key. Before,
|
|
325
|
+
the key had no effect and nothing said so. The common mix-ups get a hint:
|
|
326
|
+
`params` on a `relation` step (it takes `relationOptions`), and `x`/`y` on
|
|
327
|
+
a `modify` step (changes go inside `properties`).
|
|
328
|
+
- Clearing the canvas starts item ids again at `item_1`
|
|
329
|
+
(`pinepaper_clear_canvas`, `pinepaper_agent_start_job` and
|
|
330
|
+
`pinepaper_agent_reset`), so a batch sent after a clear gets the same ids
|
|
331
|
+
every time. Before, the numbering carried on from the cleared items, and
|
|
332
|
+
only a server restart reset it.
|
|
333
|
+
- A `group` step in a batch now takes the next `$N`, as a `create` does, so
|
|
334
|
+
a later step can animate the group: in `[create, create, group, …]` the
|
|
335
|
+
group is `$2`. This renumbers batches that create items after a group:
|
|
336
|
+
in `[create, create, group, create]` the last item was `$2` and is now
|
|
337
|
+
`$3`. Before, a `$N` meant for the group failed with "it has created 2 so
|
|
338
|
+
far".
|
|
339
|
+
- An event reaction that shows or hides an item (`on_event_set_visibility`,
|
|
340
|
+
and its `on_enter_` and `on_exit_` forms) refuses `value` and asks for
|
|
341
|
+
`visible`, the field it reads. Before, `{"value": false}` showed the item
|
|
342
|
+
instead of hiding it.
|
|
343
|
+
- A PNG, JPG, WebP, SVG or PDF of a scene that is playing is its first frame
|
|
344
|
+
(time 0), the frame a video starts on, and the result says so. Before, it
|
|
345
|
+
was whatever frame playback had reached, so items moved by relations (an
|
|
346
|
+
orbit) were in a different place on every export. `time` still picks
|
|
347
|
+
another moment.
|
|
348
|
+
- A closed shape given a `strokeColor` and no fill is drawn as an outline.
|
|
349
|
+
Before, it got the default fill, or the active brand's colour.
|
|
350
|
+
- A batch no longer flags `ttl` or `bornAt` on a `line` as a likely typo.
|
|
351
|
+
- A line created with `from` and `to` reports where it actually is, and says
|
|
352
|
+
that `position` does not move it: `from` and `to` are canvas coordinates.
|
|
353
|
+
Before, the result reported the position asked for while the line was
|
|
354
|
+
drawn at the top left.
|
|
355
|
+
- `pinepaper_transform` `nudge` moves an item the way `pinepaper_modify_item`
|
|
356
|
+
does, so an item with a loop animation keeps its new place, and the
|
|
357
|
+
result no longer reports the move as no change.
|
|
358
|
+
- `create_item` documents `properties.id`: an id of your own, so replays
|
|
359
|
+
address the same items. An id with a quote, backslash or line break is
|
|
360
|
+
refused, since later calls could not address it.
|
|
361
|
+
- An item id containing a quote no longer breaks `pinepaper_modify_item`,
|
|
362
|
+
`pinepaper_delete_item`, `pinepaper_animate`,
|
|
363
|
+
`pinepaper_keyframe_animate`, `pinepaper_apply_effect` or
|
|
364
|
+
`pinepaper_query_relations`. Before, the call failed with a syntax error.
|
|
365
|
+
- The `lane` toolkit adds `pinepaper_event`, for things that happen at a
|
|
366
|
+
set time or on a click (a panel that hides at 3 s), and
|
|
367
|
+
`pinepaper_clear_canvas`, to start over. Its batch description shows how
|
|
368
|
+
to attach an event's reactions and triggers.
|
|
369
|
+
|
|
252
370
|
## What's new in 1.6.24
|
|
253
371
|
|
|
254
372
|
### Added
|
|
@@ -1717,27 +1835,20 @@ Fourteen new tools (121 → 135) and new actions across the surface — the rele
|
|
|
1717
1835
|
|
|
1718
1836
|
| Profile | Contents |
|
|
1719
1837
|
|---------|----------|
|
|
1838
|
+
| `core` | **The default.** The craft tools the server's instructions point to, the agent workflow, canvas and query tools, plus every tool those name, so no listed tool points at a missing one. About half the tokens of `agent`. Anything else loads on demand (below) |
|
|
1720
1839
|
| `full` | Every tool, no filtering |
|
|
1721
|
-
| `agent` | Every tool except the diagnostics (`pinepaper_get_performance_metrics`, `pinepaper_diagnostic_report`) and `pinepaper_register_item
|
|
1840
|
+
| `agent` | Every tool except the diagnostics (`pinepaper_get_performance_metrics`, `pinepaper_diagnostic_report`) and `pinepaper_register_item` |
|
|
1722
1841
|
| `diagram` | Canvas + diagram + query/export |
|
|
1723
1842
|
| `map` | Canvas + map + query/export |
|
|
1724
1843
|
| `font` | Canvas + font + letter collage + export |
|
|
1725
1844
|
| `minimal` | Agent, browser, canvas, and guide only |
|
|
1726
|
-
| `lane` | **The agent lane**: exactly
|
|
1845
|
+
| `lane` | **The agent lane**: exactly seven tools — `pinepaper_agent_batch_execute`, `pinepaper_keyframe_animate`, `pinepaper_pattern`, `pinepaper_agent_export`, `pinepaper_lint_scene`, `pinepaper_event`, `pinepaper_clear_canvas` — shown with descriptions that carry the rules an agent otherwise learns by failing (the keyframe shape, an item's words and look inside `properties`, a position being the item's centre, the export's 5 s default). The whole contract, instructions included, is ~4.3k tokens. For scripted builds of shapes, text, keyframes and relations; use `core` for characters, styled scenes, maps, diagrams and sound |
|
|
1727
1846
|
|
|
1728
1847
|
**Verbosity tiers** (`PINEPAPER_VERBOSITY`): `verbose`, `compact` (default), `minimal`.
|
|
1729
1848
|
|
|
1730
|
-
**
|
|
1849
|
+
**Load on demand.** Every client starts on `core`. When a task needs more, the model calls `pinepaper_set_toolkit` with `load`: a group (`{"load": ["map"]}`, `["diagram"]`, `["font"]`, `["physics"]`, …) or a tool's own name. The tools are added for the session, along with any tools they mention, and the client is told the list changed. The server logs each client's name at start-up.
|
|
1731
1850
|
|
|
1732
|
-
|
|
1733
|
-
|--------|---------|-----------|
|
|
1734
|
-
| `claude-ai` | `minimal` | `compact` |
|
|
1735
|
-
| `claude-desktop` | `full` | `compact` |
|
|
1736
|
-
| `claude-code` | `agent` | `compact` |
|
|
1737
|
-
| `cursor` | `full` | `compact` |
|
|
1738
|
-
| `windsurf` | `full` | `compact` |
|
|
1739
|
-
|
|
1740
|
-
Explicit env vars always win. You can also hand-pick tools with `PINEPAPER_TOOLS` (comma-separated names), or switch profiles at runtime with the `pinepaper_set_toolkit` tool. Start with `pinepaper_tool_guide` to have the server explain its own surface.
|
|
1851
|
+
`PINEPAPER_TOOLKIT` always wins. You can also hand-pick tools with `PINEPAPER_TOOLS` (comma-separated names), or switch profiles at runtime with the `pinepaper_set_toolkit` tool. Start with `pinepaper_tool_guide` to have the server explain its own surface.
|
|
1741
1852
|
|
|
1742
1853
|
## Features
|
|
1743
1854
|
|
|
@@ -2322,6 +2433,10 @@ bun install
|
|
|
2322
2433
|
bun run build
|
|
2323
2434
|
```
|
|
2324
2435
|
|
|
2436
|
+
### Claude Desktop extension (.mcpb)
|
|
2437
|
+
|
|
2438
|
+
`bun run build:mcpb` builds `mcpb/pinepaper-mcp-server-<version>.mcpb`, a one-file Claude Desktop extension: open it and Desktop installs the server, with no config file to edit. The extension drives your installed Google Chrome (choose another Chromium-based browser in its settings), and its settings also set the export folder and the tool list.
|
|
2439
|
+
|
|
2325
2440
|
### Test with MCP Client (Local)
|
|
2326
2441
|
|
|
2327
2442
|
1. Build the server:
|
|
@@ -2437,9 +2552,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
|
|
|
2437
2552
|
| `PINEPAPER_API_KEY` | Service-account key (`pp_sa_…`) for the cloud-backed tools (`pinepaper_generate`) | — |
|
|
2438
2553
|
| `PINEPAPER_CLOUD_URL` | The PinePaper cloud those tools call | `https://cloud.pinepaper.studio` |
|
|
2439
2554
|
| `PINEPAPER_EXECUTION_MODE` | `puppeteer` (execute in a real browser) or `code` (return generated code only) | `puppeteer` |
|
|
2440
|
-
| `
|
|
2555
|
+
| `PINEPAPER_CHROME_PATH` | A Chromium-based browser for the canvas tools when full `puppeteer` is not installed (the Desktop extension uses your installed Chrome by default) | installed Google Chrome |
|
|
2556
|
+
| `PINEPAPER_EXPORT_DIR` | Directory for exported files | `~/Downloads/PinePaper` (`<tmpdir>/pinepaper-exports` where there is no Downloads folder) |
|
|
2441
2557
|
| `PINEPAPER_LOCALE` | Language locale code | `en` |
|
|
2442
|
-
| `PINEPAPER_TOOLKIT` | Toolkit profile (`full`/`agent`/`diagram`/`map`/`font`/`minimal`/`lane`) |
|
|
2558
|
+
| `PINEPAPER_TOOLKIT` | Toolkit profile (`core`/`full`/`agent`/`diagram`/`map`/`font`/`minimal`/`lane`) | `core` |
|
|
2443
2559
|
| `PINEPAPER_TOOLS` | Explicit comma-separated tool allowlist | unset |
|
|
2444
2560
|
| `PINEPAPER_VERBOSITY` | Description verbosity (`verbose`/`compact`/`minimal`) | `compact` |
|
|
2445
2561
|
| `PINEPAPER_TOOL_VERBOSITY` | Deprecated alias for `PINEPAPER_VERBOSITY` | unset |
|
|
@@ -305,6 +305,12 @@ export declare class PinePaperBrowserController {
|
|
|
305
305
|
/**
|
|
306
306
|
* Execute JavaScript code in PinePaper Studio
|
|
307
307
|
*/
|
|
308
|
+
/**
|
|
309
|
+
* The ungoverned path: the code as a CDP Runtime.evaluate (Puppeteer's string form awaits a promise and keeps the
|
|
310
|
+
* script's trailing value), then the in-page bridgeSafe the governed path uses, so a value holding live Paper items
|
|
311
|
+
* still crosses. A throw comes back as { success: false, error }, as it did from eval.
|
|
312
|
+
*/
|
|
313
|
+
private runUngoverned;
|
|
308
314
|
executeCode(code: string, takeScreenshot?: boolean, options?: ExecuteCodeOptions): Promise<ExecuteResult>;
|
|
309
315
|
/**
|
|
310
316
|
* Take a screenshot of the current canvas
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"puppeteer-controller.d.ts","sourceRoot":"","sources":["../../src/browser/puppeteer-controller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"puppeteer-controller.d.ts","sourceRoot":"","sources":["../../src/browser/puppeteer-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { mcpLog } from '../utils/mcp-log.js';
|
|
8
8
|
import { LAZY_HEAVY_SUBSYSTEMS, LAZY_HEAVY_CLASSES, ENGINE_SURFACE } from '../tools/engine-surface.js';
|
|
9
|
+
import { env } from '../utils/env.js';
|
|
9
10
|
export const PAGE_WAIT_UNTIL = ['load', 'domcontentloaded', 'networkidle0', 'networkidle2'];
|
|
10
11
|
/**
|
|
11
12
|
* Is PinePaper Studio actually usable? Evaluated IN THE PAGE, so it closes over
|
|
@@ -74,6 +75,46 @@ const BOOTSTRAP_SUBSYSTEMS = Object.freeze(Object.entries(ENGINE_SURFACE)
|
|
|
74
75
|
* not go through executeOrGenerate (gate A2, 1.6.19).
|
|
75
76
|
*/
|
|
76
77
|
export const BROWSER_TIME = { executeMs: 0, screenshotMs: 0 };
|
|
78
|
+
/**
|
|
79
|
+
* The browser driver. Puppeteer is an OPTIONAL peer (1.6.5): browser automation
|
|
80
|
+
* is a handful of tools, and a headless-browser download with an install script
|
|
81
|
+
* in the default tree is what supply-chain scanners flag hardest.
|
|
82
|
+
*
|
|
83
|
+
* Tried in order: `puppeteer` (its own Chrome), then `puppeteer-core` driving a
|
|
84
|
+
* browser already on the machine (1.6.25: the Claude Desktop bundle ships
|
|
85
|
+
* puppeteer-core, not a Chrome download): PINEPAPER_CHROME_PATH when set, else
|
|
86
|
+
* the installed Chrome. Neither present → the install instruction, not a crash.
|
|
87
|
+
*/
|
|
88
|
+
async function loadPuppeteer() {
|
|
89
|
+
try {
|
|
90
|
+
const full = await import('puppeteer');
|
|
91
|
+
return { launch: (opts) => full.default.launch(opts) };
|
|
92
|
+
}
|
|
93
|
+
catch { /* not installed: try the core driver */ }
|
|
94
|
+
let core = null;
|
|
95
|
+
try {
|
|
96
|
+
const specifier = 'puppeteer-core'; // a variable, so the build does not need the package installed
|
|
97
|
+
core = await import(specifier);
|
|
98
|
+
}
|
|
99
|
+
catch { /* not installed either */ }
|
|
100
|
+
if (core) {
|
|
101
|
+
const executablePath = env('PINEPAPER_CHROME_PATH')?.trim();
|
|
102
|
+
return {
|
|
103
|
+
launch: async (opts) => {
|
|
104
|
+
try {
|
|
105
|
+
return await core.default.launch({ ...opts, ...(executablePath ? { executablePath } : { channel: 'chrome' }) });
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
const why = e instanceof Error ? e.message.split('\n')[0] : String(e);
|
|
109
|
+
throw new Error(executablePath
|
|
110
|
+
? `Could not start the browser at PINEPAPER_CHROME_PATH (${executablePath}): ${why}`
|
|
111
|
+
: `The canvas tools drive your installed Google Chrome, and it could not be started (${why}). Install Chrome from https://www.google.com/chrome/, or set PINEPAPER_CHROME_PATH to another Chromium-based browser (Edge, Brave, Chromium), then retry.`);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
throw new Error('The browser tools need puppeteer, which is an optional install. Under npx, add it to the same call — args ["-y", "-p", "puppeteer", "-p", "@pinepaper.studio/mcp-server", "pinepaper-mcp"] — since a separate `npm i puppeteer` is not visible to npx\'s copy. Installed globally: `npm i -g puppeteer`; in a project: `npm i puppeteer`. Then retry. It is kept out of the default dependency tree for supply-chain hygiene.');
|
|
117
|
+
}
|
|
77
118
|
export class PinePaperBrowserController {
|
|
78
119
|
browser = null;
|
|
79
120
|
page = null;
|
|
@@ -305,19 +346,9 @@ export class PinePaperBrowserController {
|
|
|
305
346
|
this.browser = null;
|
|
306
347
|
this.page = null;
|
|
307
348
|
}
|
|
308
|
-
|
|
309
|
-
// tools, and carrying a headless-browser + install-script dependency in
|
|
310
|
-
// the default tree is what supply-chain scanners flag hardest. Absent →
|
|
311
|
-
// a clear instruction, not a crash.
|
|
312
|
-
let puppeteer;
|
|
313
|
-
try {
|
|
314
|
-
puppeteer = await import('puppeteer');
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
throw new Error('The browser tools need puppeteer, which is an optional install. Under npx, add it to the same call — args ["-y", "-p", "puppeteer", "-p", "@pinepaper.studio/mcp-server", "pinepaper-mcp"] — since a separate `npm i puppeteer` is not visible to npx\'s copy. Installed globally: `npm i -g puppeteer`; in a project: `npm i puppeteer`. Then retry. It is kept out of the default dependency tree for supply-chain hygiene.');
|
|
318
|
-
}
|
|
349
|
+
const puppeteer = await loadPuppeteer();
|
|
319
350
|
console.error('[PinePaper] Launching browser...');
|
|
320
|
-
this.browser = await puppeteer.
|
|
351
|
+
this.browser = await puppeteer.launch(this.launchOptions(this.config.headless, this.launchArgs(this.config.viewportWidth, this.config.viewportHeight)));
|
|
321
352
|
// Get existing pages first, reuse if available (avoid creating multiple tabs)
|
|
322
353
|
const pages = await this.browser.pages();
|
|
323
354
|
if (pages.length > 0) {
|
|
@@ -501,7 +532,7 @@ export class PinePaperBrowserController {
|
|
|
501
532
|
async ensureStudioPage() {
|
|
502
533
|
if (!this.page)
|
|
503
534
|
return 'ok';
|
|
504
|
-
let state
|
|
535
|
+
let state;
|
|
505
536
|
try {
|
|
506
537
|
state = await this.page.evaluate(() => {
|
|
507
538
|
const app = window.app || window.PinePaper;
|
|
@@ -548,6 +579,31 @@ export class PinePaperBrowserController {
|
|
|
548
579
|
/**
|
|
549
580
|
* Execute JavaScript code in PinePaper Studio
|
|
550
581
|
*/
|
|
582
|
+
/**
|
|
583
|
+
* The ungoverned path: the code as a CDP Runtime.evaluate (Puppeteer's string form awaits a promise and keeps the
|
|
584
|
+
* script's trailing value), then the in-page bridgeSafe the governed path uses, so a value holding live Paper items
|
|
585
|
+
* still crosses. A throw comes back as { success: false, error }, as it did from eval.
|
|
586
|
+
*/
|
|
587
|
+
async runUngoverned(code) {
|
|
588
|
+
if (!this.page)
|
|
589
|
+
return { success: false, error: 'Browser not connected', executedVia: 'eval' };
|
|
590
|
+
let handle = null;
|
|
591
|
+
try {
|
|
592
|
+
handle = await this.page.evaluateHandle(code);
|
|
593
|
+
const value = await this.page.evaluate((v) => {
|
|
594
|
+
const safe = window.__ppBridgeSafe;
|
|
595
|
+
return safe ? safe(v) : v;
|
|
596
|
+
}, handle);
|
|
597
|
+
return { success: true, result: value, executedVia: 'eval' };
|
|
598
|
+
}
|
|
599
|
+
catch (e) {
|
|
600
|
+
return { success: false, error: e instanceof Error ? e.message : 'Execution error', executedVia: 'eval' };
|
|
601
|
+
}
|
|
602
|
+
finally {
|
|
603
|
+
if (handle)
|
|
604
|
+
await handle.dispose().catch(() => { });
|
|
605
|
+
}
|
|
606
|
+
}
|
|
551
607
|
async executeCode(code, takeScreenshot = true, options = {}) {
|
|
552
608
|
if (!this.page || !this.isConnected) {
|
|
553
609
|
return {
|
|
@@ -611,7 +667,7 @@ export class PinePaperBrowserController {
|
|
|
611
667
|
stage: options.stage ?? null,
|
|
612
668
|
};
|
|
613
669
|
const __evalStart = Date.now();
|
|
614
|
-
const
|
|
670
|
+
const evaluated = await this.page.evaluate(async (codeToRun, opts) => {
|
|
615
671
|
// THE BRIDGE USES STRUCTURED CLONE, AND JSON.stringify DOES NOT PROVE IT.
|
|
616
672
|
//
|
|
617
673
|
// A result crosses CDP by structured clone, which refuses to carry a
|
|
@@ -715,25 +771,18 @@ export class PinePaperBrowserController {
|
|
|
715
771
|
return { success: false, error: e instanceof Error ? e.message : 'Execution error', executedVia: 'governed' };
|
|
716
772
|
}
|
|
717
773
|
}
|
|
718
|
-
// Fallback:
|
|
719
|
-
// bypass.
|
|
720
|
-
//
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
return { success: true, result: bridgeSafe(evalResult), executedVia: 'eval' };
|
|
728
|
-
}
|
|
729
|
-
catch (e) {
|
|
730
|
-
return {
|
|
731
|
-
success: false,
|
|
732
|
-
error: e instanceof Error ? e.message : 'Execution error',
|
|
733
|
-
executedVia: 'eval',
|
|
734
|
-
};
|
|
735
|
-
}
|
|
774
|
+
// Fallback: run ungoverned — a pre-governor FxTool build, or an explicit
|
|
775
|
+
// bypass. The code is run from the Node side as a CDP Runtime.evaluate
|
|
776
|
+
// (below), which returns the script's trailing value exactly as eval did:
|
|
777
|
+
// both generated-code shapes are `(`-led expression statements. It used
|
|
778
|
+
// to be eval() here; the published package then carried an eval call
|
|
779
|
+
// that supply-chain scanners flag, for what CDP already does.
|
|
780
|
+
window.__ppBridgeSafe = bridgeSafe;
|
|
781
|
+
return { success: true, __ppRaw: true, executedVia: 'eval' };
|
|
736
782
|
}, code, runOptions);
|
|
783
|
+
let result = evaluated;
|
|
784
|
+
if (evaluated.__ppRaw)
|
|
785
|
+
result = await this.runUngoverned(code);
|
|
737
786
|
BROWSER_TIME.executeMs += Date.now() - __evalStart;
|
|
738
787
|
// Take screenshot if requested
|
|
739
788
|
let screenshot;
|
|
@@ -981,23 +1030,13 @@ export class PinePaperBrowserController {
|
|
|
981
1030
|
this.browser = null;
|
|
982
1031
|
this.page = null;
|
|
983
1032
|
}
|
|
984
|
-
|
|
985
|
-
// tools, and carrying a headless-browser + install-script dependency in
|
|
986
|
-
// the default tree is what supply-chain scanners flag hardest. Absent →
|
|
987
|
-
// a clear instruction, not a crash.
|
|
988
|
-
let puppeteer;
|
|
989
|
-
try {
|
|
990
|
-
puppeteer = await import('puppeteer');
|
|
991
|
-
}
|
|
992
|
-
catch {
|
|
993
|
-
throw new Error('The browser tools need puppeteer, which is an optional install. Under npx, add it to the same call — args ["-y", "-p", "puppeteer", "-p", "@pinepaper.studio/mcp-server", "pinepaper-mcp"] — since a separate `npm i puppeteer` is not visible to npx\'s copy. Installed globally: `npm i -g puppeteer`; in a project: `npm i puppeteer`. Then retry. It is kept out of the default dependency tree for supply-chain hygiene.');
|
|
994
|
-
}
|
|
1033
|
+
const puppeteer = await loadPuppeteer();
|
|
995
1034
|
// Agent mode defaults to visible browser so user can see PinePaper Studio
|
|
996
1035
|
const useHeadless = options.headless ?? this.config.headless;
|
|
997
1036
|
const viewportWidth = options.viewportWidth ?? this.config.viewportWidth;
|
|
998
1037
|
const viewportHeight = options.viewportHeight ?? this.config.viewportHeight;
|
|
999
1038
|
console.error(`[PinePaper] Launching browser in agent mode (headless: ${useHeadless})...`);
|
|
1000
|
-
this.browser = await puppeteer.
|
|
1039
|
+
this.browser = await puppeteer.launch(this.launchOptions(useHeadless, this.launchArgs(viewportWidth, viewportHeight, [
|
|
1001
1040
|
// '--disable-gpu' USED TO BE HERE, AND IT TURNED OFF WEBGL.
|
|
1002
1041
|
//
|
|
1003
1042
|
// It was carried in as a headless convention under "optimization
|
|
@@ -1134,24 +1173,13 @@ ${codes.map((code, i) => `
|
|
|
1134
1173
|
})();
|
|
1135
1174
|
`.trim();
|
|
1136
1175
|
try {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
return evalResult;
|
|
1145
|
-
}
|
|
1146
|
-
catch (e) {
|
|
1147
|
-
return {
|
|
1148
|
-
success: false,
|
|
1149
|
-
error: e instanceof Error ? e.message : 'Batch execution error',
|
|
1150
|
-
results: [],
|
|
1151
|
-
itemIds: [],
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
}, batchCode);
|
|
1176
|
+
// A string is run as a CDP Runtime.evaluate: the script's value, awaited, by value (no eval in this package).
|
|
1177
|
+
const result = await this.page.evaluate(batchCode).catch((e) => ({
|
|
1178
|
+
success: false,
|
|
1179
|
+
error: e instanceof Error ? e.message : 'Batch execution error',
|
|
1180
|
+
results: [],
|
|
1181
|
+
itemIds: [],
|
|
1182
|
+
}));
|
|
1155
1183
|
const executionTime = Date.now() - startTime;
|
|
1156
1184
|
// Take screenshot if requested
|
|
1157
1185
|
let screenshot;
|
|
@@ -1268,25 +1296,25 @@ export function getBrowserController(config) {
|
|
|
1268
1296
|
// Env resolution lives here, not in the controller: explicit config wins,
|
|
1269
1297
|
// then the env var, then the default — the shape PINEPAPER_HEADLESS and
|
|
1270
1298
|
// PINEPAPER_STUDIO_URL already use.
|
|
1271
|
-
const envHeadless =
|
|
1299
|
+
const envHeadless = env('PINEPAPER_HEADLESS');
|
|
1272
1300
|
const headless = config?.headless ?? (envHeadless !== undefined ? envHeadless !== 'false' : true);
|
|
1273
|
-
const envWaitUntil =
|
|
1301
|
+
const envWaitUntil = env('PINEPAPER_WAIT_UNTIL')?.trim();
|
|
1274
1302
|
if (envWaitUntil && !PAGE_WAIT_UNTIL.includes(envWaitUntil)) {
|
|
1275
1303
|
// Loudly, because a typo here silently reinstates the hang it was set to
|
|
1276
1304
|
// avoid — and a 30s connect failure looks nothing like a bad env var.
|
|
1277
1305
|
console.error(`[PinePaper] PINEPAPER_WAIT_UNTIL="${envWaitUntil}" is not one of ${PAGE_WAIT_UNTIL.join(', ')} — ignoring it.`);
|
|
1278
1306
|
}
|
|
1279
|
-
const envTimeout = Number(
|
|
1280
|
-
if (
|
|
1281
|
-
console.error(`[PinePaper] PINEPAPER_TIMEOUT="${
|
|
1307
|
+
const envTimeout = Number(env('PINEPAPER_TIMEOUT'));
|
|
1308
|
+
if (env('PINEPAPER_TIMEOUT') && !Number.isFinite(envTimeout)) {
|
|
1309
|
+
console.error(`[PinePaper] PINEPAPER_TIMEOUT="${env('PINEPAPER_TIMEOUT')}" is not a number — ignoring it.`);
|
|
1282
1310
|
}
|
|
1283
1311
|
const mcpConfig = {
|
|
1284
1312
|
...config,
|
|
1285
1313
|
headless,
|
|
1286
1314
|
waitUntil: config?.waitUntil ?? (envWaitUntil && PAGE_WAIT_UNTIL.includes(envWaitUntil) ? envWaitUntil : undefined),
|
|
1287
1315
|
timeout: config?.timeout ?? (Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : undefined),
|
|
1288
|
-
proxy: config?.proxy ??
|
|
1289
|
-
governor: config?.governor ?? (
|
|
1316
|
+
proxy: config?.proxy ?? env('PINEPAPER_PROXY')?.trim(),
|
|
1317
|
+
governor: config?.governor ?? (env('PINEPAPER_GOVERNOR')?.trim().toLowerCase() !== 'off'),
|
|
1290
1318
|
};
|
|
1291
1319
|
globalController = new PinePaperBrowserController(mcpConfig);
|
|
1292
1320
|
}
|