diff --git a/node-agent.exe~ b/node-agent.exe~ index dcc7be8..227c001 100644 Binary files a/node-agent.exe~ and b/node-agent.exe~ differ diff --git a/services/node-agent/internal/runner/aecrash.go b/services/node-agent/internal/runner/aecrash.go index a7feaed..c0028c1 100644 --- a/services/node-agent/internal/runner/aecrash.go +++ b/services/node-agent/internal/runner/aecrash.go @@ -2,29 +2,38 @@ package runner import ( "os" + "os/exec" "path/filepath" ) -// ClearAECrashState removes After Effects' session crash-recovery marker -// (SCRPriorState.json) from every AE prefs version dir. AE checks this file at -// startup; if it indicates an unclean prior session it shows the blocking -// "Crash Repair Options" dialog — which would hang a headless afterfx/aerender -// launch. Deleting it (vs. wiping all prefs) keeps the node's prefs intact. +// ClearAECrashState removes the markers After Effects uses to decide it crashed, +// so the blocking "Crash Repair Options" (Safe Mode) dialog never appears on a +// headless launch. Two parts: // -// Safe no-op when APPDATA is unset (non-Windows / dev). +// 1. SCRPriorState.json in each AE prefs version dir (session crash-recovery state). +// 2. HKCU\Software\Adobe\After Effects\AppStates — AE writes a per-session GUID +// subkey on startup and removes it on a clean exit; a leftover one (after a +// kill/crash) triggers Safe Mode. reg.exe is a Windows built-in (no external +// dep / cgo), so we shell out to it. +// +// Targeted (vs. wiping all prefs) so the node keeps its AE preferences. Safe no-op +// on non-Windows (APPDATA unset). func ClearAECrashState() { appData := os.Getenv("APPDATA") if appData == "" { - return + return // non-Windows / dev } + + // 1. session crash-recovery files base := filepath.Join(appData, "Adobe", "After Effects") - entries, err := os.ReadDir(base) - if err != nil { - return - } - for _, e := range entries { - if e.IsDir() { - _ = os.Remove(filepath.Join(base, e.Name(), "SCRPriorState.json")) + if entries, err := os.ReadDir(base); err == nil { + for _, e := range entries { + if e.IsDir() { + _ = os.Remove(filepath.Join(base, e.Name(), "SCRPriorState.json")) + } } } + + // 2. registry session/crash state + _ = exec.Command("reg", "delete", `HKCU\Software\Adobe\After Effects\AppStates`, "/f").Run() }