4 Commits
Author SHA1 Message Date
dotCooCoo 68609fb43b Plug-ins: filters at API level 2 read type, images and symbol instances
A filter manifest at `api` 2 may list `inputs` (`type`, `image`,
`symbolInstance`). Such a filter is also given the selected objects of
those kinds, read only: type with its runs and paragraph attributes,
images with their pixel size, color mode and, when embedded and small
enough, their RGBA pixels in base64 (never a linked file's pixels or
path), and symbol instances with their symbol and transform.

The output must return each read-only object as {"id": ...} alone or
exactly as given. A change, an omission or a duplicate is refused
before the edit, so the document and undo history stay as they were,
including for output handed in from a heavy run. A filter without
`inputs` gets the same input bytes as before.

A manifest that lists `inputs` below `api` 2, outside a filter, with an
unknown or repeated kind, or with a permission list that lacks
`doc.read` does not install.

Part of #4333
2026-11-07 23:34:20 -08:00
dotCooCoo 1c676fc372 Plug-ins: API level 2 lets a plug-in report progress, see Cancel and write log lines
A plug-in whose manifest gives "api": 2 and lists the new `progress`
permission may import three host functions from module `env`:
vc_progress(done, total), vc_cancelled() -> i32 and
vc_log(level, ptr, len) -> i32. Installing checks every import and
refuses, by name, one the host doesn't offer, one with another type and
one the manifest doesn't allow.

- Progress is clamped and passed on once per tenth of a percent (past
  2,000 reports, once per 1,000 changes). A heavy filter's progress
  window and the export's progress window show it as a percentage bar,
  and their Cancel makes vc_cancelled return 1. A live effect's progress
  is not shown.
- A run cancelled before it returns ends as cancelled, and one that
  returns after its time budget ran out ends at that budget, so what a
  plug-in returns after it sees vc_cancelled changes nothing. This also
  applies to a plug-in of API level 1 that finishes after a Cancel or
  past its time budget.
- Log text must lie in the module's memory and be UTF-8. Lines go to the
  app's log as "<id>: <text>" with hidden characters escaped, at most
  1,024 characters a line, 200 lines and 32 KiB a run, and the host reads
  at most 1 MiB of log text a run.
- plugin.list and plugin.info give the manifest's `api`; the install
  prompt names the new permission in plain words.

Docs: docs/plugins.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-08 13:21:15 +07:00
dotCooCoo 874ae85fab Plug-ins: manifests list permissions, the user grants them at install, and the host enforces the grant
A manifest may list `permissions` (doc.read, doc.write, state,
effect.render, export.write) and an `api` level. doc.read, doc.write
and state follow the capability model proposed in
storytold/photocraft#662; the other names are VectorCraft's own. An
unknown, reserved, duplicate or wrong-kind name is refused by name. A
manifest without the key gets the permissions its kind implies and
installs as before.

- Install Plug-in... and File > Open show the name, id, version, file
  SHA-256 and each permission in plain words, with control and
  bidirectional characters escaped and each string cut to 64
  characters. OK installs the module only if it still has the SHA-256
  shown; Cancel installs nothing. The heavy-budget prompt and the
  status line show the escaped name too, and OK keeps the `replace` it
  was given.
- `plugin.install` needs `grant` listing every permission, and
  `plugin.inspect` reports `needsApproval`. `hash` pins the module:
  one with another SHA-256 is refused. The grant is kept with the
  module's hash in the store's `grants.json`, and only that store's
  grants count while it is attached; the same set does not ask again,
  more permissions do, and `plugin.remove` forgets it.
- The Additional Plug-ins Folder and `plugin.reload` install only
  plug-ins the attached store has granted and report the others as
  needing approval. At startup the store skips an ungranted plug-in.
- A filter run without doc.read is given no objects; without state it
  neither reads nor writes `documentData`; without doc.write an output
  that changes the document is refused and the document is unchanged.

Docs: docs/plugins.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-08 13:20:32 +07:00
bflatasticandClaude Opus 5.5 811ad1efd8 Fix #121: sandboxed WebAssembly plug-ins: object filters and live effects
VectorCraft had an Additional Plug-ins Folder preference but nothing loaded from it. Port
PhotoCraft's wasmi plug-in host (same sandbox, manifest and parameter schema) as the new
vectorcraft-plugins crate (L2), extended for vector documents:

- Object filters read the selected paths and compound paths as JSON (native PathData and
  Paint forms: geometry, fills, strokes, gradients, opacity) and return the objects to keep,
  change, add or delete; the output is validated in full and applied as one undo step
  (plugin.run). A failing plug-in leaves the document untouched.
- Live-effect plug-ins are geometry effects in the appearance stack (effect id
  plugin.<id>), re-evaluated (and cached) when the object or parameters change, editable,
  exported and baked by Expand Appearance; a missing plug-in leaves the geometry as is.
- plugin.list / info / run / install / remove / reload; the preference folder installs
  every *.wasm at startup and when it changes; File > Open of a .wasm installs it (web).
- Object > Plug-ins and Effect > Plug-ins menus with dialogs generated from the parameter
  schema (live preview), the Appearance panel's fx menu, docs/plugins.md, an original
  example plug-in (Desaturate, a Rust crate outside the workspace) and fuzzing of the
  plug-in boundary (engine/tests/plugin_fuzz.rs).

Tool plug-ins and paint-changing live effects are left for later (docs/plugins.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:19:41 +07:00