describe declares:
commands.screenshot.add.mutates: .vref/manifest.json, .vref/screenshots/*.webp
commands.convert.mutates: .vref/manifest.json, .vref/screenshots/*
Both understate what the commands can touch. An entry's file is any safe manifest-relative path — safeManifestAssetPath rejects traversal, absolute paths, schemes and control characters, but requires no screenshots/ prefix — and the manifest directory itself is whatever --manifest points at.
Reproduced against 2.0.0:
vref screenshot add ./src.png --json '{"id":"logo",...,"file":"assets/logo.webp"}'
# -> writes .vref/assets/logo.webp, outside the declared scope
convert has the same property: it re-encodes to a sibling path of whatever the entry references, so a assets/logo.png entry produces assets/logo.webp.
Automation reading mutates to decide what a command may touch can therefore miss files these commands write or delete. #48 fixed the same defect for screenshot remove by declaring .vref/**; these two were left alone because they predate that PR.
describedeclares:commands.screenshot.add.mutates:.vref/manifest.json,.vref/screenshots/*.webpcommands.convert.mutates:.vref/manifest.json,.vref/screenshots/*Both understate what the commands can touch. An entry's
fileis any safe manifest-relative path —safeManifestAssetPathrejects traversal, absolute paths, schemes and control characters, but requires noscreenshots/prefix — and the manifest directory itself is whatever--manifestpoints at.Reproduced against 2.0.0:
converthas the same property: it re-encodes to a sibling path of whatever the entry references, so aassets/logo.pngentry producesassets/logo.webp.Automation reading
mutatesto decide what a command may touch can therefore miss files these commands write or delete. #48 fixed the same defect forscreenshot removeby declaring.vref/**; these two were left alone because they predate that PR.