Commit Graph
408 Commits
Author SHA1 Message Date
aiongg 328e42373c Merge PR #3122: LC-002: reject non-object script parameters 2026-10-31 02:06:53 +00:00
aiongg 15a046c537 Merge PR #3098: Issue #3070: the CLI's refused-connection tests use a free port, not 18437 2026-10-31 02:06:53 +00:00
aiongg bc36137608 Merge PR #3076: Issue #3069: --connect resends a command that crossed the app's idle-close notice 2026-10-31 02:06:53 +00:00
aiongg 6ad10a6bf4 Merge PR #3006: CLI-HOSTILE: render --set refuses inf / NaN instead of dropping the value 2026-10-31 02:06:53 +00:00
aiongg 035564c828 Merge PR #2963: Accept a UTF-8 BOM at the start of lightcraft-cli --script files 2026-10-31 02:06:52 +00:00
aiongg 2201129a72 Merge PR #2723: Control port: close gracefully so the client reads its last reply (Windows reset) 2026-10-31 02:06:52 +00:00
Brandon Thomas c1fb95dfc0 Merge PR #3225 2026-10-30 15:24:30 -04:00
Chad ElliottandClaude Opus 5.5 e407ed0e3d test(cli): #3070 the tests that release an ephemeral port before use take turns
unused_port() lets its port go before the CLI connects, and the denoise-serve test
does the same before starting its server: with several test threads the server could
start on a port a refused-connection test had picked, which then reached it instead
of being refused. The three tests now hold one lock for their whole run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 13:02:10 -05:00
Chad ElliottandClaude Opus 5.5 54193e7cb8 test(cli): #3070 refused-connection tests use a free port, not 18437
The `--connect` failure-hint tests connected to 127.0.0.1:18437 and assumed
nothing listened there, but agents give their apps' control servers ports in
18000-19999. With an app on 18437 the tests sent it `ui.inspect` and failed.
They now bind 127.0.0.1:0, drop the listener and use that port, and check the
`--control <port>` hint against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 13:02:10 -05:00
Dylan M. Taylor 445dd3106e Update prompt shows the app icon and accent color instead of a letter (#3362)
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#f2a516, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).

craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- crates/engine/src/cmd/export.rs
- crates/ui-egui/src/dialogs/rules_editor/rules_move.rs
- crates/ui-egui/src/panels/detail.rs
2026-10-30 01:27:49 -04:00
Dylan M. Taylor f6489e60d8 refactor(lightcraft): import prefs and GPU crash names explicitly 2026-10-28 03:25:18 +00:00
Nathaniel Ledford e60b7d1787 MENU-EDIT-SELECTNONE: Edit lists Select Only Active Photo and Paste Settings from Previous with their kin, and the native Edit menu keeps single separators 2026-10-27 22:50:05 -04:00
dotCooCoo d826e79fa2 Skip offscreen Local rows and share hidden-folder checks
Reuse cached folder listings through Arc and allow tests to inject Local places.
Show browsed folders below hidden ancestors as session roots. Apply the same
hidden-entry checks to folder walks, browsing, import scanning, and Local.
2026-10-26 22:36:11 -07:00
Dominic Anaeto b576c72d0b LC-002: reject invalid script parameters 2026-10-26 22:59:44 -04:00
skylar taylor-barrick 662df66f1c Preserve queued file drops across dialogs and restore Flatpak sources (#2975) 2026-10-27 03:50:41 +01:00
aiongg 2e5597d48a refactor(lightcraft): split main.rs into crate-root modules 2026-10-26 21:39:56 +00:00
aiongg d151df0149 style: cargo fmt the moved test modules 2026-10-26 18:30:36 +00:00
aiongg ebff40bbd0 refactor(lightcraft): move logging.rs tests to apps/lightcraft/src/logging/tests.rs 2026-10-26 18:16:10 +00:00
aiongg 4e57c3b99a refactor(lightcraft): move main.rs tests to apps/lightcraft/src/tests.rs 2026-10-26 18:16:10 +00:00
aiongg 567e7f1126 test: scan source directories recursively
xtask parity reads the UI command tables from menus.rs and every file under menus/, and the desktop app's dialog-filter test checks every source file under src/, so both keep finding their items after files move into subdirectories.
2026-10-26 18:01:09 +00:00
Chad ElliottandClaude Opus 5.5 0a76419c4e fix(mcp): #3069 resend a request that crossed the app's idle-close notice
A request sent just as the app expires an idle control connection crosses
the app's id-less idle-close notice: the client's pre-send check saw an
open connection, wrote the request, and read the notice as its reply, so
`--connect` and the MCP server failed a command the app never read.

The app reads nothing after its idle timeout, so such a request never ran.
The app now marks the notice `"closed": "idle"`, and `Remote::call` sends
a request whose reply is that notice once more on a new connection (it
also matches the notice's exact text, for apps from before the marker).
At most one resend per call, whatever the reason; a reply with an id or
any other error is returned as before.

`idle_close_reconnects_without_replaying_a_command` now forces both
orders (notice before the next request, and a request crossing it)
instead of racing the notice; with main's client it fails every run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:08:24 -05:00
aiongg 1952d4fd3c Merge upstream main into docking-adoption 2026-10-26 02:18:38 +00:00
Andrew FrahnandClaude Opus 5.5 2085426230 CLI-HOSTILE: render --set refuses inf / NaN instead of dropping the value
`inf`, `NaN` and `1e999` parse as f64 but serialize to JSON null, so the control was
silently skipped and the photo rendered without the requested edit. They are now an error.
Hostile-input check added to the render subcommand test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:13:34 +11:00
Dylan M. Taylor 2b9317519c 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, and the Windows update helper runs before argument parsing.

Ref: storytold/craft-libs#319
2026-10-25 14:22:14 -04:00
aiongg 672baaea46 Merge lightcraft#2913 (egui 0.37) into docking-adoption; craft-ui and craft-docpath at craft-libs main a091680 2026-10-25 17:36:59 +00:00
NetterSilverandClaude Haiku 5.5 286154a17c Accept a UTF-8 BOM at the start of lightcraft-cli --script files
Fixes #2937

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 17:16:44 +00:00
skylar taylor-barrick 3401286b5c egui037: preserve modal focus and first-pass text selection 2026-10-25 14:15:30 +01:00
aiongg 4bc5d2b587 Docking: the web app resets a saved split-frame layout once too 2026-10-25 12:17:42 +00:00
aiongg 8ae15d4f5e Docking: side panels in dock columns; saved split-frame layouts reset once 2026-10-25 12:17:28 +00:00
skylar taylor-barrick c627ce7210 egui-037: preserve modal input ownership and packaged font notices 2026-10-25 13:14:34 +01:00
skylartaylor e7144adc1f M0.37: reconcile current LightCraft main and qualify the migration 2026-10-25 07:47:22 +01:00
aiongg 7291abdc14 Merge upstream main into docking-adoption 2026-10-25 05:55:03 +00:00
aiongg 5c46163e66 Merge PR #2778: LRC-PRINT-TEMPLATES: print templates export to a file and import from one 2026-10-25 02:23:20 +00:00
skylartaylor c057ccc23f Migrate LightCraft to egui 0.37 and reconcile dependency and font locks
Preserve current main, adapt frame/input and IME handling, and keep library
check results stable across layout passes. Include the matching Nix font lock
and reviewed attribution changes.
2026-10-25 02:54:42 +01:00
aiongg 5ce171da23 Docking: the workspace, its commands and their parser come from craft-ui (craft-libs 16fb3d4)
craft-ui and craft-docpath are pinned to craft-libs 16fb3d46e1eaa0d455465e4e66a3ac7b17b55bd3.
The saved workspace is craft_ui::docking::Workspace<Panel>; settings written
before it had a version load as version 1. ui.dock params parse as the shared
DockCommand and apply through Workspace::apply_all. LightCraft keeps its
panels, permissions, default layout, photo-view checks, the fallback beside
the photo view for a panel with no recorded place, and its settings file.

The photo view takes side splits (accepts_splits on PROTECTED), so panels
still open and move beside it.

Tests: a version 1 workspace file loads and reopens its hidden panel; a drag
of a group by its bar moves both of its panels.
2026-10-24 19:23:08 +00:00
dotCooCoo 59e9a6a4f3 LRC-PRINT-TEMPLATES: print templates export to a file and import from one
The Print dialog's templates could be saved, applied and deleted, but
not moved to another library or another computer. Each saved template
now has an Export… button that writes it to a .lcprint file, and
Import… beside Save adds templates from such files.

print.template.export {name, path} writes {format, version, name,
settings}. print.template.import {path} reads at most 256 KB, checks
the format, version, name and every setting as a saved template's
settings are checked, drops cell photos and guides, and adds the
template under its name, or under "name (2)" and so on when the name is
in use. The buttons appear where the host provides open and save
dialogs: the desktop app does, and the web build does not.
2026-10-23 23:18:35 -07:00
skylartaylor 50df646183 M0.37: port LightCraft UI, input and capture lifecycle to egui 0.37 2026-10-24 08:02:12 +02:00
francoisgnandClaude Opus 5.5 144d900c21 Merge upstream/main (integration batch 43, #2729, #2737, #2412) into round3a-integration
Conflicts:
- apps/lightcraft/src/native_menu.rs: upstream's item swapping (macOS keys
  given up for real, Help menu not swapped, Settings / Quit tracked) with
  KEY-GRID's keymap-aware rows. `Item.label` stays the text the row shows
  (native_item_presentation), so `Item::native_label` reuses it instead of
  formatting it again; Settings / Quit store theirs through
  display_item_label, as upstream's native_label did. No early return after
  a rebuild (upstream).
- crates/ui-egui/src/i18n.rs: upstream's tests (#2729: one test per check
  across languages, gaps reported, never a failure) plus the batch's two new
  ones (dropped-photos notice, Polish counts); production code as merged.
- grid.rs, keyword_list.rs, masking.rs: the translation tests #2729 removed
  stay removed; the batch's new keyword and segmenter tests stay.
- cmd/library.rs, ui-egui/src/lib.rs: both test modules, each with its
  #[cfg(test)].
- xtask/src/main.rs: #2302's test_selected and upstream's translation_gaps.
- docs: tracker / gap rows take both sides' edits, headers list both sides'
  changes, history rows of both sides newest-first. What's New: one section
  per date, newest first (the batch had 10-22 above 10-23, and second 10-21
  and 10-19 sections); no line lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:26:48 +03:00
Brandon Thomas b106ceaca1 Merge PR #2621
# Conflicts:
#	docs/whats-new.md
2026-10-23 17:21:16 -04:00
Brandon Thomas c342c480cf Merge PR #2665 2026-10-23 17:21:16 -04:00
aiongg b264557916 i18n: missing translations are reported, never a failure (#2729)
A message a catalog lacks, or translates as an empty string, shows in
English and fails nothing:

- build.rs no longer requires every formats catalog to carry the same
  messages, and tr_format! gets a last arm that formats the English
  source, so a message no catalog has builds.
- Coverage tests (every language translates X) and tests of one
  language's exact wording are gone; the language-switching, layout,
  date, placeholder and user-value tests read the catalog's own value
  instead of a hard-coded translation.
- i18n::tests::translation_gaps_report lists, per language, the plain
  and format messages it lacks and its untranslated What's New lines.
  It always passes; cargo xtask ci
  runs it from the test step's binary after the tests.
- catalogs_load checks that every catalog file is a JSON object of
  strings with each key once; it.json named "Dimensions" twice.
2026-10-23 16:42:28 -04:00
insideTheFluxandClaude Opus 5.5 e99fbea7f9 Control port: bound the close drain in total; the reset test waits for the rejection
close_gracefully read with a 500 ms timeout per read but no overall limit, so a local client
sending one byte every few hundred milliseconds kept the drain (and its connection slot) going
until it had sent MAX_LINE. Each read now waits at most the time left of DRAIN_TIME (1 s).
New test a_closing_connection_is_not_held_open_by_a_trickling_peer: without the limit it drains
for 10 s.

tcp_connection_is_closed_after_junk no longer sleeps before its second write: it reads the
reply and the rejection first, so the server has rejected the junk before the next line is
sent. It still pauses before the last read so that a reset can arrive. Without
close_gracefully it fails with os error 10053 on Windows.

From CodeRabbit's review of #2723.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PtjHGt5gnCHXgLt4NbGorf
2026-10-23 11:59:47 -07:00
ClaudeandLochLogic 2b341bbdee Control port: close gracefully so the peer reads the last reply (Windows reset)
After rejecting a line the server closed its socket at once. A line the client sent after the
junk then arrived at a closed socket, which answers with a reset, and on Windows the reset
discards the replies the client has not read yet: the client saw os error 10053 / 10054 instead
of the error explaining why. This is the Windows x64 failure of
tcp_connection_is_closed_after_junk in #2377's CI.

serve_stream now shuts down the write side (FIN), reads and drops what is left (at most 4 MiB,
500 ms), then closes. close_gracefully is taken from #1970 by LochLogic, split out so it can
land ahead of the per-run token work; #1991 did not include it.

The test sends its last line 100 ms after the junk and reads after another 100 ms, so it fails
on every run without the fix on Windows (10053) instead of depending on timing.

Co-Authored-By: LochLogic <252105752+LochLogic@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K93HTyCiwYvbRGaAkjPvXn
2026-10-23 11:36:51 -07:00
francoisgnandClaude Opus 5.5 10e184f117 Round 3a: control-server test sends request 2 once after the upstream merge
The merge kept both upstream's (#2710) and the batch's step that sends the
next request (or shuts the write side) during a slow reply, so request 2
went twice and the test waited on a reply nobody gave. Upstream's step
stays, before the sleep. Also drops a mention of `cargo xtask warm`, which
doesn't exist, from test_selected's doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 21:13:09 +03:00
francoisgnandClaude Opus 5.5 f74178cdae Merge upstream/main (#2710 one test binary per crate, #2713) into round3a-integration
Conflicts:
- xtask/src/main.rs: upstream's runners (cargo test or nextest, no
  examples, doctests apart, one wasm `cargo check --keep-going`) with
  #2302's `ci --quick` on top: test_selected builds the same targets
  (--lib --bins --tests), the wasm check takes the changed crates in one
  call, the full test step is upstream's.
- apps/lightcraft/src/control_server.rs: upstream's `before` closure, with
  the batch's no-delay sockets kept.
- docs/parity-checklist.md: LR-BEHAV-ACCESS from main (tests/it path),
  LR-BEHAV-LOCALE / LR-BEHAV-LOCALIZE from the batch (Polish).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 21:06:33 +03:00
aiongg f3bb7a9f30 CI: one test binary per crate, line tables only, one WASM check (#2710)
* CI: dev profile keeps line tables for workspace crates and no debug info for dependencies

* Control server tests: persistent_requests_and_slow_replies_outlive_the_idle_read_timeout no longer races the idle timeout

Each request (and the closing half-shutdown) reaches the socket before the
worker reads, so on a slow machine only the reply waits outlast the 100 ms
idle timeout, as the test intends. The idle test sends its input the same
way, and the no-frames test allows 5 s instead of 2 s to give up.

* CI: one integration-test binary per crate

Each crate's tests/*.rs become modules of tests/it/main.rs (51 test files
into 13 binaries, plus 6 that stay their own). Inner #![cfg] attributes
move to the mod lines. Files that change state for the whole process keep
a binary of their own: codecs jxl_tail_heap and raw sr2_heap (dhat global
allocator), gpu shutdown, shutdown_first and memory, ui-egui shutdown.
Docs, comments and the GPU probe name the new paths and targets
(--test it <module>::); the CI report names an it binary's skips after
the crate.

* CI: tests under nextest, doctests apart, one wasm check

xtask ci runs the tests with cargo nextest run --lib --bins --tests when
cargo-nextest is installed, else cargo test with the same targets and a
one-line notice; doctests run after them with cargo test --workspace --doc.
The heif and hardware GPU steps use the same runner. Examples stay out of
the test build (clippy --all-targets still checks them). Concurrent tests
under nextest follow the RUST_TEST_THREADS cap (NEXTEST_TEST_THREADS).
The wasm check is one cargo check --keep-going over the same crates, and
clippy runs with --keep-going.

* CI: tests run under cargo test by default, nextest with LIGHTCRAFT_NEXTEST=1 (per-process scene cache)
2026-10-23 13:34:30 -04:00
francoisgn 22a8343ec7 Merge PR #2701 (review round a4ed555d4) 2026-10-23 18:46:55 +03:00
francoisgnandClaude Opus 5.5 a4ed555d45 #1290: recent libraries are checked on workers, never on the UI thread
Review round (CodeRabbit + an adversarial review, handled together):
- The launch list starts with every row "Checking…" and a worker per path checks it (a
  share whose server is gone, or a sleeping disk, can take seconds or never answer; one
  that hangs doesn't hold the others). After 5 s a row says the drive isn't answering;
  it can still be opened. Once every answer is in, the selection moves to the first
  library that can be opened, unless the person moved it.
- File ▸ Open Recent Library and `app.recentLibraries` no longer look at folders either
  (the menu is rebuilt every frame): they use the same answers, refreshed after 30 s, when
  a library is opened, removed from the list, or fails to open. `app.recentLibraries`
  gives `exists: null` and `checking` until a check answered.
- Reasons are found on the worker and put into words on the UI thread, in the interface
  language. A check whose worker dies ends as "This library couldn't be checked".
- Each check holds an activity row ("Checking recent libraries"; quick ones don't show).
- Docs: control protocol (`checking`, `available`, `exists`), What's New; fr strings.
Tests: slow check never holds the window; late answers keep the person's selection; the
menu takes its answers from a worker (fails with the old is_dir()); reasons in French; one
hung drive doesn't hold the others; a dying check ends; reopening clears a missing answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:46:42 +03:00
francoisgn 81a9e8b298 Merge PR #2701: #2701 3fe02631e LRC-LIB-CATALOG-SWITCH: choose what opens at launch, the last library
# Conflicts:
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/src/panels/settings.rs
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-23 16:39:33 +03:00
Nathaniel Ledford 6889fe223b MENU-BAR: a menu item's cached accelerator follows the native call, and a failed one is retried 2026-10-23 08:23:43 -04:00