Add a sink func(v any) field so MarteController's event stream can be
routed somewhere other than the browser WebSocket hub. NewMarteController
now sets sink to broadcast through the hub as before; a new
NewHeadlessMarteController(sink) constructor builds an instance with
hub == nil for the upcoming debugclient E2E tool. Direct m.hub.* calls
(SetSourceState/UpdateConfigForSource/PushDataForSource) are now guarded
with nil checks so a headless controller doesn't panic.