A grant records the module's SHA-256, but only its permissions were
compared, so a module with other bytes under a granted id inherited the
grant when it listed no new permission.
A grant now covers a module only when the id, the SHA-256 and every
listed permission match. plugin.inspect reports needsApproval for a
changed module, plugin.install refuses it without a new grant and leaves
the installed module and its grant as they are, Install Plug-in and
File > Open ask again, and the plug-in store and plug-in folders skip it.
The same bytes install again without asking, and a module with no
permissions list or an empty one needs no grant. A grant whose hash is
not 64 lower-case hexadecimal digits covers nothing.
plugin.install still trusts the client that sends grant; the docs say so.
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.
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.