Four refinements to the sticky Todos panel on top of the live SessionObserverRegistry linkage:
- Cube animates whenever any visible open todo is "live" (in_progress, or a still-pending todo with a matching in-flight subagent). The previous subagent-only gate left lone in_progress rows on the static '⟳' fallback; ticking on an orphan in_progress row is the correct "still open" signal.
- 'normalizeForTodoMatch' now collapses any non-alphanumeric run to one space, so subagent descriptions with '#', '.', ':' etc. match todo content that omits the punctuation. Fixes the case where 3 subagents were spawned but only 2 of 3 matching todos lit up because the matcher's normalizer collapsed whitespace but left '#' intact.
- New '#reconcileTodosWithSubagents' runs on every observer-registry change and auto-checkmarks any pending/in_progress todo whose content matches a 'status === "completed"' subagent description. Failed/aborted subagents intentionally don't auto-flip - those stay open for the user (or next agent turn) to decide.
- All-done close animation: when every visible task is closed, fold the panel away over ~1.4s. A 900ms celebratory frame holds the bright bold "Todos ✓" header so the user can read the final checkmarks, then a fade through 'muted' / 'dim' with rows progressively dropped from the bottom. '#todoClosingState' state machine plays the animation exactly once per open->all-closed transition and aborts cleanly if a new open task arrives mid-animation.
Verification:
bun test test/tools/todo-write.test.ts → 24 pass / 0 fail (one new case for # punctuation tolerance)
bun run check → biome + tsgo clean