Two gaps CodeRabbit found in the guard:
- `same_file` compared paths, plain and resolved. A second hard link to
the file is a different path to the same data, so `convert`,
`run --out` and Save As to the link passed the guard and truncated
the file. It now asks the file system (same-file: device and inode on
Unix, volume and file index on Windows). same-file was already in the
lock through walkdir.
- `run --in X --out X` checked the tab the script left active. A script
that ends on `file.duplicate` or `file.new` leaves a tab with no count
of images left in X, so X was written over. The count is now taken
when X is opened and checked against `--out` whatever tab is active;
the active tab's own file is still checked as before.
The script check is a separate function so it can be tested without a
file past the 4 GiB budget.
A native file whose images together pass IMAGE_BUDGET (4 GiB, or 20,000
images) opens without the images past it. They are intact in the file, but
saving it again wrote the archive from the images in memory, so every
save, autosave or `convert` onto itself deleted them for good. A 7.6 GiB
`.fig` converted to a 7.3 GiB `.figcraft` reopened with 1,312 of its 2,337
images: one save would have dropped the other 1,025.
Loading now tells images left out for the budget apart from damaged ones
(`Loaded::images_past_budget`). A tab opened or reverted from such a file
remembers the file, and saving over it is refused with a message that says
how many images would be lost and to save under another name; saving a copy
elsewhere works, and the original keeps its images. Auto-save skips the
tab instead of retrying and failing every minute. `figcraft-cli convert`
and `run --in X --out X` refuse to write over their input the same way.
The same file is matched by its resolved path, so `./a.figcraft` and
`a.figcraft` count as one (`file_access::same_file`).
The note for each image left out for the budget now says it stays in the
file, which can't be saved over without losing it. Damaged and missing
images keep the old wording: they can't be kept, and saving drops them as
before. The doc comment on report_lost_images said saving always drops
the images it reports, which is no longer true for budget ones, so it went.
This stops the data loss; it doesn't make such files editable in place.
Loading images on demand would, and is discussed in the issue this links.
Tests: the count and the note for both budgets; saving over the file
refused with the file unchanged, Save As then working, and saving back over
the original refused again; a snapshot encoded in the background refused
too; a tab without images left out saving as before. Checked by hand on the
7.3 GiB file with file.save, file.saveAs, convert and run --out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picks up the startup prompt without the glyphs a font may lack (storytold/craft-libs#343, #344): the close mark is painted and the version pill is ASCII, so apps that panic on a missing glyph no longer take the prompt down.
Part of tracking issue storytold/craft-libs#319
Picks up the update prompt fix that draws its close mark and version pill
without glyphs a font may lack, so the prompt no longer takes the app down
when a bundled face has no ✕ or →.
Part of tracking issue storytold/craft-libs#319🤖 Generated with Codebuff
Co-authored-by: Codebuff <noreply@codebuff.com>
* feat: startup update prompt modal and direct self-updating
The update flow (check at start or on request, the startup prompt, the self-update worker) is craft-update's Updater; the app only supplies the suite, its close path and its status window. The check at start is opt-in for the desktop app, an install holds back while documents are unsaved, and the Windows update helper runs before argument parsing.
Ref: storytold/craft-libs#319
* fix(updates): re-add the update hooks to the 0.37 frame loop
* fix(updates): address review feedback
Wake the UI when a manual check is queued from a menu callback; the update prompt owns the keyboard while it is open (LightCraft); Download opens through the desktop URL hook (FilmCraft); the Help menu dispatches through menus::invoke (FigCraft); print jobs and comment drafts hold an install back (WordCraft); Check for Updates is a registered command (GridCraft); an install holds back while documents are unsaved.
* fix(updates): show the prompt on Home and presenter frames and close the application, not one window
* fix(updates): add the update strings to the English catalog
* E21: require release font coverage and stabilize capture deadline tests
* E21: separate capture, IME and field-save regression phases
* M0: correct the migration qualification reference
* M-egui037: document input lifecycle and UI regression contracts
* M0: correct egui 0.37 status docs and stabilize join-code regression
---------
Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
The 0.11.1 release's Web job failed: the wasm was 25,248,590 bytes, over packaging/web/package.sh's 25,165,824-byte limit. opt-level z brings it to 23,306,645 bytes (measured locally with the release's craft-fonts ref, wasm-bindgen 0.2.129 and wasm-opt -Oz).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
import-cert.sh deleted its whole private temp directory on exit, and the keychain lives there, so codesign failed with "The specified item could not be found in the keychain" in the release build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/ui-egui/src/field_math.rs:105 (Parser::factor, unit loop; end() at :109)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/component_codegen.rs:~226 (RESERVED list used by ident at :346)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/svg/src/lib.rs:97 (num, used by matrix at :129 for the image pattern's patternTransform at :243-254)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Prototype player: no clicks reach the prototype behind the link notice
* Selection colors: scopes filter the variable menu; the command binds as variable.bind does
* Style picker: color variables scoped to every selected layer's fill or stroke
* Corner button: named Corner smoothing on polygons and stars
* docs/gaps.md: known gaps from the #1311 review
* cargo fmt
* Style picker: clippy