diff --git a/ROADMAP.md b/ROADMAP.md index a579491a..00f1d942 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~30 points of "ready for real work" and ~350–620 h away -> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (open-issue count, crash list and localization share re-audited against `upstream/main` 470ea7a3) · **Target:** Adobe After Effects 2026 (26.5.0.89) +> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-14 · **Change:** minor (open-issue count, crash list and localization share re-audited against `upstream/main` 470ea7a3) · **Target:** Adobe After Effects 2026 (26.5.0.89) EffectCraft aims to do what After Effects does, with the same panels, menus and behaviour, written from scratch in Rust. This page is the one-page summary; the evidence is in @@ -157,3 +157,20 @@ Come tell us what matters most to you on [Discord](https://discord.gg/artcraft). | 2026-10-10 | minor | Stage checked against the new core-workflow gate (all six pass; still alpha) | | 2026-10-10 | major | Rewritten to the shared progress-docs standard: stage, two numbers, dimensions, features, languages, upcoming, progress log; milestones moved to docs/roadmap.md | | 2026-10-05 | major | Two numbers (breadth vs real use) and workstreams G1–G9 | + +## Packaging update (2026-10-11) + +Windows setup now uses the suite's shared `craft-installer` UI, preserving existing folder, +shortcut and launch options and app-owned installation policy. Install, uninstall and repair +have explicit completion screens; cancellation and failure have separate endings. Source/profile +checks, WiX UI library compilation for x64/x86/ARM64, PowerShell parsing and package identity +comparisons pass. Native fixture MSI linking/UI tables pass on all three architectures, and +Windows full UI install/repair/uninstall, x86 install/remove, folder upgrades, desktop choices +and launch checks pass with fixtures. Native evidence and real-release acceptance limits +are linked from +[Windows packaging](packaging/windows/README.md). + +Windows Settings removal now opens the shared completion screen. Quiet install/removal +remains unattended; Settings labels preserve compatibility with existing Launchers, and +previous Modify policy is retained. Windows 11 fixture verification covers both installation +scopes and x64/x86 removal, with full MSI validation on x64/x86/ARM64. diff --git a/apps/effectcraft-cli/tests/cli.rs b/apps/effectcraft-cli/tests/cli.rs index 62aefd5d..dd2bf2ab 100644 --- a/apps/effectcraft-cli/tests/cli.rs +++ b/apps/effectcraft-cli/tests/cli.rs @@ -283,7 +283,10 @@ fn render_out_is_relative_to_the_working_directory() { .unwrap(); assert!(o.status.success(), "{out}: {}", String::from_utf8_lossy(&o.stderr)); let v: Value = serde_json::from_slice(&o.stdout).unwrap(); - PathBuf::from(v["rendered"][0]["output"].as_str().unwrap()) + let done = PathBuf::from(v["rendered"][0]["output"].as_str().unwrap()); + assert!(done.is_absolute(), "the CLI reports the absolute output path"); + // Windows canonical paths may add a verbatim prefix; compare the same file. + done.canonicalize().unwrap() }; // A path that already names the project folder is not doubled. let done = render(&root, "proj/x.ecproj", "proj/out/d.gif"); diff --git a/crates/engine/src/commands/relink_moved.rs b/crates/engine/src/commands/relink_moved.rs index 4f70dd6e..af5735c7 100644 --- a/crates/engine/src/commands/relink_moved.rs +++ b/crates/engine/src/commands/relink_moved.rs @@ -306,7 +306,7 @@ mod tests { let r = s.execute("footage.relink", json!({"item": a.0, "path": target})).unwrap(); assert_eq!(r["relinked"], json!([a.0, b.0, m.0]), "{r}"); assert_eq!(r["stillMissing"], 1); - assert_eq!(path_of(&s, m), new.join("audio/m.wav").to_string_lossy()); + assert_eq!(std::path::Path::new(&path_of(&s, m)), new.join("audio/m.wav")); assert_eq!(path_of(&s, other), "/elsewhere/c.mov"); // One undo step brings every path back. s.execute("edit.undo", json!({})).unwrap(); diff --git a/crates/engine/src/footage_check.rs b/crates/engine/src/footage_check.rs index de14b06c..20a39d19 100644 --- a/crates/engine/src/footage_check.rs +++ b/crates/engine/src/footage_check.rs @@ -269,7 +269,7 @@ mod tests { _ => None, }) .collect(); - assert!(paths.contains(&d.join("Job/shots/a.png").to_string_lossy().to_string()), "{paths:?}"); + assert!(paths.iter().any(|path| std::path::Path::new(path) == d.join("Job/shots/a.png")), "{paths:?}"); assert!(!o.is_dirty(), "finding the files is not an edit"); let _ = std::fs::remove_dir_all(d); } diff --git a/crates/host/tests/relink.rs b/crates/host/tests/relink.rs index 5bb31b4e..54abd693 100644 --- a/crates/host/tests/relink.rs +++ b/crates/host/tests/relink.rs @@ -48,7 +48,7 @@ fn replacing_a_missing_file_relinks_the_others_that_moved_with_it() { let r = s.execute("file.replaceFootage", json!({"item": a, "path": new.join("stills/a.png").to_string_lossy()})).unwrap(); assert_eq!(r["relinked"].as_array().map(Vec::len), Some(1), "{r}"); let after = footage_paths(&s); - assert!(after.iter().all(|(_, p, missing)| p.starts_with(&*new.to_string_lossy()) && !missing), "{after:?}"); + assert!(after.iter().all(|(_, p, missing)| Path::new(p).starts_with(&new) && !missing), "{after:?}"); // One undo step puts both back. s.execute("edit.undo", json!({})).unwrap(); assert_eq!(footage_paths(&s).iter().map(|(_, p, _)| p.clone()).collect::>(), before.iter().map(|(_, p, _)| p.clone()).collect::>()); diff --git a/docs/roadmap.md b/docs/roadmap.md index 73fdfd23..4dd9fac0 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,6 +1,6 @@ # Roadmap detail -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (new file: milestones moved from ROADMAP.md, current focus and next steps with Opus 5.5 estimates) · **Target:** Adobe After Effects 2026 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared Windows installer UI; existing folder/shortcut/launch options retained; install and uninstall completion) · **Target:** Adobe After Effects 2026 Forward-looking detail behind the [ROADMAP](../ROADMAP.md). The work list itself, one gap at a time, is [gaps.md](gaps.md); the numbers are in [target-app-parity.md](target-app-parity.md). @@ -85,3 +85,12 @@ To beta (≈ 75% ready and `.aep` opening): **≈ 350–620 h**. To full parity: |---|---|---| | 2026-10-10 | minor | Alpha gate: six core workflows checked; all pass, stage stays alpha | | 2026-10-10 | major | New file: milestones from ROADMAP.md, current focus, next steps with estimates | + +## Packaging update (2026-10-11) + +Windows setup now uses the suite's shared `craft-installer` UI, preserving existing folder, +shortcut and launch options and app-owned installation policy. Install, uninstall and repair +have explicit completion screens; cancellation and failure have separate endings. Source/profile +checks, WiX UI library compilation for x64/x86/ARM64, PowerShell parsing and package identity +comparisons pass. Full MSI linking and interactive Windows acceptance remain pending; see +[Windows packaging](../packaging/windows/README.md). diff --git a/packaging/windows/README.md b/packaging/windows/README.md new file mode 100644 index 00000000..b6e447e8 --- /dev/null +++ b/packaging/windows/README.md @@ -0,0 +1,34 @@ +# Windows installer UI + +`installer-ui.wxs` is generated from the shared `craft-installer` crate in +[craft-libs](https://github.com/storytold/craft-libs/tree/main/crates/installer). +`package.ps1` compiles it with this app's package source. The common UI provides progress, +repair/remove, and explicit install/uninstall/repair success, cancellation and failure screens. + +Regenerate or check from a sibling craft-libs checkout: + +```sh +cargo run --locked -p craft-installer -- --write --app effectcraft ../effectcraft/packaging/windows/installer-ui.wxs +cargo run --locked -p craft-installer -- --check --app effectcraft ../effectcraft/packaging/windows/installer-ui.wxs +``` + +Edit the shared templates/profile and regenerate; avoid editing this snapshot by hand. The +profile retains this app's existing folder, shortcut and launch options; defaults, persistence, +components, associations and signing stay in the app-owned source. Release builds require no +sibling checkout, published crate or additional runtime dependency. `/qn`, `/qb` and `/passive` +remain unattended and do not launch the app. + +Source/profile checks and native fixture MSI linking/UI table checks passed for x64, x86 and +ARM64. All 14 profiles passed full UI install, missing-file repair and cached uninstall, and +x86 silent install/removal. Folder upgrades, desktop choices and all six launch profiles also +passed their Windows fixture checks. See the +[Windows verification record](../../../craft-libs/docs/windows-installer-verification.md) for +interactive results, scope validation and remaining acceptance checks with real release payloads. +The shared crate includes reusable linking, full UI, option/upgrade/launch and x86 test runners. +Windows Settings now uses a separate MSI-owned entry whose uninstall command selects full UI, +including the completion screen. Its quiet command and direct `/qn`, `/qb`, `/passive` commands +remain unattended. The main feature references `CraftInstallerSettings`; the shared snapshot +owns this registration and hides the native MSI entry while retaining MSI repair/upgrade APIs. + +The Settings display name appends `(Craft Apps)` for compatibility with older Launchers; the +hidden native MSI name stays unchanged. Existing ARP Modify policy is retained explicitly. diff --git a/packaging/windows/effectcraft.wxs b/packaging/windows/effectcraft.wxs index 00b0c5d6..d3737156 100644 --- a/packaging/windows/effectcraft.wxs +++ b/packaging/windows/effectcraft.wxs @@ -23,7 +23,6 @@ DowngradeErrorMessage="A newer version of EffectCraft is already installed." /> - @@ -54,11 +53,12 @@ DESKTOPSHORTCUT=0 silently); an upgrade keeps what the installed copy chose, and adds none to an install from before this option. --> + + Condition="WIX_UPGRADE_DETECTED AND NOT CRAFTDESKTOPSHORTCUTSELECTED" /> @@ -68,7 +68,10 @@ + + + diff --git a/packaging/windows/installer-ui.wxs b/packaging/windows/installer-ui.wxs index 16ab58d7..d6c47f9c 100644 --- a/packaging/windows/installer-ui.wxs +++ b/packaging/windows/installer-ui.wxs @@ -1,49 +1,89 @@ - + + - - - - - - + + + + + - - - - - - - - + + + + + + + + + + - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + @@ -59,7 +99,8 @@ - + + @@ -67,136 +108,178 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/windows/test-msi.ps1 b/packaging/windows/test-msi.ps1 index 5868c77b..395b0607 100644 --- a/packaging/windows/test-msi.ps1 +++ b/packaging/windows/test-msi.ps1 @@ -107,7 +107,7 @@ Assert-InstalledIn $Custom Assert-DesktopShortcut $true # Read single values: Get-ItemProperty throws on some machines' malformed Uninstall entries. $arp = @(Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall' | - ForEach-Object { if ($_.GetValue('DisplayName') -eq 'EffectCraft') { $_.GetValue('DisplayVersion') } }) + ForEach-Object { if ($_.GetValue('DisplayName') -eq 'EffectCraft (Craft Apps)' -and $_.GetValue('SystemComponent') -ne 1) { $_.GetValue('DisplayVersion') } }) if ($arp.Count -ne 1 -or $arp[0] -ne '0.0.3') { throw "expected one EffectCraft 0.0.3 in Apps, found: $($arp -join ', ')" } # Repair the way the wizard's Repair button does: damage the CLI in place (a later write time, as a