pub struct SubagentWatcher {
event_bus: Arc<EventBus>,
sessions: Mutex<HashMap<String, SessionWatch>>,
watched_agents: Mutex<Vec<WatchedAgent>>,
}Fields§
§event_bus: Arc<EventBus>§sessions: Mutex<HashMap<String, SessionWatch>>§watched_agents: Mutex<Vec<WatchedAgent>>Implementations§
Source§impl SubagentWatcher
impl SubagentWatcher
pub fn new(event_bus: Arc<EventBus>) -> Self
Sourcepub fn spawn(event_bus: Arc<EventBus>) -> Arc<Self>
pub fn spawn(event_bus: Arc<EventBus>) -> Arc<Self>
Create a new SubagentWatcher and return it wrapped in Arc.
Sourcepub fn watch_agent(
self: &Arc<Self>,
agent_id: &str,
parent_block_id: &str,
config_dir: PathBuf,
)
pub fn watch_agent( self: &Arc<Self>, agent_id: &str, parent_block_id: &str, config_dir: PathBuf, )
Start watching a Claude Code agent’s session directory for subagent files. Spawns a background tokio task for debounced file event processing.
parent_block_id is the pane/block that owns this Claude instance (from
the reactive register request). It is stamped onto every emitted subagent
event so the frontend can route the ⚡ panel to the originating pane only,
instead of every agent pane rendering every subagent globally.
Note: the watcher dedupes by agent_id, so if the same agent_id is
registered from two blocks, events carry the first registrant’s block id.
That edge case (same instance name in two panes) is rare; the common
leak — a terminal Claude’s subagents showing up in unrelated agent panes —
is fully fixed because the terminal block id never matches an agent pane.
Sourcepub fn unwatch_agent(&self, agent_id: &str)
pub fn unwatch_agent(&self, agent_id: &str)
Stop watching an agent: drop its filesystem watcher, which closes the
debounce channel — so the processing task self-terminates on the next
rx.recv() returning None. Idempotent: a no-op if the agent isn’t
currently watched.
Without this, watched_agents was push-only: every distinct agent that
ever ran leaked one OS watch handle + channel + idle task for the rest of
the process lifetime, even after its pane/agent was deleted. (Session
records in sessions are plain data, not handles, and are left as-is.)
Sourcepub fn list_active(&self) -> Vec<SubagentInfo>
pub fn list_active(&self) -> Vec<SubagentInfo>
List all subagents across all sessions (sync — safe to call from RPC dispatch).
Sourcepub fn get_history(&self, agent_id: &str, limit: usize) -> Vec<SubagentEvent>
pub fn get_history(&self, agent_id: &str, limit: usize) -> Vec<SubagentEvent>
Get recent events for a specific subagent (sync — safe to call from RPC dispatch).
Sourcefn scan_existing_subagents(
&self,
parent_agent: &str,
parent_block_id: &str,
projects_dir: &Path,
)
fn scan_existing_subagents( &self, parent_agent: &str, parent_block_id: &str, projects_dir: &Path, )
Scan for existing subagent JSONL files in a projects directory.
Sourcefn process_jsonl_change(
&self,
parent_agent: &str,
parent_block_id: &str,
jsonl_path: &Path,
)
fn process_jsonl_change( &self, parent_agent: &str, parent_block_id: &str, jsonl_path: &Path, )
Process a changed/new JSONL subagent file. Reads new lines, updates state, and broadcasts events via EventBus.
Auto Trait Implementations§
impl !Freeze for SubagentWatcher
impl RefUnwindSafe for SubagentWatcher
impl Send for SubagentWatcher
impl Sync for SubagentWatcher
impl Unpin for SubagentWatcher
impl UnwindSafe for SubagentWatcher
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more