* 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>
* chore: resolve SonarCloud maintainability issues
- Define SHA256_FMT constant in packaging script to remove duplicated string literal (shelldre:S1192)
- Remove redundant 'static lifetime annotations from const items (rust:S8863)
- Replace closures with method and function pointers (rust:S1612)
- Extract helper functions in synthetic document generation, bezier polyline flattening, and component restoration to reduce cognitive complexity (rust:S3776)
* fix(packaging): use verify_sha256 helper function to avoid shellcheck SC2059
* fix(engine): remove duplicate closing brace in large_document
* fix(engine): take &mut Document in restore_id_map; keep 'static on associated consts
restore_id_map allocates ids, so it needs a mutable document. Elided
lifetimes in associated consts trip elided_lifetimes_in_associated_constant,
so those annotations are restored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Assign positional parameters to locals in sha256 verification
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
* Dev profile: line tables for workspace crates, no debug info for dependencies
* Tests: one integration-test binary per crate with several test files
* xtask ci: nextest, doctests, tests without examples, --keep-going; add xtask test
read() returns Result<Message>, not a lock guard; these test loops
deliberately ignore what the client sent first.
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The accepting thread read listener.incoming().flatten(), which drops a
failed accept and asks again at once. While accepting keeps failing, for
example when the process has run out of file descriptors, that thread
kept a core busy. It now waits 100 ms after a failed accept. The loop goes
through a small accepted helper so the wait can be tested.
Review: `mcp --bogus --help` stopped at --bogus with exit 2. The parser
now keeps the first bad option and reports it only when no --help or -h
follows.
Review: " . .name. . " kept inner dots at the edges; trim spaces and dots
in one pass. docs/cli.md and safe_file_name's comment give the 100 and
200 character limits.
`figcraft-cli mcp --help` failed with "unknown option --help" and
exit code 2; only a leading --help worked. The argument parser now
returns CliError::Help for --help or -h among a subcommand's options
(not as an option's value), and main prints the usage on stdout with
exit code 0. docs/cli.md says so.
export into a folder replaced every character outside letters, digits,
'-', '_', space and '.' with '_', so a frame called
"Homepage - desktop (live + verbeteringen)" became
"Homepage - desktop _live _ verbeteringen_.png". The app's
file.exportLayers keeps those names and only replaces what file systems
refuse. The CLI now uses the engine's safe_file_name, and docs/cli.md
says which characters are replaced.
Also adds my own entry to contributors/people.toml.
Validated formatting, workspace Clippy, workspace tests excluding the two pre-existing localized startup assertion failures tracked in #1017, layers, assets, WASM and plugins. The startup tests are unchanged in this independent fix.
A batch step can name itself with "as" and later steps refer to it with
{"$ref": "name"}, alongside positional {"$step": n}. "field" now takes a
slash path into the result as well as a key, so {"$ref": "copy",
"field": "ids/0"} reaches the first id edit.duplicate returned (the
convention variable.bind uses for fills/0/color; a leading "/" as in
JSON Pointer also works, and a key holding "/" still matches first).
Resolution moves to crates/engine/src/batch.rs (BatchStep, BatchScope),
shared by command.batch, the CLI script runner, the control channel and
the MCP batch tool, which now passes "as" through. Duplicate names fail
before any step runs; unknown, same-step or later names, bad paths and
out-of-range indexes fail the batch with the step, name and full path.
$ref is reserved like $step; nested batches keep their own names.
Fixes#994.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(window): adopt shared craft-window for Linux decorations
Replace FigCraft's bespoke Wayland xdg-decoration probe
(apps/figcraft/src/linux_window.rs) with the shared craft-window crate
from craft-libs, so every Craft app agrees on who draws the window frame
per desktop.
The decision is now made once, before the viewport is built, by
craft_window::Choice::probe(Prefix::new("FIGCRAFT")) and mapped onto
FigCraft's existing TitleBar enum:
Frame::Desktop => TitleBar::Native (TitleBar::Inset on macOS, unchanged)
Frame::App(_) => TitleBar::Custom
This drops the old runtime send_viewport_cmd(Decorations(..)) switch and
the linux_window probe. macOS keeps its inset traffic lights and Windows
keeps the system frame exactly as before. The only behaviour change: on
KDE and other Wayland compositors with server-side decorations (Sway,
Hyprland, COSMIC) FigCraft now keeps the native frame instead of always
drawing its own custom title bar, matching the rest of the suite.
NOT MERGEABLE YET: craft-window is pinned to the unmerged feature branch
from storytold/craft-libs#217 and must be repointed to a merged rev
before this can land.
* fix(window): preserve Windows titlebar; pin craft-window to merged rev
- Keep FigCraft's own custom title bar on Windows. craft-window returns
Frame::Desktop on Windows, and the mapper was turning that into
TitleBar::Native, flipping Windows from its existing undecorated custom
bar to the system frame. Map Frame::Desktop to Custom on Windows (as
macOS maps to Inset); only Linux/BSD Frame::Desktop becomes Native. This
keeps macOS and Windows unchanged; the sole change stays KDE/Wayland.
- Repoint craft-window from the (now-merged) feature branch to the squash
commit on storytold/craft-libs (craft-libs#217), and commit Cargo.lock.
Verified: cargo build -p figcraft and cargo test -p figcraft (53 tests)
pass against the merged dependency; rustfmt clean.