Chromium debug profile, media-cache and vision/computer-use cache dirs were
created with bare makedirs inheriting the umask (0755); their files landed
0644. Under the documented HERMES_HOME_MODE=0701 traversal hatch those stores
(Cookies, Login Data, screenshots, inbound media) were readable by every
other local account. Dirs are now created owner-only (0700) with the mode
passed to mkdir (no post-chmod window) and reconciled via the house
hermes_cli.config._secure_dir / _secure_file policy helpers, which keep the
managed/NixOS group-share carve-out and HERMES_UID/HERMES_GID ownership.
Cache files are written 0600 via os.open.
Deleting a session also left its journaled in-flight turn tail (user prompt
+ tool calls) in localStorage to age out on its own; purgeInFlightTurnJournals
now runs on both delete surfaces (sidebar removeSession and Settings
permanent delete), draining every id the delete holds.
Refs #77486
Resolved toward the branch: PM provisions uv/python (main's install.ps1 uv-shim
salvage + its test and workflow steps dropped), the shim re-exec stays retired,
package.json carries no electron-builder block (afterExtract identity stamp wired
into electron-builder.config.cjs instead; after-pack.mjs keeps signing only),
Desktop workspace-deps helpers stay retired. Main's scratch-dir bootstrap
(export_scratch_tmp_env) is taken and re-run after profile resolution.
Review follow-ups on the inline-image guard:
- `image/jpg` is the JPEG alias every other image site accepts
(vision_message_prep, conversation_compression, image_gen_provider,
mcp_tool_content); the Responses guard downgraded it to a text
placeholder, losing a valid image. It now counts as JPEG.
- The Anthropic converter forwarded data:image/svg+xml (bmp, tiff) verbatim
as media_type, which 400s every turn once the part is in history. It now
applies the same rule: SVG is rasterized to PNG when a rasterizer exists,
any other unsupported inline subtype becomes a text placeholder, and
image/jpg is normalized to image/jpeg.
Both wire paths share one helper next to the existing supported-set
constant in tools/vision_tools_image_prep (import-time deps: hermes_constants
only, no cycle).
A/B: new Anthropic test and the jpg assertion red on the previous head,
green now.
The send-layer guard from c9f8cb72a6a downgrades every inline
data:image/svg+xml part to a text placeholder, so the model never sees a
drawing the agent (or a user attachment) wanted it to look at. The
reporter's ask was to rasterize instead of drop when that is possible.
Reuse the vision_analyze rasterizer chain (cairosvg / svglib+reportlab /
rsvg-convert / inkscape, all soft deps) through a small
rasterize_svg_data_url helper in tools/vision_tools_image_prep: the SVG
payload is decoded to a temp file, rasterized, re-encoded as a PNG data URL
and forwarded as input_image; the temp files are removed. Without a
rasterizer the existing placeholder still applies, so the request can never
carry SVG source. Import is lazy inside _input_image_part (no cycle; the prep
module only depends on hermes_constants at import time).
Live (real converter on a temp HERMES_HOME): base with cairosvg installed ->
input_text placeholder; fixed with cairosvg -> input_image
data:image/png (PNG magic verified); fixed without any rasterizer ->
placeholder.
vision_analyze rejected iPhone photos with 'source is not a recognized
image'. iPhones capture HEIC (ISO-BMFF/HEVC) and upload pipelines often
mislabel it .jpg; the magic-byte sniff had no HEIF branch, so the bytes
were rejected before reaching normalization.
- _detect_image_mime_type_from_bytes: sniff the ISO-BMFF 'ftyp' box and
recognize HEIF/HEIC (heic/heix/heim/heis/hevc/hevx/mif1/msf1) and AVIF
(avif/avis) brands, returning image/heic or image/avif. Non-image ftyp
brands (mp4, ...) stay unrecognized.
- _normalize_to_supported_image: register the pillow-heif Pillow opener,
then re-encode HEIF/AVIF to PNG before embed (same soft-dependency
pattern as SVG rasterization). Missing decoder yields an actionable
'pip install pillow-heif' error, not a generic failure.
- Add pillow-heif==1.4.0 as a core dep alongside Pillow (prebuilt wheels
bundle libheif; no system libs needed).
- Tests: brand detection (incl. AVIF + mp4-not-misdetected), end-to-end
HEIC->PNG normalization, and the decoder-missing error path.
The vision resolver's magic-byte sniff stays authoritative (no extension
trust); HEIF now reaches the existing normalize step instead of 400ing.