New `wave59_handlers.py` (~250 lines) mirroring four Rust-only packs:
- wol: pure-Python magic packet via socket + SO_BROADCAST. No PowerShell
shellout (unlike the Rust pack). Reads MAC from memory_store under
'wol_<alias>' or JARVIS_WOL_TARGET env. Same MAC format tolerance
(colons / dashes / dots / bare) as the Rust normaliser.
- banter: pause/resume state + fire-one. Python edition doesn't run a
background banter thread (the Rust daemon already does), so this is
just the user-facing surface — same voice phrases work.
- conversation: do_conversation_summary calls Groq with last 12 turns
from main.py's `message_log`. set_history_ref() injects the live list
reference at startup so the handler reads up-to-date history without
a circular import. Offline-safe: GROQ_TOKEN missing → speak the last
user message instead. do_conversation_repeat re-speaks the last
assistant turn.
- ddg_answer: urllib + DuckDuckGo Instant Answer JSON. Picks
AbstractText → Answer → Definition → RelatedTopics[0]. Opens
duckduckgo.com search fallback when nothing instant.
extensions.py / main.py / commands.yaml: 7 new dispatch entries +
proxy fns. commands.yaml now at 207 entries.
tests/test_wave59_handlers.py: 11 unit tests for MAC normalisation,
magic packet shape, WOL error paths, banter state machine, DDG trigger
stripping, conversation history handling. Network calls deliberately
NOT exercised here — they belong to integration tests.
Tests: 104 → 115 (+11).