Put JsValue in TaskEvent rather than String; add TaskEventUnapply trait

TaskEventUnapply auto-implements unapply() for events that are intended
to go in a TaskEvent.

The JsValue lets us serialize TaskEvent more cleanly with a nested
JSON tree instead of JSON-inside-a-JSON-string.