SessionRegistry now tracks a oneshot abort sender per active session:
- abort_senders: HashMap<u64, oneshot::Sender<()>> field added.
- register_abort(session_id): creates the channel, stores the sender,
returns the receiver to the supervise task.
- terminate(): removes the session state AND drops the abort sender,
closing the channel and triggering the receiver in supervise.
runtime::supervise() now accepts abort_rx: oneshot::Receiver<()>:
- After the READY signal is received, the process-wait loop uses
tokio::select! on child.wait() vs abort_rx.
- On abort: logs intent, calls child.kill(), then sets state Stopped.
- On natural exit: logs exit status, sets state Stopped.
dispatch::LaunchApp: calls register_abort immediately after launch,
passes the receiver to the spawned supervise task.
Integration test updated to pass the abort receiver.
runtime.rs — process lifecycle manager:
- supervise(session_id, app_id, registry): spawns the weft-runtime child
process identified by WEFT_RUNTIME_BIN env var. If unset, logs debug
and returns immediately (no-op until runtime binary is available).
- Child process invoked as: <WEFT_RUNTIME_BIN> <app_id> <session_id>
with stdout/stderr piped, stdin closed.
- wait_for_ready(): reads stdout line-by-line; returns Ok(()) on first
line matching 'READY'; returns Err if stdout closes without it.
- 30-second READY_TIMEOUT via tokio::time::timeout; on expiry, kills
the child and transitions session to Stopped.
- On success: sets session state to Running, broadcasts AppReady to all
connected WebSocket clients via registry broadcast channel.
- drain_stderr(): async task that forwards child stderr lines to tracing
at WARN level for observability.
- On process exit: sets session state to Stopped regardless of exit code.
main.rs — wiring:
- SessionRegistry now owns broadcast::Sender<Response>; Default creates
the channel internally. Added set_state(), subscribe(), broadcast()
methods. Removed standalone broadcast_tx from run(); WS handlers
subscribe via registry.lock().await.subscribe().
- dispatch::LaunchApp spawns a tokio task calling runtime::supervise
immediately after creating the session. supervise is a no-op when
WEFT_RUNTIME_BIN is unset, so existing tests are unaffected.
Cargo.toml: added tokio 'process' and 'time' features.